// CommitContainerHandle() commits any changes to container handle. // func (c *ContainerProxy) CommitContainerHandle(handle, imageID string) error { defer trace.End(trace.Begin(handle)) if c.client == nil { return derr.NewErrorWithStatusCode(fmt.Errorf("ContainerProxy.CommitContainerHandle failed to create a portlayer client"), http.StatusInternalServerError) } _, err := c.client.Containers.Commit(containers.NewCommitParamsWithContext(ctx).WithHandle(handle)) if err != nil { cerr := fmt.Errorf("No such image: %s", imageID) log.Errorf("%s (%s)", cerr, err) // FIXME: Containers.Commit returns more errors than it's swagger spec says. // When no image exist, it also sends back non swagger errors. We should fix // this once Commit returns correct error codes. return derr.NewRequestNotFoundError(cerr) } return nil }
func (n *Network) ConnectContainerToNetwork(containerName, networkName string, endpointConfig *apinet.EndpointSettings) error { vc := cache.ContainerCache().GetContainer(containerName) if vc != nil { containerName = vc.ContainerID } client := PortLayerClient() getRes, err := client.Containers.Get(containers.NewGetParamsWithContext(ctx).WithID(containerName)) if err != nil { switch err := err.(type) { case *containers.GetNotFound: return derr.NewRequestNotFoundError(fmt.Errorf(err.Payload.Message)) case *containers.GetDefault: return derr.NewErrorWithStatusCode(fmt.Errorf(err.Payload.Message), http.StatusInternalServerError) default: return derr.NewErrorWithStatusCode(err, http.StatusInternalServerError) } } h := getRes.Payload nc := &models.NetworkConfig{NetworkName: networkName} if endpointConfig != nil { if endpointConfig.IPAMConfig != nil && endpointConfig.IPAMConfig.IPv4Address != "" { nc.Address = &endpointConfig.IPAMConfig.IPv4Address } // Pass Links and Aliases to PL nc.Aliases = vicendpoint.Alias(endpointConfig) } addConRes, err := client.Scopes.AddContainer(scopes.NewAddContainerParamsWithContext(ctx). WithScope(nc.NetworkName). WithConfig(&models.ScopesAddContainerConfig{ Handle: h, NetworkConfig: nc, })) if err != nil { switch err := err.(type) { case *scopes.AddContainerNotFound: return derr.NewRequestNotFoundError(fmt.Errorf(err.Payload.Message)) case *scopes.AddContainerInternalServerError: return derr.NewErrorWithStatusCode(fmt.Errorf(err.Payload.Message), http.StatusInternalServerError) default: return derr.NewErrorWithStatusCode(err, http.StatusInternalServerError) } } h = addConRes.Payload // only bind if the container is running // get the state of the container getStateRes, err := client.Containers.GetState(containers.NewGetStateParamsWithContext(ctx).WithHandle(h)) if err != nil { switch err := err.(type) { case *containers.GetStateNotFound: return derr.NewRequestNotFoundError(fmt.Errorf(err.Payload.Message)) case *containers.GetStateDefault: return derr.NewErrorWithStatusCode(fmt.Errorf(err.Payload.Message), http.StatusInternalServerError) default: return derr.NewErrorWithStatusCode(err, http.StatusInternalServerError) } } h = getStateRes.Payload.Handle if getStateRes.Payload.State == "RUNNING" { bindRes, err := client.Scopes.BindContainer(scopes.NewBindContainerParamsWithContext(ctx).WithHandle(h)) if err != nil { switch err := err.(type) { case *scopes.BindContainerNotFound: return derr.NewRequestNotFoundError(fmt.Errorf(err.Payload.Message)) case *scopes.BindContainerInternalServerError: return derr.NewErrorWithStatusCode(fmt.Errorf(err.Payload.Message), http.StatusInternalServerError) default: return derr.NewErrorWithStatusCode(err, http.StatusInternalServerError) } } defer func() { if err == nil { return } if _, err2 := client.Scopes.UnbindContainer(scopes.NewUnbindContainerParamsWithContext(ctx).WithHandle(h)); err2 != nil { log.Warnf("failed bind container rollback: %s", err2) } }() h = bindRes.Payload.Handle } // commit handle _, err = client.Containers.Commit(containers.NewCommitParamsWithContext(ctx).WithHandle(h)) if err != nil { switch err := err.(type) { case *containers.CommitNotFound: return derr.NewRequestNotFoundError(fmt.Errorf(err.Payload.Message)) case *containers.CommitDefault: return derr.NewErrorWithStatusCode(fmt.Errorf(err.Payload.Message), http.StatusInternalServerError) default: return derr.NewErrorWithStatusCode(err, http.StatusInternalServerError) } } return nil }
func (c *Container) containerStart(name string, hostConfig *containertypes.HostConfig, bind bool) error { var err error // Get an API client to the portlayer client := c.containerProxy.Client() // Look up the container name in the metadata cache to get long ID vc := cache.ContainerCache().GetContainer(name) if vc == nil { return NotFoundError(name) } id := vc.ContainerID // handle legacy hostConfig if hostConfig != nil { // hostConfig exist for backwards compatibility. TODO: Figure out which parameters we // need to look at in hostConfig } else if vc != nil { hostConfig = vc.HostConfig } if vc != nil && hostConfig.NetworkMode.NetworkName() == "" { hostConfig.NetworkMode = vc.HostConfig.NetworkMode } // get a handle to the container handle, err := c.Handle(id, name) if err != nil { return err } var endpoints []*models.EndpointConfig // bind network if bind { var bindRes *scopes.BindContainerOK bindRes, err = client.Scopes.BindContainer(scopes.NewBindContainerParamsWithContext(ctx).WithHandle(handle)) if err != nil { switch err := err.(type) { case *scopes.BindContainerNotFound: cache.ContainerCache().DeleteContainer(id) return NotFoundError(name) case *scopes.BindContainerInternalServerError: return InternalServerError(err.Payload.Message) default: return InternalServerError(err.Error()) } } handle = bindRes.Payload.Handle endpoints = bindRes.Payload.Endpoints // unbind in case we fail later defer func() { if err != nil { client.Scopes.UnbindContainer(scopes.NewUnbindContainerParamsWithContext(ctx).WithHandle(handle)) } }() // unmap ports that vc needs if they're not being used by previously mapped container err = c.cleanupPortBindings(vc) if err != nil { return err } } // change the state of the container // TODO: We need a resolved ID from the name var stateChangeRes *containers.StateChangeOK stateChangeRes, err = client.Containers.StateChange(containers.NewStateChangeParamsWithContext(ctx).WithHandle(handle).WithState("RUNNING")) if err != nil { switch err := err.(type) { case *containers.StateChangeNotFound: cache.ContainerCache().DeleteContainer(id) return NotFoundError(name) case *containers.StateChangeDefault: return InternalServerError(err.Payload.Message) default: return InternalServerError(err.Error()) } } handle = stateChangeRes.Payload // map ports if bind { e := c.findPortBoundNetworkEndpoint(hostConfig, endpoints) if err = MapPorts(hostConfig, e, id); err != nil { return InternalServerError(fmt.Sprintf("error mapping ports: %s", err)) } defer func() { if err != nil { UnmapPorts(hostConfig) } }() } // commit the handle; this will reconfigure and start the vm _, err = client.Containers.Commit(containers.NewCommitParamsWithContext(ctx).WithHandle(handle)) if err != nil { switch err := err.(type) { case *containers.CommitNotFound: cache.ContainerCache().DeleteContainer(id) return NotFoundError(name) case *containers.CommitConflict: return ConflictError(err.Error()) case *containers.CommitDefault: return InternalServerError(err.Payload.Message) default: return InternalServerError(err.Error()) } } return nil }
// ContainerAttach attaches to logs according to the config passed in. See ContainerAttachConfig. func (c *Container) ContainerAttach(name string, ca *backend.ContainerAttachConfig) error { defer trace.End(trace.Begin(name)) // Look up the container name in the metadata cache to get long ID vc := cache.ContainerCache().GetContainer(name) if vc == nil { return NotFoundError(name) } id := vc.ContainerID client := c.containerProxy.Client() handle, err := c.Handle(id, name) if err != nil { return err } bind, err := client.Interaction.InteractionBind(interaction.NewInteractionBindParamsWithContext(ctx). WithConfig(&models.InteractionBindConfig{ Handle: handle, })) if err != nil { return InternalServerError(err.Error()) } handle, ok := bind.Payload.Handle.(string) if !ok { return InternalServerError(fmt.Sprintf("Type assertion failed for %#+v", handle)) } // commit the handle; this will reconfigure the vm _, err = client.Containers.Commit(containers.NewCommitParamsWithContext(ctx).WithHandle(handle)) if err != nil { switch err := err.(type) { case *containers.CommitNotFound: return NotFoundError(name) case *containers.CommitConflict: return ConflictError(err.Error()) case *containers.CommitDefault: return InternalServerError(err.Payload.Message) default: return InternalServerError(err.Error()) } } clStdin, clStdout, clStderr, err := ca.GetStreams() if err != nil { return InternalServerError("Unable to get stdio streams for calling client") } defer clStdin.Close() if !vc.Config.Tty && ca.MuxStreams { // replace the stdout/stderr with Docker's multiplex stream if ca.UseStdout { clStderr = stdcopy.NewStdWriter(clStderr, stdcopy.Stderr) } if ca.UseStderr { clStdout = stdcopy.NewStdWriter(clStdout, stdcopy.Stdout) } } err = c.containerProxy.AttachStreams(context.Background(), vc, clStdin, clStdout, clStderr, ca) if err != nil { if _, ok := err.(DetachError); ok { log.Infof("Detach detected, tearing down connection") client = c.containerProxy.Client() handle, err = c.Handle(id, name) if err != nil { return err } unbind, err := client.Interaction.InteractionUnbind(interaction.NewInteractionUnbindParamsWithContext(ctx). WithConfig(&models.InteractionUnbindConfig{ Handle: handle, })) if err != nil { return InternalServerError(err.Error()) } handle, ok = unbind.Payload.Handle.(string) if !ok { return InternalServerError("type assertion failed") } // commit the handle; this will reconfigure the vm _, err = client.Containers.Commit(containers.NewCommitParamsWithContext(ctx).WithHandle(handle)) if err != nil { switch err := err.(type) { case *containers.CommitNotFound: return NotFoundError(name) case *containers.CommitDefault: return InternalServerError(err.Payload.Message) default: return InternalServerError(err.Error()) } } } return err } return nil }