diff --git a/api/client/service/opts.go b/api/client/service/opts.go index 7c0b0761c6..8b982ca257 100644 --- a/api/client/service/opts.go +++ b/api/client/service/opts.go @@ -358,6 +358,27 @@ func convertPortToPortConfig( return ports } +type logDriverOptions struct { + name string + opts opts.ListOpts +} + +func newLogDriverOptions() logDriverOptions { + return logDriverOptions{opts: opts.NewListOpts(runconfigopts.ValidateEnv)} +} + +func (ldo *logDriverOptions) toLogDriver() *swarm.Driver { + if ldo.name == "" { + return nil + } + + // set the log driver only if specified. + return &swarm.Driver{ + Name: ldo.name, + Options: runconfigopts.ConvertKVStringsToMap(ldo.opts.GetAll()), + } +} + // ValidatePort validates a string is in the expected format for a port definition func ValidatePort(value string) (string, error) { portMappings, err := nat.ParsePortSpec(value) @@ -392,6 +413,8 @@ type serviceOptions struct { endpoint endpointOptions registryAuth bool + + logDriver logDriverOptions } func newServiceOptions() *serviceOptions { @@ -401,6 +424,7 @@ func newServiceOptions() *serviceOptions { endpoint: endpointOptions{ ports: opts.NewListOpts(ValidatePort), }, + logDriver: newLogDriverOptions(), } } @@ -427,6 +451,7 @@ func (opts *serviceOptions) ToService() (swarm.ServiceSpec, error) { Placement: &swarm.Placement{ Constraints: opts.constraints, }, + LogDriver: opts.logDriver.toLogDriver(), }, Mode: swarm.ServiceMode{}, UpdateConfig: &swarm.UpdateConfig{ @@ -482,6 +507,9 @@ func addServiceFlags(cmd *cobra.Command, opts *serviceOptions) { flags.StringVar(&opts.endpoint.mode, flagEndpointMode, "", "Endpoint mode (vip or dnsrr)") flags.BoolVar(&opts.registryAuth, flagRegistryAuth, false, "Send registry authentication details to Swarm agents") + + flags.StringVar(&opts.logDriver.name, flagLogDriver, "", "Logging driver for service") + flags.Var(&opts.logDriver.opts, flagLogOpt, "Logging driver options") } const ( @@ -520,4 +548,6 @@ const ( flagUpdateParallelism = "update-parallelism" flagUser = "user" flagRegistryAuth = "registry-auth" + flagLogDriver = "log-driver" + flagLogOpt = "log-opt" ) diff --git a/api/client/service/update.go b/api/client/service/update.go index 8ad3f58e90..c8538fbd2f 100644 --- a/api/client/service/update.go +++ b/api/client/service/update.go @@ -211,6 +211,11 @@ func updateService(flags *pflag.FlagSet, spec *swarm.ServiceSpec) error { } updatePorts(flags, &spec.EndpointSpec.Ports) } + + if err := updateLogDriver(flags, &spec.TaskTemplate); err != nil { + return err + } + return nil } @@ -386,3 +391,27 @@ func updateReplicas(flags *pflag.FlagSet, serviceMode *swarm.ServiceMode) error serviceMode.Replicated.Replicas = flags.Lookup(flagReplicas).Value.(*Uint64Opt).Value() return nil } + +// updateLogDriver updates the log driver only if the log driver flag is set. +// All options will be replaced with those provided on the command line. +func updateLogDriver(flags *pflag.FlagSet, taskTemplate *swarm.TaskSpec) error { + if !flags.Changed(flagLogDriver) { + return nil + } + + name, err := flags.GetString(flagLogDriver) + if err != nil { + return err + } + + if name == "" { + return nil + } + + taskTemplate.LogDriver = &swarm.Driver{ + Name: name, + Options: runconfigopts.ConvertKVStringsToMap(flags.Lookup(flagLogOpt).Value.(*opts.ListOpts).GetAll()), + } + + return nil +} diff --git a/daemon/cluster/convert/service.go b/daemon/cluster/convert/service.go index 912d601354..2872b10ab8 100644 --- a/daemon/cluster/convert/service.go +++ b/daemon/cluster/convert/service.go @@ -28,6 +28,7 @@ func ServiceFromGRPC(s swarmapi.Service) types.Service { Resources: resourcesFromGRPC(s.Spec.Task.Resources), RestartPolicy: restartPolicyFromGRPC(s.Spec.Task.Restart), Placement: placementFromGRPC(s.Spec.Task.Placement), + LogDriver: driverFromGRPC(s.Spec.Task.LogDriver), }, Networks: networks, @@ -86,6 +87,7 @@ func ServiceSpecToGRPC(s types.ServiceSpec) (swarmapi.ServiceSpec, error) { }, Task: swarmapi.TaskSpec{ Resources: resourcesToGRPC(s.TaskTemplate.Resources), + LogDriver: driverToGRPC(s.TaskTemplate.LogDriver), }, Networks: networks, } @@ -251,3 +253,25 @@ func placementFromGRPC(p *swarmapi.Placement) *types.Placement { return r } + +func driverFromGRPC(p *swarmapi.Driver) *types.Driver { + if p == nil { + return nil + } + + return &types.Driver{ + Name: p.Name, + Options: p.Options, + } +} + +func driverToGRPC(p *types.Driver) *swarmapi.Driver { + if p == nil { + return nil + } + + return &swarmapi.Driver{ + Name: p.Name, + Options: p.Options, + } +} diff --git a/daemon/cluster/convert/task.go b/daemon/cluster/convert/task.go index b701ae36cf..4ba85b726a 100644 --- a/daemon/cluster/convert/task.go +++ b/daemon/cluster/convert/task.go @@ -22,6 +22,7 @@ func TaskFromGRPC(t swarmapi.Task) types.Task { Resources: resourcesFromGRPC(t.Spec.Resources), RestartPolicy: restartPolicyFromGRPC(t.Spec.Restart), Placement: placementFromGRPC(t.Spec.Placement), + LogDriver: driverFromGRPC(t.Spec.LogDriver), }, Status: types.TaskStatus{ State: types.TaskState(strings.ToLower(t.Status.State.String())),