func endpointFromGRPC(e *swarmapi.Endpoint) types.Endpoint { endpoint := types.Endpoint{} if e != nil { if espec := endpointSpecFromGRPC(e.Spec); espec != nil { endpoint.Spec = *espec } for _, portState := range e.Ports { endpoint.Ports = append(endpoint.Ports, types.PortConfig{ Name: portState.Name, Protocol: types.PortConfigProtocol(strings.ToLower(swarmapi.PortConfig_Protocol_name[int32(portState.Protocol)])), TargetPort: portState.TargetPort, PublishedPort: portState.PublishedPort, }) } for _, v := range e.VirtualIPs { endpoint.VirtualIPs = append(endpoint.VirtualIPs, types.EndpointVirtualIP{ NetworkID: v.NetworkID, Addr: v.Addr}) } } return endpoint }
// Set a new port value func (p *PortOpt) Set(value string) error { csvReader := csv.NewReader(strings.NewReader(value)) fields, err := csvReader.Read() if err != nil { return err } pConfig := swarm.PortConfig{} for _, field := range fields { parts := strings.SplitN(field, "=", 2) if len(parts) != 2 { return fmt.Errorf("invalid field %s", field) } key := strings.ToLower(parts[0]) value := strings.ToLower(parts[1]) switch key { case portOptProtocol: if value != string(swarm.PortConfigProtocolTCP) && value != string(swarm.PortConfigProtocolUDP) { return fmt.Errorf("invalid protocol value %s", value) } pConfig.Protocol = swarm.PortConfigProtocol(value) case portOptMode: if value != string(swarm.PortConfigPublishModeIngress) && value != string(swarm.PortConfigPublishModeHost) { return fmt.Errorf("invalid publish mode value %s", value) } pConfig.PublishMode = swarm.PortConfigPublishMode(value) case portOptTargetPort: tPort, err := strconv.ParseUint(value, 10, 16) if err != nil { return err } pConfig.TargetPort = uint32(tPort) case portOptPublishedPort: pPort, err := strconv.ParseUint(value, 10, 16) if err != nil { return err } pConfig.PublishedPort = uint32(pPort) default: return fmt.Errorf("invalid field key %s", key) } } if pConfig.TargetPort == 0 { return fmt.Errorf("missing mandatory field %q", portOptTargetPort) } p.ports = append(p.ports, pConfig) return nil }
func convertPortToPortConfig( port nat.Port, portBindings map[nat.Port][]nat.PortBinding, ) []swarm.PortConfig { ports := []swarm.PortConfig{} for _, binding := range portBindings[port] { hostPort, _ := strconv.ParseUint(binding.HostPort, 10, 16) ports = append(ports, swarm.PortConfig{ //TODO Name: ? Protocol: swarm.PortConfigProtocol(strings.ToLower(port.Proto())), TargetPort: uint32(port.Int()), PublishedPort: uint32(hostPort), }) } return ports }
func endpointSpecFromGRPC(es *swarmapi.EndpointSpec) *types.EndpointSpec { var endpointSpec *types.EndpointSpec if es != nil { endpointSpec = &types.EndpointSpec{} endpointSpec.Mode = types.ResolutionMode(strings.ToLower(es.Mode.String())) for _, portState := range es.Ports { endpointSpec.Ports = append(endpointSpec.Ports, types.PortConfig{ Name: portState.Name, Protocol: types.PortConfigProtocol(strings.ToLower(swarmapi.PortConfig_Protocol_name[int32(portState.Protocol)])), TargetPort: portState.TargetPort, PublishedPort: portState.PublishedPort, }) } } return endpointSpec }
func deployBundle(ctx context.Context, dockerCli *command.DockerCli, opts deployOptions) error { bundle, err := loadBundlefile(dockerCli.Err(), opts.namespace, opts.bundlefile) if err != nil { return err } if err := checkDaemonIsSwarmManager(ctx, dockerCli); err != nil { return err } namespace := namespace{name: opts.namespace} networks := make(map[string]types.NetworkCreate) for _, service := range bundle.Services { for _, networkName := range service.Networks { networks[networkName] = types.NetworkCreate{ Labels: getStackLabels(namespace.name, nil), } } } services := make(map[string]swarm.ServiceSpec) for internalName, service := range bundle.Services { name := namespace.scope(internalName) var ports []swarm.PortConfig for _, portSpec := range service.Ports { ports = append(ports, swarm.PortConfig{ Protocol: swarm.PortConfigProtocol(portSpec.Protocol), TargetPort: portSpec.Port, }) } nets := []swarm.NetworkAttachmentConfig{} for _, networkName := range service.Networks { nets = append(nets, swarm.NetworkAttachmentConfig{ Target: namespace.scope(networkName), Aliases: []string{networkName}, }) } serviceSpec := swarm.ServiceSpec{ Annotations: swarm.Annotations{ Name: name, Labels: getStackLabels(namespace.name, service.Labels), }, TaskTemplate: swarm.TaskSpec{ ContainerSpec: swarm.ContainerSpec{ Image: service.Image, Command: service.Command, Args: service.Args, Env: service.Env, // Service Labels will not be copied to Containers // automatically during the deployment so we apply // it here. Labels: getStackLabels(namespace.name, nil), }, }, EndpointSpec: &swarm.EndpointSpec{ Ports: ports, }, Networks: nets, } services[internalName] = serviceSpec } if err := createNetworks(ctx, dockerCli, namespace, networks); err != nil { return err } return deployServices(ctx, dockerCli, services, namespace, opts.sendRegistryAuth) }
func deployServices( ctx context.Context, dockerCli *command.DockerCli, services map[string]bundlefile.Service, namespace string, sendAuth bool, ) error { apiClient := dockerCli.Client() out := dockerCli.Out() existingServices, err := getServices(ctx, apiClient, namespace) if err != nil { return err } existingServiceMap := make(map[string]swarm.Service) for _, service := range existingServices { existingServiceMap[service.Spec.Name] = service } for internalName, service := range services { name := fmt.Sprintf("%s_%s", namespace, internalName) var ports []swarm.PortConfig for _, portSpec := range service.Ports { ports = append(ports, swarm.PortConfig{ Protocol: swarm.PortConfigProtocol(portSpec.Protocol), TargetPort: portSpec.Port, }) } serviceSpec := swarm.ServiceSpec{ Annotations: swarm.Annotations{ Name: name, Labels: getStackLabels(namespace, service.Labels), }, TaskTemplate: swarm.TaskSpec{ ContainerSpec: swarm.ContainerSpec{ Image: service.Image, Command: service.Command, Args: service.Args, Env: service.Env, // Service Labels will not be copied to Containers // automatically during the deployment so we apply // it here. Labels: getStackLabels(namespace, nil), }, }, EndpointSpec: &swarm.EndpointSpec{ Ports: ports, }, Networks: convertNetworks(service.Networks, namespace, internalName), } cspec := &serviceSpec.TaskTemplate.ContainerSpec if service.WorkingDir != nil { cspec.Dir = *service.WorkingDir } if service.User != nil { cspec.User = *service.User } encodedAuth := "" if sendAuth { // Retrieve encoded auth token from the image reference image := serviceSpec.TaskTemplate.ContainerSpec.Image encodedAuth, err = dockerCli.RetrieveAuthTokenFromImage(ctx, image) if err != nil { return err } } if service, exists := existingServiceMap[name]; exists { fmt.Fprintf(out, "Updating service %s (id: %s)\n", name, service.ID) updateOpts := types.ServiceUpdateOptions{} if sendAuth { updateOpts.EncodedRegistryAuth = encodedAuth } if err := apiClient.ServiceUpdate( ctx, service.ID, service.Version, serviceSpec, updateOpts, ); err != nil { return err } } else { fmt.Fprintf(out, "Creating service %s\n", name) createOpts := types.ServiceCreateOptions{} if sendAuth { createOpts.EncodedRegistryAuth = encodedAuth } if _, err := apiClient.ServiceCreate(ctx, serviceSpec, createOpts); err != nil { return err } } } return nil }
func equalProtocol(prot1, prot2 swarm.PortConfigProtocol) bool { return prot1 == prot2 || (prot1 == swarm.PortConfigProtocol("") && prot2 == swarm.PortConfigProtocolTCP) || (prot2 == swarm.PortConfigProtocol("") && prot1 == swarm.PortConfigProtocolTCP) }
// Set a new port value func (p *PortOpt) Set(value string) error { longSyntax, err := regexp.MatchString(`\w+=\w+(,\w+=\w+)*`, value) if err != nil { return err } if longSyntax { csvReader := csv.NewReader(strings.NewReader(value)) fields, err := csvReader.Read() if err != nil { return err } pConfig := swarm.PortConfig{} for _, field := range fields { parts := strings.SplitN(field, "=", 2) if len(parts) != 2 { return fmt.Errorf("invalid field %s", field) } key := strings.ToLower(parts[0]) value := strings.ToLower(parts[1]) switch key { case portOptProtocol: if value != string(swarm.PortConfigProtocolTCP) && value != string(swarm.PortConfigProtocolUDP) { return fmt.Errorf("invalid protocol value %s", value) } pConfig.Protocol = swarm.PortConfigProtocol(value) case portOptMode: if value != string(swarm.PortConfigPublishModeIngress) && value != string(swarm.PortConfigPublishModeHost) { return fmt.Errorf("invalid publish mode value %s", value) } pConfig.PublishMode = swarm.PortConfigPublishMode(value) case portOptTargetPort: tPort, err := strconv.ParseUint(value, 10, 16) if err != nil { return err } pConfig.TargetPort = uint32(tPort) case portOptPublishedPort: pPort, err := strconv.ParseUint(value, 10, 16) if err != nil { return err } pConfig.PublishedPort = uint32(pPort) default: return fmt.Errorf("invalid field key %s", key) } } if pConfig.TargetPort == 0 { return fmt.Errorf("missing mandatory field %q", portOptTargetPort) } if pConfig.PublishMode == "" { pConfig.PublishMode = swarm.PortConfigPublishModeIngress } if pConfig.Protocol == "" { pConfig.Protocol = swarm.PortConfigProtocolTCP } p.ports = append(p.ports, pConfig) } else { // short syntax portConfigs := []swarm.PortConfig{} // We can ignore errors because the format was already validated by ValidatePort ports, portBindings, _ := nat.ParsePortSpecs([]string{value}) for port := range ports { portConfigs = append(portConfigs, ConvertPortToPortConfig(port, portBindings)...) } p.ports = append(p.ports, portConfigs...) } return nil }
// TaskFromGRPC converts a grpc Task to a Task. func TaskFromGRPC(t swarmapi.Task) types.Task { if t.Spec.GetAttachment() != nil { return types.Task{} } containerConfig := t.Spec.Runtime.(*swarmapi.TaskSpec_Container).Container containerStatus := t.Status.GetContainer() networks := make([]types.NetworkAttachmentConfig, 0, len(t.Spec.Networks)) for _, n := range t.Spec.Networks { networks = append(networks, types.NetworkAttachmentConfig{Target: n.Target, Aliases: n.Aliases}) } task := types.Task{ ID: t.ID, Annotations: types.Annotations{ Name: t.Annotations.Name, Labels: t.Annotations.Labels, }, ServiceID: t.ServiceID, Slot: int(t.Slot), NodeID: t.NodeID, Spec: types.TaskSpec{ ContainerSpec: containerSpecFromGRPC(containerConfig), Resources: resourcesFromGRPC(t.Spec.Resources), RestartPolicy: restartPolicyFromGRPC(t.Spec.Restart), Placement: placementFromGRPC(t.Spec.Placement), LogDriver: driverFromGRPC(t.Spec.LogDriver), Networks: networks, }, Status: types.TaskStatus{ State: types.TaskState(strings.ToLower(t.Status.State.String())), Message: t.Status.Message, Err: t.Status.Err, }, DesiredState: types.TaskState(strings.ToLower(t.DesiredState.String())), } // Meta task.Version.Index = t.Meta.Version.Index task.CreatedAt, _ = ptypes.Timestamp(t.Meta.CreatedAt) task.UpdatedAt, _ = ptypes.Timestamp(t.Meta.UpdatedAt) task.Status.Timestamp, _ = ptypes.Timestamp(t.Status.Timestamp) if containerStatus != nil { task.Status.ContainerStatus.ContainerID = containerStatus.ContainerID task.Status.ContainerStatus.PID = int(containerStatus.PID) task.Status.ContainerStatus.ExitCode = int(containerStatus.ExitCode) } // NetworksAttachments for _, na := range t.Networks { task.NetworksAttachments = append(task.NetworksAttachments, networkAttachementFromGRPC(na)) } if t.Status.PortStatus == nil { return task } for _, p := range t.Status.PortStatus.Ports { task.Status.PortStatus.Ports = append(task.Status.PortStatus.Ports, types.PortConfig{ Name: p.Name, Protocol: types.PortConfigProtocol(strings.ToLower(swarmapi.PortConfig_Protocol_name[int32(p.Protocol)])), PublishMode: types.PortConfigPublishMode(strings.ToLower(swarmapi.PortConfig_PublishMode_name[int32(p.PublishMode)])), TargetPort: p.TargetPort, PublishedPort: p.PublishedPort, }) } return task }