Example #1
0
// 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
}
Example #2
0
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
}
Example #3
0
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
}
Example #4
0
// 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
}