github.com/ssdev-go/moby@v17.12.1-ce-rc2+incompatible/daemon/cluster/convert/container.go (about) 1 package convert 2 3 import ( 4 "errors" 5 "fmt" 6 "strings" 7 8 container "github.com/docker/docker/api/types/container" 9 mounttypes "github.com/docker/docker/api/types/mount" 10 types "github.com/docker/docker/api/types/swarm" 11 swarmapi "github.com/docker/swarmkit/api" 12 gogotypes "github.com/gogo/protobuf/types" 13 "github.com/sirupsen/logrus" 14 ) 15 16 func containerSpecFromGRPC(c *swarmapi.ContainerSpec) *types.ContainerSpec { 17 if c == nil { 18 return nil 19 } 20 containerSpec := &types.ContainerSpec{ 21 Image: c.Image, 22 Labels: c.Labels, 23 Command: c.Command, 24 Args: c.Args, 25 Hostname: c.Hostname, 26 Env: c.Env, 27 Dir: c.Dir, 28 User: c.User, 29 Groups: c.Groups, 30 StopSignal: c.StopSignal, 31 TTY: c.TTY, 32 OpenStdin: c.OpenStdin, 33 ReadOnly: c.ReadOnly, 34 Hosts: c.Hosts, 35 Secrets: secretReferencesFromGRPC(c.Secrets), 36 Configs: configReferencesFromGRPC(c.Configs), 37 Isolation: IsolationFromGRPC(c.Isolation), 38 } 39 40 if c.DNSConfig != nil { 41 containerSpec.DNSConfig = &types.DNSConfig{ 42 Nameservers: c.DNSConfig.Nameservers, 43 Search: c.DNSConfig.Search, 44 Options: c.DNSConfig.Options, 45 } 46 } 47 48 // Privileges 49 if c.Privileges != nil { 50 containerSpec.Privileges = &types.Privileges{} 51 52 if c.Privileges.CredentialSpec != nil { 53 containerSpec.Privileges.CredentialSpec = &types.CredentialSpec{} 54 switch c.Privileges.CredentialSpec.Source.(type) { 55 case *swarmapi.Privileges_CredentialSpec_File: 56 containerSpec.Privileges.CredentialSpec.File = c.Privileges.CredentialSpec.GetFile() 57 case *swarmapi.Privileges_CredentialSpec_Registry: 58 containerSpec.Privileges.CredentialSpec.Registry = c.Privileges.CredentialSpec.GetRegistry() 59 } 60 } 61 62 if c.Privileges.SELinuxContext != nil { 63 containerSpec.Privileges.SELinuxContext = &types.SELinuxContext{ 64 Disable: c.Privileges.SELinuxContext.Disable, 65 User: c.Privileges.SELinuxContext.User, 66 Type: c.Privileges.SELinuxContext.Type, 67 Role: c.Privileges.SELinuxContext.Role, 68 Level: c.Privileges.SELinuxContext.Level, 69 } 70 } 71 } 72 73 // Mounts 74 for _, m := range c.Mounts { 75 mount := mounttypes.Mount{ 76 Target: m.Target, 77 Source: m.Source, 78 Type: mounttypes.Type(strings.ToLower(swarmapi.Mount_MountType_name[int32(m.Type)])), 79 ReadOnly: m.ReadOnly, 80 } 81 82 if m.BindOptions != nil { 83 mount.BindOptions = &mounttypes.BindOptions{ 84 Propagation: mounttypes.Propagation(strings.ToLower(swarmapi.Mount_BindOptions_MountPropagation_name[int32(m.BindOptions.Propagation)])), 85 } 86 } 87 88 if m.VolumeOptions != nil { 89 mount.VolumeOptions = &mounttypes.VolumeOptions{ 90 NoCopy: m.VolumeOptions.NoCopy, 91 Labels: m.VolumeOptions.Labels, 92 } 93 if m.VolumeOptions.DriverConfig != nil { 94 mount.VolumeOptions.DriverConfig = &mounttypes.Driver{ 95 Name: m.VolumeOptions.DriverConfig.Name, 96 Options: m.VolumeOptions.DriverConfig.Options, 97 } 98 } 99 } 100 101 if m.TmpfsOptions != nil { 102 mount.TmpfsOptions = &mounttypes.TmpfsOptions{ 103 SizeBytes: m.TmpfsOptions.SizeBytes, 104 Mode: m.TmpfsOptions.Mode, 105 } 106 } 107 containerSpec.Mounts = append(containerSpec.Mounts, mount) 108 } 109 110 if c.StopGracePeriod != nil { 111 grace, _ := gogotypes.DurationFromProto(c.StopGracePeriod) 112 containerSpec.StopGracePeriod = &grace 113 } 114 115 if c.Healthcheck != nil { 116 containerSpec.Healthcheck = healthConfigFromGRPC(c.Healthcheck) 117 } 118 119 return containerSpec 120 } 121 122 func secretReferencesToGRPC(sr []*types.SecretReference) []*swarmapi.SecretReference { 123 refs := make([]*swarmapi.SecretReference, 0, len(sr)) 124 for _, s := range sr { 125 ref := &swarmapi.SecretReference{ 126 SecretID: s.SecretID, 127 SecretName: s.SecretName, 128 } 129 if s.File != nil { 130 ref.Target = &swarmapi.SecretReference_File{ 131 File: &swarmapi.FileTarget{ 132 Name: s.File.Name, 133 UID: s.File.UID, 134 GID: s.File.GID, 135 Mode: s.File.Mode, 136 }, 137 } 138 } 139 140 refs = append(refs, ref) 141 } 142 143 return refs 144 } 145 146 func secretReferencesFromGRPC(sr []*swarmapi.SecretReference) []*types.SecretReference { 147 refs := make([]*types.SecretReference, 0, len(sr)) 148 for _, s := range sr { 149 target := s.GetFile() 150 if target == nil { 151 // not a file target 152 logrus.Warnf("secret target not a file: secret=%s", s.SecretID) 153 continue 154 } 155 refs = append(refs, &types.SecretReference{ 156 File: &types.SecretReferenceFileTarget{ 157 Name: target.Name, 158 UID: target.UID, 159 GID: target.GID, 160 Mode: target.Mode, 161 }, 162 SecretID: s.SecretID, 163 SecretName: s.SecretName, 164 }) 165 } 166 167 return refs 168 } 169 170 func configReferencesToGRPC(sr []*types.ConfigReference) []*swarmapi.ConfigReference { 171 refs := make([]*swarmapi.ConfigReference, 0, len(sr)) 172 for _, s := range sr { 173 ref := &swarmapi.ConfigReference{ 174 ConfigID: s.ConfigID, 175 ConfigName: s.ConfigName, 176 } 177 if s.File != nil { 178 ref.Target = &swarmapi.ConfigReference_File{ 179 File: &swarmapi.FileTarget{ 180 Name: s.File.Name, 181 UID: s.File.UID, 182 GID: s.File.GID, 183 Mode: s.File.Mode, 184 }, 185 } 186 } 187 188 refs = append(refs, ref) 189 } 190 191 return refs 192 } 193 194 func configReferencesFromGRPC(sr []*swarmapi.ConfigReference) []*types.ConfigReference { 195 refs := make([]*types.ConfigReference, 0, len(sr)) 196 for _, s := range sr { 197 target := s.GetFile() 198 if target == nil { 199 // not a file target 200 logrus.Warnf("config target not a file: config=%s", s.ConfigID) 201 continue 202 } 203 refs = append(refs, &types.ConfigReference{ 204 File: &types.ConfigReferenceFileTarget{ 205 Name: target.Name, 206 UID: target.UID, 207 GID: target.GID, 208 Mode: target.Mode, 209 }, 210 ConfigID: s.ConfigID, 211 ConfigName: s.ConfigName, 212 }) 213 } 214 215 return refs 216 } 217 218 func containerToGRPC(c *types.ContainerSpec) (*swarmapi.ContainerSpec, error) { 219 containerSpec := &swarmapi.ContainerSpec{ 220 Image: c.Image, 221 Labels: c.Labels, 222 Command: c.Command, 223 Args: c.Args, 224 Hostname: c.Hostname, 225 Env: c.Env, 226 Dir: c.Dir, 227 User: c.User, 228 Groups: c.Groups, 229 StopSignal: c.StopSignal, 230 TTY: c.TTY, 231 OpenStdin: c.OpenStdin, 232 ReadOnly: c.ReadOnly, 233 Hosts: c.Hosts, 234 Secrets: secretReferencesToGRPC(c.Secrets), 235 Configs: configReferencesToGRPC(c.Configs), 236 Isolation: isolationToGRPC(c.Isolation), 237 } 238 239 if c.DNSConfig != nil { 240 containerSpec.DNSConfig = &swarmapi.ContainerSpec_DNSConfig{ 241 Nameservers: c.DNSConfig.Nameservers, 242 Search: c.DNSConfig.Search, 243 Options: c.DNSConfig.Options, 244 } 245 } 246 247 if c.StopGracePeriod != nil { 248 containerSpec.StopGracePeriod = gogotypes.DurationProto(*c.StopGracePeriod) 249 } 250 251 // Privileges 252 if c.Privileges != nil { 253 containerSpec.Privileges = &swarmapi.Privileges{} 254 255 if c.Privileges.CredentialSpec != nil { 256 containerSpec.Privileges.CredentialSpec = &swarmapi.Privileges_CredentialSpec{} 257 258 if c.Privileges.CredentialSpec.File != "" && c.Privileges.CredentialSpec.Registry != "" { 259 return nil, errors.New("cannot specify both \"file\" and \"registry\" credential specs") 260 } 261 if c.Privileges.CredentialSpec.File != "" { 262 containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_File{ 263 File: c.Privileges.CredentialSpec.File, 264 } 265 } else if c.Privileges.CredentialSpec.Registry != "" { 266 containerSpec.Privileges.CredentialSpec.Source = &swarmapi.Privileges_CredentialSpec_Registry{ 267 Registry: c.Privileges.CredentialSpec.Registry, 268 } 269 } else { 270 return nil, errors.New("must either provide \"file\" or \"registry\" for credential spec") 271 } 272 } 273 274 if c.Privileges.SELinuxContext != nil { 275 containerSpec.Privileges.SELinuxContext = &swarmapi.Privileges_SELinuxContext{ 276 Disable: c.Privileges.SELinuxContext.Disable, 277 User: c.Privileges.SELinuxContext.User, 278 Type: c.Privileges.SELinuxContext.Type, 279 Role: c.Privileges.SELinuxContext.Role, 280 Level: c.Privileges.SELinuxContext.Level, 281 } 282 } 283 } 284 285 // Mounts 286 for _, m := range c.Mounts { 287 mount := swarmapi.Mount{ 288 Target: m.Target, 289 Source: m.Source, 290 ReadOnly: m.ReadOnly, 291 } 292 293 if mountType, ok := swarmapi.Mount_MountType_value[strings.ToUpper(string(m.Type))]; ok { 294 mount.Type = swarmapi.Mount_MountType(mountType) 295 } else if string(m.Type) != "" { 296 return nil, fmt.Errorf("invalid MountType: %q", m.Type) 297 } 298 299 if m.BindOptions != nil { 300 if mountPropagation, ok := swarmapi.Mount_BindOptions_MountPropagation_value[strings.ToUpper(string(m.BindOptions.Propagation))]; ok { 301 mount.BindOptions = &swarmapi.Mount_BindOptions{Propagation: swarmapi.Mount_BindOptions_MountPropagation(mountPropagation)} 302 } else if string(m.BindOptions.Propagation) != "" { 303 return nil, fmt.Errorf("invalid MountPropagation: %q", m.BindOptions.Propagation) 304 } 305 } 306 307 if m.VolumeOptions != nil { 308 mount.VolumeOptions = &swarmapi.Mount_VolumeOptions{ 309 NoCopy: m.VolumeOptions.NoCopy, 310 Labels: m.VolumeOptions.Labels, 311 } 312 if m.VolumeOptions.DriverConfig != nil { 313 mount.VolumeOptions.DriverConfig = &swarmapi.Driver{ 314 Name: m.VolumeOptions.DriverConfig.Name, 315 Options: m.VolumeOptions.DriverConfig.Options, 316 } 317 } 318 } 319 320 if m.TmpfsOptions != nil { 321 mount.TmpfsOptions = &swarmapi.Mount_TmpfsOptions{ 322 SizeBytes: m.TmpfsOptions.SizeBytes, 323 Mode: m.TmpfsOptions.Mode, 324 } 325 } 326 327 containerSpec.Mounts = append(containerSpec.Mounts, mount) 328 } 329 330 if c.Healthcheck != nil { 331 containerSpec.Healthcheck = healthConfigToGRPC(c.Healthcheck) 332 } 333 334 return containerSpec, nil 335 } 336 337 func healthConfigFromGRPC(h *swarmapi.HealthConfig) *container.HealthConfig { 338 interval, _ := gogotypes.DurationFromProto(h.Interval) 339 timeout, _ := gogotypes.DurationFromProto(h.Timeout) 340 startPeriod, _ := gogotypes.DurationFromProto(h.StartPeriod) 341 return &container.HealthConfig{ 342 Test: h.Test, 343 Interval: interval, 344 Timeout: timeout, 345 Retries: int(h.Retries), 346 StartPeriod: startPeriod, 347 } 348 } 349 350 func healthConfigToGRPC(h *container.HealthConfig) *swarmapi.HealthConfig { 351 return &swarmapi.HealthConfig{ 352 Test: h.Test, 353 Interval: gogotypes.DurationProto(h.Interval), 354 Timeout: gogotypes.DurationProto(h.Timeout), 355 Retries: int32(h.Retries), 356 StartPeriod: gogotypes.DurationProto(h.StartPeriod), 357 } 358 } 359 360 // IsolationFromGRPC converts a swarm api container isolation to a moby isolation representation 361 func IsolationFromGRPC(i swarmapi.ContainerSpec_Isolation) container.Isolation { 362 switch i { 363 case swarmapi.ContainerIsolationHyperV: 364 return container.IsolationHyperV 365 case swarmapi.ContainerIsolationProcess: 366 return container.IsolationProcess 367 case swarmapi.ContainerIsolationDefault: 368 return container.IsolationDefault 369 } 370 return container.IsolationEmpty 371 } 372 373 func isolationToGRPC(i container.Isolation) swarmapi.ContainerSpec_Isolation { 374 if i.IsHyperV() { 375 return swarmapi.ContainerIsolationHyperV 376 } 377 if i.IsProcess() { 378 return swarmapi.ContainerIsolationProcess 379 } 380 return swarmapi.ContainerIsolationDefault 381 }