|
@@ -238,6 +238,38 @@ func (r *restartPolicyOptions) ToRestartPolicy() *swarm.RestartPolicy {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+type credentialSpecOpt struct {
|
|
|
|
+ value *swarm.CredentialSpec
|
|
|
|
+ source string
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (c *credentialSpecOpt) Set(value string) error {
|
|
|
|
+ c.source = value
|
|
|
|
+ c.value = &swarm.CredentialSpec{}
|
|
|
|
+ switch {
|
|
|
|
+ case strings.HasPrefix(value, "file://"):
|
|
|
|
+ c.value.File = strings.TrimPrefix(value, "file://")
|
|
|
|
+ case strings.HasPrefix(value, "registry://"):
|
|
|
|
+ c.value.Registry = strings.TrimPrefix(value, "registry://")
|
|
|
|
+ default:
|
|
|
|
+ return errors.New("Invalid credential spec - value must be prefixed file:// or registry:// followed by a value")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return nil
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (c *credentialSpecOpt) Type() string {
|
|
|
|
+ return "credential-spec"
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (c *credentialSpecOpt) String() string {
|
|
|
|
+ return c.source
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+func (c *credentialSpecOpt) Value() *swarm.CredentialSpec {
|
|
|
|
+ return c.value
|
|
|
|
+}
|
|
|
|
+
|
|
func convertNetworks(networks []string) []swarm.NetworkAttachmentConfig {
|
|
func convertNetworks(networks []string) []swarm.NetworkAttachmentConfig {
|
|
nets := []swarm.NetworkAttachmentConfig{}
|
|
nets := []swarm.NetworkAttachmentConfig{}
|
|
for _, network := range networks {
|
|
for _, network := range networks {
|
|
@@ -355,6 +387,7 @@ type serviceOptions struct {
|
|
workdir string
|
|
workdir string
|
|
user string
|
|
user string
|
|
groups opts.ListOpts
|
|
groups opts.ListOpts
|
|
|
|
+ credentialSpec credentialSpecOpt
|
|
stopSignal string
|
|
stopSignal string
|
|
tty bool
|
|
tty bool
|
|
readOnly bool
|
|
readOnly bool
|
|
@@ -500,6 +533,12 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) {
|
|
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
|
EndpointSpec: opts.endpoint.ToEndpointSpec(),
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if opts.credentialSpec.Value() != nil {
|
|
|
|
+ service.TaskTemplate.ContainerSpec.Privileges = &swarm.Privileges{
|
|
|
|
+ CredentialSpec: opts.credentialSpec.Value(),
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
return service, nil
|
|
return service, nil
|
|
}
|
|
}
|
|
|
|
|
|
@@ -511,6 +550,8 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
|
|
|
|
|
|
flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
|
|
flags.StringVarP(&opts.workdir, flagWorkdir, "w", "", "Working directory inside the container")
|
|
flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
|
flags.StringVarP(&opts.user, flagUser, "u", "", "Username or UID (format: <name|uid>[:<group|gid>])")
|
|
|
|
+ flags.Var(&opts.credentialSpec, flagCredentialSpec, "Credential spec for managed service account (Windows only)")
|
|
|
|
+ flags.SetAnnotation(flagCredentialSpec, "version", []string{"1.29"})
|
|
flags.StringVar(&opts.hostname, flagHostname, "", "Container hostname")
|
|
flags.StringVar(&opts.hostname, flagHostname, "", "Container hostname")
|
|
flags.SetAnnotation(flagHostname, "version", []string{"1.25"})
|
|
flags.SetAnnotation(flagHostname, "version", []string{"1.25"})
|
|
flags.Var(&opts.entrypoint, flagEntrypoint, "Overwrite the default ENTRYPOINT of the image")
|
|
flags.Var(&opts.entrypoint, flagEntrypoint, "Overwrite the default ENTRYPOINT of the image")
|
|
@@ -582,6 +623,7 @@ func addServiceFlags(flags *pflag.FlagSet, opts *serviceOptions) {
|
|
}
|
|
}
|
|
|
|
|
|
const (
|
|
const (
|
|
|
|
+ flagCredentialSpec = "credential-spec"
|
|
flagPlacementPref = "placement-pref"
|
|
flagPlacementPref = "placement-pref"
|
|
flagPlacementPrefAdd = "placement-pref-add"
|
|
flagPlacementPrefAdd = "placement-pref-add"
|
|
flagPlacementPrefRemove = "placement-pref-rm"
|
|
flagPlacementPrefRemove = "placement-pref-rm"
|