VMware vSphere Integrated Containers provider (#206)
* Add Virtual Kubelet provider for VIC Initial virtual kubelet provider for VMware VIC. This provider currently handles creating and starting of a pod VM via the VIC portlayer and persona server. Image store handling via the VIC persona server. This provider currently requires the feature/wolfpack branch of VIC. * Added pod stop and delete. Also added node capacity. Added the ability to stop and delete pod VMs via VIC. Also retrieve node capacity information from the VCH. * Cleanup and readme file Some file clean up and added a Readme.md markdown file for the VIC provider. * Cleaned up errors, added function comments, moved operation code 1. Cleaned up error handling. Set standard for creating errors. 2. Added method prototype comments for all interface functions. 3. Moved PodCreator, PodStarter, PodStopper, and PodDeleter to a new folder. * Add mocking code and unit tests for podcache, podcreator, and podstarter Used the unit test framework used in VIC to handle assertions in the provider's unit test. Mocking code generated using OSS project mockery, which is compatible with the testify assertion framework. * Vendored packages for the VIC provider Requires feature/wolfpack branch of VIC and a few specific commit sha of projects used within VIC. * Implementation of POD Stopper and Deleter unit tests (#4) * Updated files for initial PR
This commit is contained in:
167
providers/vic/proxy/image_store.go
Normal file
167
providers/vic/proxy/image_store.go
Normal file
@@ -0,0 +1,167 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/vmware/vic/lib/apiservers/engine/backends/cache"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/metadata"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
)
|
||||
|
||||
//TODO: This image cache needs to hook into the VIC persona to receive an event when users pulled images
|
||||
// via docker.
|
||||
|
||||
type ImageStore interface {
|
||||
Get(op trace.Operation, idOrRef, tag string, actuate bool) (*metadata.ImageConfig, error)
|
||||
GetImages(op trace.Operation) []*metadata.ImageConfig
|
||||
PullImage(op trace.Operation, image, tag, username, password string) error
|
||||
}
|
||||
|
||||
type VicImageStore struct {
|
||||
client *client.PortLayer
|
||||
personaAddr string
|
||||
portlayerAddr string
|
||||
}
|
||||
|
||||
type ImageStoreError string
|
||||
|
||||
func (e ImageStoreError) Error() string { return string(e) }
|
||||
|
||||
const (
|
||||
ImageStorePortlayerClientError = ImageStoreError("ImageStore cannot be created without a valid portlayer client")
|
||||
ImageStorePersonaAddrError = ImageStoreError("ImageStore cannot be created without a valid VIC persona addr")
|
||||
ImageStorePortlayerAddrError = ImageStoreError("ImageStore cannot be created without a valid VIC portlayer addr")
|
||||
ImageStoreContainerIDError = ImageStoreError("ImageStore called with empty container ID")
|
||||
ImageStoreEmptyUserNameError = ImageStoreError("ImageStore called with empty username")
|
||||
ImageStoreEmptyPasswordError = ImageStoreError("ImageStore called with empty password")
|
||||
)
|
||||
|
||||
func NewImageStore(plClient *client.PortLayer, personaAddr, portlayerAddr string) (ImageStore, error) {
|
||||
if plClient == nil {
|
||||
return nil, ImageStorePortlayerClientError
|
||||
}
|
||||
if personaAddr == "" {
|
||||
return nil, ImageStorePersonaAddrError
|
||||
}
|
||||
if portlayerAddr == "" {
|
||||
return nil, ImageStorePortlayerAddrError
|
||||
}
|
||||
|
||||
err := cache.InitializeImageCache(plClient)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
vs := &VicImageStore{
|
||||
client: plClient,
|
||||
personaAddr: personaAddr,
|
||||
portlayerAddr: portlayerAddr,
|
||||
}
|
||||
|
||||
return vs, nil
|
||||
}
|
||||
|
||||
// Get retrieves the VIC ImageConfig data structure. If the config is not cached,
|
||||
// VicImageStore can request imagec to pull the image if actuate is set to true.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// idOrRef docker image id or reference
|
||||
// tag docker image tag
|
||||
// realize determines whether the image is pulled if not in the cache
|
||||
// returns:
|
||||
// error
|
||||
func (v *VicImageStore) Get(op trace.Operation, idOrRef, tag string, realize bool) (*metadata.ImageConfig, error) {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("Get - %s:%s", idOrRef, tag), op))
|
||||
|
||||
if idOrRef == "" {
|
||||
op.Errorf(ImageStoreContainerIDError.Error())
|
||||
return nil, ImageStoreContainerIDError
|
||||
}
|
||||
|
||||
c, err := cache.ImageCache().Get(idOrRef)
|
||||
if err != nil && realize {
|
||||
err = v.PullImage(op, idOrRef, tag, "", "")
|
||||
if err == nil {
|
||||
//TODO: Find a better way to get update imageconfig instead of this hammer
|
||||
err := cache.InitializeImageCache(v.client)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c, err = cache.ImageCache().Get(idOrRef)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c, nil
|
||||
}
|
||||
|
||||
// Get retrieves all the VIC ImageConfig data structure.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// returns:
|
||||
// array of ImageConfig
|
||||
func (v *VicImageStore) GetImages(op trace.Operation) []*metadata.ImageConfig {
|
||||
defer trace.End(trace.Begin("", op))
|
||||
|
||||
return cache.ImageCache().GetImages()
|
||||
}
|
||||
|
||||
// PullImage makes a request to the VIC persona server (imageC component) to retrieve a container image.
|
||||
//
|
||||
// arguments:
|
||||
// op operation trace logger
|
||||
// idOrRef docker image id or reference
|
||||
// tag docker image tag
|
||||
// username user name for the registry server
|
||||
// password password for the registry server
|
||||
// returns:
|
||||
// array of ImageConfig
|
||||
func (v *VicImageStore) PullImage(op trace.Operation, image, tag, username, password string) error {
|
||||
defer trace.End(trace.Begin(fmt.Sprintf("Get - %s:%s", image, tag), op))
|
||||
|
||||
if image == "" {
|
||||
op.Errorf(ImageStoreContainerIDError.Error())
|
||||
return ImageStoreContainerIDError
|
||||
}
|
||||
|
||||
pullClient := &http.Client{Timeout: 60 * time.Second}
|
||||
var personaServer string
|
||||
if tag == "" {
|
||||
personaServer = fmt.Sprintf("http://%s/v1.35/images/create?fromImage=%s", v.personaAddr, image)
|
||||
} else {
|
||||
personaServer = fmt.Sprintf("http://%s/v1.35/images/create?fromImage=%s&tag=%s", v.personaAddr, image, tag)
|
||||
}
|
||||
op.Infof("POST %s", personaServer)
|
||||
reader := bytes.NewBuffer([]byte(""))
|
||||
resp, err := pullClient.Post(personaServer, "application/json", reader)
|
||||
if err != nil {
|
||||
op.Errorf("Error from docker pull: error = %s", err.Error())
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != 200 {
|
||||
msg := fmt.Sprintf("Error from docker pull: status = %d", resp.StatusCode)
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
|
||||
body, err := ioutil.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
msg := fmt.Sprintf("Error reading docker pull response: error = %s", err.Error())
|
||||
op.Errorf(msg)
|
||||
return fmt.Errorf(msg)
|
||||
}
|
||||
op.Infof("Response from docker pull: body = %s", string(body))
|
||||
|
||||
return nil
|
||||
}
|
||||
589
providers/vic/proxy/isolation_proxy.go
Normal file
589
providers/vic/proxy/isolation_proxy.go
Normal file
@@ -0,0 +1,589 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
vicerrors "github.com/vmware/vic/lib/apiservers/engine/errors"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/containers"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/interaction"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/logging"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/scopes"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/storage"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/client/tasks"
|
||||
"github.com/vmware/vic/lib/apiservers/portlayer/models"
|
||||
"github.com/vmware/vic/pkg/trace"
|
||||
"github.com/vmware/vic/pkg/vsphere/sys"
|
||||
|
||||
"github.com/docker/docker/api/types/strslice"
|
||||
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/cache"
|
||||
"github.com/virtual-kubelet/virtual-kubelet/providers/vic/constants"
|
||||
)
|
||||
|
||||
type IsolationProxy interface {
|
||||
CreateHandle(op trace.Operation) (string, string, error)
|
||||
AddImageToHandle(op trace.Operation, handle, deltaID, layerID, imageID, imageName string) (string, error)
|
||||
CreateHandleTask(op trace.Operation, handle, id, layerID string, config IsolationContainerConfig) (string, error)
|
||||
AddHandleToScope(op trace.Operation, handle string, config IsolationContainerConfig) (string, error)
|
||||
AddInteractionToHandle(op trace.Operation, handle string) (string, error)
|
||||
AddLoggingToHandle(op trace.Operation, handle string) (string, error)
|
||||
CommitHandle(op trace.Operation, handle, containerID string, waitTime int32) error
|
||||
SetState(op trace.Operation, handle, name, state string) (string, error)
|
||||
|
||||
BindScope(op trace.Operation, handle string, name string) (string, interface{}, error)
|
||||
UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error)
|
||||
|
||||
Handle(op trace.Operation, id, name string) (string, error)
|
||||
State(op trace.Operation, id, name string) (string, error)
|
||||
Remove(op trace.Operation, id string, force bool) error
|
||||
}
|
||||
|
||||
type VicIsolationProxy struct {
|
||||
client *client.PortLayer
|
||||
imageStore ImageStore
|
||||
podCache cache.PodCache
|
||||
portlayerAddr string
|
||||
hostUUID string
|
||||
}
|
||||
|
||||
type PortBinding struct {
|
||||
HostIP string
|
||||
HostPort string
|
||||
}
|
||||
|
||||
type IsolationContainerConfig struct {
|
||||
ID string
|
||||
ImageID string
|
||||
LayerID string
|
||||
ImageName string
|
||||
Name string
|
||||
Namespace string
|
||||
|
||||
Cmd []string
|
||||
Path string
|
||||
Entrypoint []string
|
||||
//Args []string
|
||||
Env []string
|
||||
WorkingDir string
|
||||
User string
|
||||
StopSignal string
|
||||
|
||||
Attach bool
|
||||
StdinOnce bool
|
||||
OpenStdin bool
|
||||
Tty bool
|
||||
|
||||
CPUCount int64
|
||||
Memory int64
|
||||
|
||||
PortMap map[string]PortBinding
|
||||
}
|
||||
|
||||
func NewIsolationProxy(plClient *client.PortLayer, portlayerAddr string, hostUUID string, imageStore ImageStore, podCache cache.PodCache) IsolationProxy {
|
||||
if plClient == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
return &VicIsolationProxy{
|
||||
client: plClient,
|
||||
imageStore: imageStore,
|
||||
podCache: podCache,
|
||||
portlayerAddr: portlayerAddr,
|
||||
hostUUID: hostUUID,
|
||||
}
|
||||
}
|
||||
|
||||
// CreateHandle creates a "manifest" that will be used by Commit() to create the actual
|
||||
// isolation vm.
|
||||
//
|
||||
// returns:
|
||||
// (container/pod id, handle, error)
|
||||
func (v *VicIsolationProxy) CreateHandle(op trace.Operation) (string, string, error) {
|
||||
defer trace.End(trace.Begin("CreateHandle", op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
// Call the Exec port layer to create the container
|
||||
var err error
|
||||
var hostUUID string
|
||||
if v.hostUUID != "" {
|
||||
hostUUID = v.hostUUID
|
||||
} else {
|
||||
hostUUID, err = sys.UUID()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", "", vicerrors.InternalServerError("IsolationProxy.CreateContainerHandle got unexpected error getting VCH UUID")
|
||||
}
|
||||
|
||||
plCreateParams := initIsolationConfig(op, "", constants.DummyRepoName, constants.DummyImage, constants.DummyLayerID, hostUUID)
|
||||
createResults, err := v.client.Containers.Create(plCreateParams)
|
||||
if err != nil {
|
||||
if _, ok := err.(*containers.CreateNotFound); ok {
|
||||
cerr := fmt.Errorf("No such image: %s", constants.DummyImage)
|
||||
op.Errorf("%s (%s)", cerr, err)
|
||||
return "", "", vicerrors.NotFoundError(cerr.Error())
|
||||
}
|
||||
|
||||
// If we get here, most likely something went wrong with the port layer API server
|
||||
return "", "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
id := createResults.Payload.ID
|
||||
h := createResults.Payload.Handle
|
||||
|
||||
return id, h, nil
|
||||
}
|
||||
|
||||
// Handle retrieves a handle to a VIC container. Handles should be treated as opaque strings.
|
||||
//
|
||||
// returns:
|
||||
// (handle string, error)
|
||||
func (v *VicIsolationProxy) Handle(op trace.Operation, id, name string) (string, error) {
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
resp, err := v.client.Containers.Get(containers.NewGetParamsWithContext(op).WithID(id))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.GetNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.GetDefault:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) AddImageToHandle(op trace.Operation, handle, deltaID, layerID, imageID, imageName string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.AddImageToContainer failed to get the portlayer client")
|
||||
}
|
||||
|
||||
var err error
|
||||
var hostUUID string
|
||||
if v.hostUUID != "" {
|
||||
hostUUID = v.hostUUID
|
||||
} else {
|
||||
hostUUID, err = sys.UUID()
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.AddImageToContainer got unexpected error getting VCH UUID")
|
||||
}
|
||||
|
||||
response, err := v.client.Storage.ImageJoin(storage.NewImageJoinParamsWithContext(op).WithStoreName(hostUUID).WithID(layerID).
|
||||
WithConfig(&models.ImageJoinConfig{
|
||||
Handle: handle,
|
||||
DeltaID: deltaID,
|
||||
ImageID: imageID,
|
||||
RepoName: imageName,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) CreateHandleTask(op trace.Operation, handle, id, layerID string, config IsolationContainerConfig) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.InternalServerError("IsolationProxy.CreateContainerTask failed to create a portlayer client")
|
||||
}
|
||||
|
||||
op.Debugf("CreateHandleTask - %#v", config)
|
||||
|
||||
plTaskParams := IsolationContainerConfigToTask(op, id, layerID, config)
|
||||
plTaskParams.Config.Handle = handle
|
||||
|
||||
op.Debugf("*** CreateContainerTask - params = %#v", *plTaskParams.Config)
|
||||
responseJoin, err := v.client.Tasks.Join(plTaskParams)
|
||||
if err != nil {
|
||||
op.Errorf("Unable to join primary task to container: %+v", err)
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
handle, ok := responseJoin.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed on handle from task join: %#+v", handle))
|
||||
}
|
||||
|
||||
plBindParams := tasks.NewBindParamsWithContext(op).WithConfig(&models.TaskBindConfig{Handle: handle, ID: id})
|
||||
responseBind, err := v.client.Tasks.Bind(plBindParams)
|
||||
if err != nil {
|
||||
op.Errorf("Unable to bind primary task to container: %+v", err)
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
handle, ok = responseBind.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed on handle from task bind %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddHandleToScope adds a container, referenced by handle, to a scope.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddHandleToScope(op trace.Operation, handle string, config IsolationContainerConfig) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
// configure network
|
||||
netConf := networkConfigFromIsolationConfig(config)
|
||||
if netConf != nil {
|
||||
addContRes, err := v.client.Scopes.AddContainer(scopes.NewAddContainerParamsWithContext(op).
|
||||
WithScope(netConf.NetworkName).
|
||||
WithConfig(&models.ScopesAddContainerConfig{
|
||||
Handle: handle,
|
||||
NetworkConfig: netConf,
|
||||
}))
|
||||
|
||||
if err != nil {
|
||||
op.Errorf("IsolationProxy.AddContainerToScope: Scopes error: %s", err.Error())
|
||||
return handle, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
|
||||
defer func() {
|
||||
if err == nil {
|
||||
return
|
||||
}
|
||||
// roll back the AddContainer call
|
||||
if _, err2 := v.client.Scopes.RemoveContainer(scopes.NewRemoveContainerParamsWithContext(op).WithHandle(handle).WithScope(netConf.NetworkName)); err2 != nil {
|
||||
op.Warnf("could not roll back container add: %s", err2)
|
||||
}
|
||||
}()
|
||||
|
||||
handle = addContRes.Payload
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddLoggingToHandle adds logging capability to the isolation vm, referenced by handle.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddLoggingToHandle(op trace.Operation, handle string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
response, err := v.client.Logging.LoggingJoin(logging.NewLoggingJoinParamsWithContext(op).
|
||||
WithConfig(&models.LoggingJoinConfig{
|
||||
Handle: handle,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
// AddInteractionToContainer adds interaction capabilities to a container, referenced by handle.
|
||||
// If an error is return, the returned handle should not be used.
|
||||
//
|
||||
// returns:
|
||||
// modified handle
|
||||
func (v *VicIsolationProxy) AddInteractionToHandle(op trace.Operation, handle string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
response, err := v.client.Interaction.InteractionJoin(interaction.NewInteractionJoinParamsWithContext(op).
|
||||
WithConfig(&models.InteractionJoinConfig{
|
||||
Handle: handle,
|
||||
}))
|
||||
if err != nil {
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
handle, ok := response.Payload.Handle.(string)
|
||||
if !ok {
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle))
|
||||
}
|
||||
|
||||
return handle, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) CommitHandle(op trace.Operation, handle, containerID string, waitTime int32) error {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
var commitParams *containers.CommitParams
|
||||
if waitTime > 0 {
|
||||
commitParams = containers.NewCommitParamsWithContext(op).WithHandle(handle).WithWaitTime(&waitTime)
|
||||
} else {
|
||||
commitParams = containers.NewCommitParamsWithContext(op).WithHandle(handle)
|
||||
}
|
||||
|
||||
_, err := v.client.Containers.Commit(commitParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.CommitNotFound:
|
||||
return vicerrors.NotFoundError(containerID)
|
||||
case *containers.CommitConflict:
|
||||
return vicerrors.ConflictError(err.Error())
|
||||
case *containers.CommitDefault:
|
||||
return vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
//TODO: I don't think this function should be in here.
|
||||
// BindNetwork binds the handle to the scope and returns endpoints. Caller of the function does not need
|
||||
// to interpret the return value. In the event the caller want to unbind,
|
||||
func (v *VicIsolationProxy) BindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", nil, vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
bindParams := scopes.NewBindContainerParamsWithContext(op).WithHandle(handle)
|
||||
bindRes, err := v.client.Scopes.BindContainer(bindParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *scopes.BindContainerNotFound:
|
||||
return "", nil, vicerrors.NotFoundError(name)
|
||||
case *scopes.BindContainerInternalServerError:
|
||||
return "", nil, vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", nil, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return bindRes.Payload.Handle, bindRes.Payload.Endpoints, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", nil, vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
unbindParams := scopes.NewUnbindContainerParamsWithContext(op).WithHandle(handle)
|
||||
resp, err := v.client.Scopes.UnbindContainer(unbindParams)
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *scopes.UnbindContainerNotFound:
|
||||
return "", nil, vicerrors.NotFoundError(name)
|
||||
case *scopes.UnbindContainerInternalServerError:
|
||||
return "", nil, vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", nil, vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Payload.Handle, resp.Payload.Endpoints, nil
|
||||
}
|
||||
|
||||
// SetState adds the desire state of the isolation unit once the handle is commited.
|
||||
//
|
||||
// returns handle string and error
|
||||
func (v *VicIsolationProxy) SetState(op trace.Operation, handle, name, state string) (string, error) {
|
||||
defer trace.End(trace.Begin(handle, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
resp, err := v.client.Containers.StateChange(containers.NewStateChangeParamsWithContext(op).WithHandle(handle).WithState(state))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.StateChangeNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.StateChangeDefault:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
return resp.Payload, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) State(op trace.Operation, id, name string) (string, error) {
|
||||
defer trace.End(trace.Begin(id, op))
|
||||
|
||||
if v.client == nil {
|
||||
return "", vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
results, err := v.client.Containers.GetContainerInfo(containers.NewGetContainerInfoParamsWithContext(op).WithID(id))
|
||||
if err != nil {
|
||||
switch err := err.(type) {
|
||||
case *containers.GetContainerInfoNotFound:
|
||||
return "", vicerrors.NotFoundError(name)
|
||||
case *containers.GetContainerInfoInternalServerError:
|
||||
return "", vicerrors.InternalServerError(err.Payload.Message)
|
||||
default:
|
||||
return "", vicerrors.InternalServerError(fmt.Sprintf("Unknown error from the interaction port layer: %s", err))
|
||||
}
|
||||
}
|
||||
|
||||
state := results.Payload.ContainerConfig.State
|
||||
return state, nil
|
||||
}
|
||||
|
||||
func (v *VicIsolationProxy) Remove(op trace.Operation, id string, force bool) error {
|
||||
defer trace.End(trace.Begin(id, op))
|
||||
|
||||
if v.client == nil {
|
||||
return vicerrors.NillPortlayerClientError("IsolationProxy")
|
||||
}
|
||||
|
||||
pForce := force
|
||||
params := containers.NewContainerRemoveParamsWithContext(op).
|
||||
WithID(id).
|
||||
WithForce(&pForce).
|
||||
WithTimeout(120 * time.Second)
|
||||
|
||||
removeOK, err := v.client.Containers.ContainerRemove(params)
|
||||
op.Debugf("ContainerRemove returned %# +v", removeOK)
|
||||
return err
|
||||
}
|
||||
|
||||
//------------------------------------
|
||||
// Utility Functions
|
||||
//------------------------------------
|
||||
|
||||
// Convert isolation container config to portlayer task param
|
||||
func IsolationContainerConfigToTask(op trace.Operation, id, layerID string, ic IsolationContainerConfig) *tasks.JoinParams {
|
||||
config := &models.TaskJoinConfig{}
|
||||
|
||||
var path string
|
||||
var args []string
|
||||
|
||||
// we explicitly specify the ID for the primary task so that it's the same as the containerID
|
||||
config.ID = id
|
||||
|
||||
// Set the filesystem namespace this task expects to run in
|
||||
config.Namespace = layerID
|
||||
|
||||
// Expand cmd into entrypoint and args
|
||||
cmd := strslice.StrSlice(ic.Cmd)
|
||||
if len(ic.Entrypoint) != 0 {
|
||||
path, args = ic.Entrypoint[0], append(ic.Entrypoint[1:], cmd...)
|
||||
} else {
|
||||
path, args = cmd[0], cmd[1:]
|
||||
}
|
||||
|
||||
// copy the path
|
||||
config.Path = path
|
||||
|
||||
// copy the args
|
||||
config.Args = make([]string, len(args))
|
||||
copy(config.Args, args)
|
||||
|
||||
// copy the env array
|
||||
config.Env = make([]string, len(ic.Env))
|
||||
copy(config.Env, ic.Env)
|
||||
|
||||
// working dir
|
||||
config.WorkingDir = ic.WorkingDir
|
||||
|
||||
// user
|
||||
config.User = ic.User
|
||||
|
||||
// attach. Always set to true otherwise we cannot attach later.
|
||||
// this tells portlayer container is attachable.
|
||||
config.Attach = true
|
||||
|
||||
// openstdin
|
||||
config.OpenStdin = ic.OpenStdin
|
||||
|
||||
// tty
|
||||
config.Tty = ic.Tty
|
||||
|
||||
// container stop signal
|
||||
config.StopSignal = ic.StopSignal
|
||||
|
||||
op.Debugf("dockerContainerCreateParamsToTask = %+v", config)
|
||||
|
||||
return tasks.NewJoinParamsWithContext(op).WithConfig(config)
|
||||
}
|
||||
|
||||
// initIsolationConfig returns a default config used to create the isolation unit handle
|
||||
func initIsolationConfig(op trace.Operation, name, repoName, imageID, layerID, imageStore string) *containers.CreateParams {
|
||||
config := &models.ContainerCreateConfig{}
|
||||
|
||||
config.NumCpus = constants.DefaultCPUs
|
||||
config.MemoryMB = constants.DefaultMemory
|
||||
|
||||
// Layer/vmdk to use
|
||||
config.Layer = layerID
|
||||
|
||||
// Image ID
|
||||
config.Image = imageID
|
||||
|
||||
// Repo Requested
|
||||
config.RepoName = repoName
|
||||
|
||||
//copy friendly name
|
||||
config.Name = name
|
||||
|
||||
// image store
|
||||
config.ImageStore = &models.ImageStore{Name: imageStore}
|
||||
|
||||
// network
|
||||
config.NetworkDisabled = true
|
||||
|
||||
// hostname
|
||||
config.Hostname = constants.HostName
|
||||
//// domainname - https://github.com/moby/moby/issues/27067
|
||||
//config.Domainname = cc.Config.Domainname
|
||||
|
||||
op.Debugf("dockerContainerCreateParamsToPortlayer = %+v", config)
|
||||
|
||||
return containers.NewCreateParamsWithContext(op).WithCreateConfig(config)
|
||||
}
|
||||
|
||||
func networkConfigFromIsolationConfig(config IsolationContainerConfig) *models.NetworkConfig {
|
||||
nc := &models.NetworkConfig{
|
||||
NetworkName: "default",
|
||||
}
|
||||
|
||||
for key, val := range config.PortMap {
|
||||
nc.Ports = append(nc.Ports, fmt.Sprintf("%s:%s", val.HostPort, key))
|
||||
}
|
||||
|
||||
return nc
|
||||
}
|
||||
65
providers/vic/proxy/mocks/ImageStore.go
Normal file
65
providers/vic/proxy/mocks/ImageStore.go
Normal file
@@ -0,0 +1,65 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
package mocks
|
||||
|
||||
import metadata "github.com/vmware/vic/lib/metadata"
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
|
||||
import trace "github.com/vmware/vic/pkg/trace"
|
||||
|
||||
// ImageStore is an autogenerated mock type for the ImageStore type
|
||||
type ImageStore struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// Get provides a mock function with given fields: op, idOrRef, tag, actuate
|
||||
func (_m *ImageStore) Get(op trace.Operation, idOrRef string, tag string, actuate bool) (*metadata.ImageConfig, error) {
|
||||
ret := _m.Called(op, idOrRef, tag, actuate)
|
||||
|
||||
var r0 *metadata.ImageConfig
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, bool) *metadata.ImageConfig); ok {
|
||||
r0 = rf(op, idOrRef, tag, actuate)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).(*metadata.ImageConfig)
|
||||
}
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, bool) error); ok {
|
||||
r1 = rf(op, idOrRef, tag, actuate)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// GetImages provides a mock function with given fields: op
|
||||
func (_m *ImageStore) GetImages(op trace.Operation) []*metadata.ImageConfig {
|
||||
ret := _m.Called(op)
|
||||
|
||||
var r0 []*metadata.ImageConfig
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation) []*metadata.ImageConfig); ok {
|
||||
r0 = rf(op)
|
||||
} else {
|
||||
if ret.Get(0) != nil {
|
||||
r0 = ret.Get(0).([]*metadata.ImageConfig)
|
||||
}
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// PullImage provides a mock function with given fields: op, image, tag, username, password
|
||||
func (_m *ImageStore) PullImage(op trace.Operation, image string, tag string, username string, password string) error {
|
||||
ret := _m.Called(op, image, tag, username, password)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, string) error); ok {
|
||||
r0 = rf(op, image, tag, username, password)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
295
providers/vic/proxy/mocks/IsolationProxy.go
Normal file
295
providers/vic/proxy/mocks/IsolationProxy.go
Normal file
@@ -0,0 +1,295 @@
|
||||
// Code generated by mockery v1.0.0. DO NOT EDIT.
|
||||
package mocks
|
||||
|
||||
import mock "github.com/stretchr/testify/mock"
|
||||
import proxy "github.com/virtual-kubelet/virtual-kubelet/providers/vic/proxy"
|
||||
import trace "github.com/vmware/vic/pkg/trace"
|
||||
|
||||
// IsolationProxy is an autogenerated mock type for the IsolationProxy type
|
||||
type IsolationProxy struct {
|
||||
mock.Mock
|
||||
}
|
||||
|
||||
// AddHandleToScope provides a mock function with given fields: op, handle, config
|
||||
func (_m *IsolationProxy) AddHandleToScope(op trace.Operation, handle string, config proxy.IsolationContainerConfig) (string, error) {
|
||||
ret := _m.Called(op, handle, config)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, proxy.IsolationContainerConfig) string); ok {
|
||||
r0 = rf(op, handle, config)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, proxy.IsolationContainerConfig) error); ok {
|
||||
r1 = rf(op, handle, config)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddImageToHandle provides a mock function with given fields: op, handle, deltaID, layerID, imageID, imageName
|
||||
func (_m *IsolationProxy) AddImageToHandle(op trace.Operation, handle string, deltaID string, layerID string, imageID string, imageName string) (string, error) {
|
||||
ret := _m.Called(op, handle, deltaID, layerID, imageID, imageName)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, string, string) string); ok {
|
||||
r0 = rf(op, handle, deltaID, layerID, imageID, imageName)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string, string, string) error); ok {
|
||||
r1 = rf(op, handle, deltaID, layerID, imageID, imageName)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddInteractionToHandle provides a mock function with given fields: op, handle
|
||||
func (_m *IsolationProxy) AddInteractionToHandle(op trace.Operation, handle string) (string, error) {
|
||||
ret := _m.Called(op, handle)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string) string); ok {
|
||||
r0 = rf(op, handle)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string) error); ok {
|
||||
r1 = rf(op, handle)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// AddLoggingToHandle provides a mock function with given fields: op, handle
|
||||
func (_m *IsolationProxy) AddLoggingToHandle(op trace.Operation, handle string) (string, error) {
|
||||
ret := _m.Called(op, handle)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string) string); ok {
|
||||
r0 = rf(op, handle)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string) error); ok {
|
||||
r1 = rf(op, handle)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// BindScope provides a mock function with given fields: op, handle, name
|
||||
func (_m *IsolationProxy) BindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
ret := _m.Called(op, handle, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, handle, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 interface{}
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) interface{}); ok {
|
||||
r1 = rf(op, handle, name)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation, string, string) error); ok {
|
||||
r2 = rf(op, handle, name)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CommitHandle provides a mock function with given fields: op, handle, containerID, waitTime
|
||||
func (_m *IsolationProxy) CommitHandle(op trace.Operation, handle string, containerID string, waitTime int32) error {
|
||||
ret := _m.Called(op, handle, containerID, waitTime)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, int32) error); ok {
|
||||
r0 = rf(op, handle, containerID, waitTime)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// CreateHandle provides a mock function with given fields: op
|
||||
func (_m *IsolationProxy) CreateHandle(op trace.Operation) (string, string, error) {
|
||||
ret := _m.Called(op)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation) string); ok {
|
||||
r0 = rf(op)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 string
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation) string); ok {
|
||||
r1 = rf(op)
|
||||
} else {
|
||||
r1 = ret.Get(1).(string)
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation) error); ok {
|
||||
r2 = rf(op)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
|
||||
// CreateHandleTask provides a mock function with given fields: op, handle, id, layerID, config
|
||||
func (_m *IsolationProxy) CreateHandleTask(op trace.Operation, handle string, id string, layerID string, config proxy.IsolationContainerConfig) (string, error) {
|
||||
ret := _m.Called(op, handle, id, layerID, config)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string, proxy.IsolationContainerConfig) string); ok {
|
||||
r0 = rf(op, handle, id, layerID, config)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string, proxy.IsolationContainerConfig) error); ok {
|
||||
r1 = rf(op, handle, id, layerID, config)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Handle provides a mock function with given fields: op, id, name
|
||||
func (_m *IsolationProxy) Handle(op trace.Operation, id string, name string) (string, error) {
|
||||
ret := _m.Called(op, id, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, id, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) error); ok {
|
||||
r1 = rf(op, id, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// Remove provides a mock function with given fields: op, id, force
|
||||
func (_m *IsolationProxy) Remove(op trace.Operation, id string, force bool) error {
|
||||
ret := _m.Called(op, id, force)
|
||||
|
||||
var r0 error
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, bool) error); ok {
|
||||
r0 = rf(op, id, force)
|
||||
} else {
|
||||
r0 = ret.Error(0)
|
||||
}
|
||||
|
||||
return r0
|
||||
}
|
||||
|
||||
// SetState provides a mock function with given fields: op, handle, name, state
|
||||
func (_m *IsolationProxy) SetState(op trace.Operation, handle string, name string, state string) (string, error) {
|
||||
ret := _m.Called(op, handle, name, state)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string, string) string); ok {
|
||||
r0 = rf(op, handle, name, state)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string, string) error); ok {
|
||||
r1 = rf(op, handle, name, state)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// State provides a mock function with given fields: op, id, name
|
||||
func (_m *IsolationProxy) State(op trace.Operation, id string, name string) (string, error) {
|
||||
ret := _m.Called(op, id, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, id, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 error
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) error); ok {
|
||||
r1 = rf(op, id, name)
|
||||
} else {
|
||||
r1 = ret.Error(1)
|
||||
}
|
||||
|
||||
return r0, r1
|
||||
}
|
||||
|
||||
// UnbindScope provides a mock function with given fields: op, handle, name
|
||||
func (_m *IsolationProxy) UnbindScope(op trace.Operation, handle string, name string) (string, interface{}, error) {
|
||||
ret := _m.Called(op, handle, name)
|
||||
|
||||
var r0 string
|
||||
if rf, ok := ret.Get(0).(func(trace.Operation, string, string) string); ok {
|
||||
r0 = rf(op, handle, name)
|
||||
} else {
|
||||
r0 = ret.Get(0).(string)
|
||||
}
|
||||
|
||||
var r1 interface{}
|
||||
if rf, ok := ret.Get(1).(func(trace.Operation, string, string) interface{}); ok {
|
||||
r1 = rf(op, handle, name)
|
||||
} else {
|
||||
if ret.Get(1) != nil {
|
||||
r1 = ret.Get(1).(interface{})
|
||||
}
|
||||
}
|
||||
|
||||
var r2 error
|
||||
if rf, ok := ret.Get(2).(func(trace.Operation, string, string) error); ok {
|
||||
r2 = rf(op, handle, name)
|
||||
} else {
|
||||
r2 = ret.Error(2)
|
||||
}
|
||||
|
||||
return r0, r1, r2
|
||||
}
|
||||
Reference in New Issue
Block a user