func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) { if flags.Changed(flagPublishAdd) { values := flags.Lookup(flagPublishAdd).Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) for port := range ports { *portConfig = append(*portConfig, convertPortToPortConfig(port, portBindings)...) } } if !flags.Changed(flagPublishRemove) { return } toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll() newPorts := []swarm.PortConfig{} portLoop: for _, port := range *portConfig { for _, rawTargetPort := range toRemove { targetPort := nat.Port(rawTargetPort) if equalPort(targetPort, port) { continue portLoop } } newPorts = append(newPorts, port) } *portConfig = newPorts }
func flagChanged(flags *flag.FlagSet, key string) bool { flag := flags.Lookup(key) if flag == nil { return false } return flag.Changed }
func (c *Config) updateFlag(name string, flags *flag.FlagSet) { if f := flags.Lookup(name); f != nil { val := c.Viper.Get(name) strVal := fmt.Sprintf("%v", val) f.DefValue = strVal } }
// TODO: should this override by destination path, or does swarm handle that? func updateMounts(flags *pflag.FlagSet, mounts *[]swarm.Mount) { if !flags.Changed(flagMount) { return } *mounts = flags.Lookup(flagMount).Value.(*MountOpt).Value() }
// findConfigurationConflicts iterates over the provided flags searching for // duplicated configurations and unknown keys. It returns an error with all the conflicts if // it finds any. func findConfigurationConflicts(config map[string]interface{}, flags *pflag.FlagSet) error { // 1. Search keys from the file that we don't recognize as flags. unknownKeys := make(map[string]interface{}) for key, value := range config { if flag := flags.Lookup(key); flag == nil { unknownKeys[key] = value } } // 2. Discard values that implement NamedOption. // Their configuration name differs from their flag name, like `labels` and `label`. if len(unknownKeys) > 0 { unknownNamedConflicts := func(f *pflag.Flag) { if namedOption, ok := f.Value.(opts.NamedOption); ok { if _, valid := unknownKeys[namedOption.Name()]; valid { delete(unknownKeys, namedOption.Name()) } } } flags.VisitAll(unknownNamedConflicts) } if len(unknownKeys) > 0 { var unknown []string for key := range unknownKeys { unknown = append(unknown, key) } return fmt.Errorf("the following directives don't match any configuration option: %s", strings.Join(unknown, ", ")) } var conflicts []string printConflict := func(name string, flagValue, fileValue interface{}) string { return fmt.Sprintf("%s: (from flag: %v, from file: %v)", name, flagValue, fileValue) } // 3. Search keys that are present as a flag and as a file option. duplicatedConflicts := func(f *pflag.Flag) { // search option name in the json configuration payload if the value is a named option if namedOption, ok := f.Value.(opts.NamedOption); ok { if optsValue, ok := config[namedOption.Name()]; ok { conflicts = append(conflicts, printConflict(namedOption.Name(), f.Value.String(), optsValue)) } } else { // search flag name in the json configuration payload for _, name := range []string{f.Name, f.Shorthand} { if value, ok := config[name]; ok { conflicts = append(conflicts, printConflict(name, f.Value.String(), value)) break } } } } flags.Visit(duplicatedConflicts) if len(conflicts) > 0 { return fmt.Errorf("the following directives are specified both as a flag and in the configuration file: %s", strings.Join(conflicts, ", ")) } return nil }
// Test if the named flag is a boolean flag. func isBooleanFlag(name string, f *flag.FlagSet) bool { flag := f.Lookup(name) if flag == nil { return false } return flag.Value.Type() == "bool" }
// Merge all of the flags from fsFrom into fsTo. func AddPFlagSetToPFlagSet(fsFrom *pflag.FlagSet, fsTo *pflag.FlagSet) { fsFrom.VisitAll(func(f *pflag.Flag) { if fsTo.Lookup(f.Name) == nil { fsTo.AddFlag(f) } }) }
func mergeSwarm(swarm *swarm.Swarm, flags *pflag.FlagSet) error { spec := &swarm.Spec if flags.Changed(flagTaskHistoryLimit) { spec.Orchestration.TaskHistoryRetentionLimit, _ = flags.GetInt64(flagTaskHistoryLimit) } if flags.Changed(flagDispatcherHeartbeat) { if v, err := flags.GetDuration(flagDispatcherHeartbeat); err == nil { spec.Dispatcher.HeartbeatPeriod = uint64(v.Nanoseconds()) } } if flags.Changed(flagCertExpiry) { if v, err := flags.GetDuration(flagCertExpiry); err == nil { spec.CAConfig.NodeCertExpiry = v } } if flags.Changed(flagExternalCA) { value := flags.Lookup(flagExternalCA).Value.(*ExternalCAOption) spec.CAConfig.ExternalCAs = value.Value() } return nil }
func updateMounts(flags *pflag.FlagSet, mounts *[]mounttypes.Mount) error { mountsByTarget := map[string]mounttypes.Mount{} if flags.Changed(flagMountAdd) { values := flags.Lookup(flagMountAdd).Value.(*opts.MountOpt).Value() for _, mount := range values { if _, ok := mountsByTarget[mount.Target]; ok { return fmt.Errorf("duplicate mount target") } mountsByTarget[mount.Target] = mount } } // Add old list of mount points minus updated one. for _, mount := range *mounts { if _, ok := mountsByTarget[mount.Target]; !ok { mountsByTarget[mount.Target] = mount } } newMounts := []mounttypes.Mount{} toRemove := buildToRemoveSet(flags, flagMountRemove) for _, mount := range mountsByTarget { if _, exists := toRemove[mount.Target]; !exists { newMounts = append(newMounts, mount) } } sort.Sort(byMountSource(newMounts)) *mounts = newMounts return nil }
func mergeSwarm(swarm *swarm.Swarm, flags *pflag.FlagSet) error { spec := &swarm.Spec if flags.Changed("auto-accept") { value := flags.Lookup("auto-accept").Value.(*AutoAcceptOption) if len(spec.AcceptancePolicy.Policies) > 0 { spec.AcceptancePolicy.Policies = value.Policies(spec.AcceptancePolicy.Policies[0].Secret) } else { spec.AcceptancePolicy.Policies = value.Policies("") } } if flags.Changed("secret") { secret, _ := flags.GetString("secret") for _, policy := range spec.AcceptancePolicy.Policies { policy.Secret = secret } } if flags.Changed("task-history-limit") { spec.Orchestration.TaskHistoryRetentionLimit, _ = flags.GetInt64("task-history-limit") } if flags.Changed("dispatcher-heartbeat") { if v, err := flags.GetDuration("dispatcher-heartbeat"); err == nil { spec.Dispatcher.HeartbeatPeriod = uint64(v.Nanoseconds()) } } return nil }
func updateEnvironment(flags *pflag.FlagSet, field *[]string) { if flags.Changed(flagEnvAdd) { value := flags.Lookup(flagEnvAdd).Value.(*opts.ListOpts) *field = append(*field, value.GetAll()...) } toRemove := buildToRemoveSet(flags, flagEnvRemove) *field = removeItems(*field, toRemove, envKey) }
// TODO: should this override by destination path, or does swarm handle that? func mergeMounts(flags *pflag.FlagSet, mounts *[]swarm.Mount) { if !flags.Changed("mount") { return } values := flags.Lookup("mount").Value.(*MountOpt).Value() *mounts = append(*mounts, values...) }
// getConflictFreeConfiguration loads the configuration from a JSON file. // It compares that configuration with the one provided by the flags, // and returns an error if there are conflicts. func getConflictFreeConfiguration(configFile string, flags *pflag.FlagSet) (*Config, error) { b, err := ioutil.ReadFile(configFile) if err != nil { return nil, err } var config Config var reader io.Reader if flags != nil { var jsonConfig map[string]interface{} reader = bytes.NewReader(b) if err := json.NewDecoder(reader).Decode(&jsonConfig); err != nil { return nil, err } configSet := configValuesSet(jsonConfig) if err := findConfigurationConflicts(configSet, flags); err != nil { return nil, err } // Override flag values to make sure the values set in the config file with nullable values, like `false`, // are not overridden by default truthy values from the flags that were not explicitly set. // See https://github.com/docker/docker/issues/20289 for an example. // // TODO: Rewrite configuration logic to avoid same issue with other nullable values, like numbers. namedOptions := make(map[string]interface{}) for key, value := range configSet { f := flags.Lookup(key) if f == nil { // ignore named flags that don't match namedOptions[key] = value continue } if _, ok := f.Value.(boolValue); ok { f.Value.Set(fmt.Sprintf("%v", value)) } } if len(namedOptions) > 0 { // set also default for mergeVal flags that are boolValue at the same time. flags.VisitAll(func(f *pflag.Flag) { if opt, named := f.Value.(opts.NamedOption); named { v, set := namedOptions[opt.Name()] _, boolean := f.Value.(boolValue) if set && boolean { f.Value.Set(fmt.Sprintf("%v", v)) } } }) } config.valuesSet = configSet } reader = bytes.NewReader(b) err = json.NewDecoder(reader).Decode(&config) return &config, err }
func flagsNotIntersected(l *flag.FlagSet, r *flag.FlagSet) *flag.FlagSet { f := flag.NewFlagSet("notIntersected", flag.ContinueOnError) l.VisitAll(func(flag *flag.Flag) { if r.Lookup(flag.Name) == nil { f.AddFlag(flag) } }) return f }
func confirmAction(flags *pflag.FlagSet) bool { if flags.Lookup(yesFlag).Value.String() == "false" { util.Info("Continue? [Y/n] ") cont := util.AskForConfirmation(true) if !cont { util.Fatal("Cancelled...\n") return false } } return true }
func updateReplicas(flags *pflag.FlagSet, serviceMode *swarm.ServiceMode) error { if !flags.Changed(flagReplicas) { return nil } if serviceMode == nil || serviceMode.Replicated == nil { return fmt.Errorf("replicas can only be used with replicated mode") } serviceMode.Replicated.Replicas = flags.Lookup(flagReplicas).Value.(*Uint64Opt).Value() return nil }
// TODO: should this override by name, or does swarm handle that? func mergePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) { if !flags.Changed("ports") { return } values := flags.Lookup("ports").Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) for port := range ports { *portConfig = append(*portConfig, convertPortToPortConfig(port, portBindings)...) } }
func updateLabels(flags *pflag.FlagSet, field *map[string]string) { if !flags.Changed(flagLabel) { return } values := flags.Lookup(flagLabel).Value.(*opts.ListOpts).GetAll() localLabels := map[string]string{} for key, value := range runconfigopts.ConvertKVStringsToMap(values) { localLabels[key] = value } *field = localLabels }
func buildToRemoveSet(flags *pflag.FlagSet, flag string) map[string]struct{} { var empty struct{} toRemove := make(map[string]struct{}) if !flags.Changed(flag) { return toRemove } toRemoveSlice := flags.Lookup(flag).Value.(*opts.ListOpts).GetAll() for _, key := range toRemoveSlice { toRemove[key] = empty } return toRemove }
// TODO: should this override by name, or does swarm handle that? func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) { if !flags.Changed(flagPublish) { return } values := flags.Lookup(flagPublish).Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) var localPortConfig []swarm.PortConfig for port := range ports { localPortConfig = append(localPortConfig, convertPortToPortConfig(port, portBindings)...) } *portConfig = localPortConfig }
func mergeLabels(flags *pflag.FlagSet, field *map[string]string) { if !flags.Changed("label") { return } if *field == nil { *field = make(map[string]string) } values := flags.Lookup("label").Value.(*opts.ListOpts).GetAll() for key, value := range runconfigopts.ConvertKVStringsToMap(values) { (*field)[key] = value } }
func updateMounts(flags *pflag.FlagSet, mounts *[]mounttypes.Mount) { if flags.Changed(flagMountAdd) { values := flags.Lookup(flagMountAdd).Value.(*MountOpt).Value() *mounts = append(*mounts, values...) } toRemove := buildToRemoveSet(flags, flagMountRemove) newMounts := []mounttypes.Mount{} for _, mount := range *mounts { if _, exists := toRemove[mount.Target]; !exists { newMounts = append(newMounts, mount) } } *mounts = newMounts }
func mergeNodeUpdate(flags *pflag.FlagSet) func(*swarm.Node) error { return func(node *swarm.Node) error { spec := &node.Spec if flags.Changed(flagRole) { str, err := flags.GetString(flagRole) if err != nil { return err } spec.Role = swarm.NodeRole(str) } if flags.Changed(flagMembership) { str, err := flags.GetString(flagMembership) if err != nil { return err } spec.Membership = swarm.NodeMembership(str) } if flags.Changed(flagAvailability) { str, err := flags.GetString(flagAvailability) if err != nil { return err } spec.Availability = swarm.NodeAvailability(str) } if spec.Annotations.Labels == nil { spec.Annotations.Labels = make(map[string]string) } if flags.Changed(flagLabelAdd) { labels := flags.Lookup(flagLabelAdd).Value.(*opts.ListOpts).GetAll() for k, v := range runconfigopts.ConvertKVStringsToMap(labels) { spec.Annotations.Labels[k] = v } } if flags.Changed(flagLabelRemove) { keys := flags.Lookup(flagLabelRemove).Value.(*opts.ListOpts).GetAll() for _, k := range keys { // if a key doesn't exist, fail the command explicitly if _, exists := spec.Annotations.Labels[k]; !exists { return fmt.Errorf("key %s doesn't exist in node's labels", k) } delete(spec.Annotations.Labels, k) } } return nil } }
// Apply stores the provided arguments onto a flag set, reporting any errors // encountered during the process. func Apply(args map[string][]string, flags *pflag.FlagSet) []error { var errs []error for key, value := range args { flag := flags.Lookup(key) if flag == nil { errs = append(errs, fmt.Errorf("%q is not a valid flag", key)) continue } for _, s := range value { if err := flag.Value.Set(s); err != nil { errs = append(errs, fmt.Errorf("%q could not be set: %v", err)) break } } } return errs }
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error { // The key of the map is `port/protocol`, e.g., `80/tcp` portSet := map[string]swarm.PortConfig{} // Build the current list of portConfig for _, entry := range *portConfig { if _, ok := portSet[portConfigToString(&entry)]; !ok { portSet[portConfigToString(&entry)] = entry } } newPorts := []swarm.PortConfig{} // Clean current ports toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.PortOpt).Value() portLoop: for _, port := range portSet { for _, pConfig := range toRemove { if equalProtocol(port.Protocol, pConfig.Protocol) && port.TargetPort == pConfig.TargetPort && equalPublishMode(port.PublishMode, pConfig.PublishMode) { continue portLoop } } newPorts = append(newPorts, port) } // Check to see if there are any conflict in flags. if flags.Changed(flagPublishAdd) { ports := flags.Lookup(flagPublishAdd).Value.(*opts.PortOpt).Value() for _, port := range ports { if _, ok := portSet[portConfigToString(&port)]; ok { continue } //portSet[portConfigToString(&port)] = port newPorts = append(newPorts, port) } } // Sort the PortConfig to avoid unnecessary updates sort.Sort(byPortConfig(newPorts)) *portConfig = newPorts return nil }
// Apply stores the provided arguments onto a flag set, reporting any errors // encountered during the process. func Apply(args map[string][]string, flags *pflag.FlagSet) []error { var errs []error for key, value := range args { flag := flags.Lookup(key) if flag == nil { errs = append(errs, field.Invalid(field.NewPath("flag"), key, "is not a valid flag")) continue } for _, s := range value { if err := flag.Value.Set(s); err != nil { errs = append(errs, field.Invalid(field.NewPath(key), s, fmt.Sprintf("could not be set: %v", err))) break } } } return errs }
func updatePlacement(flags *pflag.FlagSet, placement *swarm.Placement) { if flags.Changed(flagConstraintAdd) { values := flags.Lookup(flagConstraintAdd).Value.(*opts.ListOpts).GetAll() placement.Constraints = append(placement.Constraints, values...) } toRemove := buildToRemoveSet(flags, flagConstraintRemove) newConstraints := []string{} for _, constraint := range placement.Constraints { if _, exists := toRemove[constraint]; !exists { newConstraints = append(newConstraints, constraint) } } // Sort so that result is predictable. sort.Strings(newConstraints) placement.Constraints = newConstraints }
func updatePorts(flags *pflag.FlagSet, portConfig *[]swarm.PortConfig) error { // The key of the map is `port/protocol`, e.g., `80/tcp` portSet := map[string]swarm.PortConfig{} // Check to see if there are any conflict in flags. if flags.Changed(flagPublishAdd) { values := flags.Lookup(flagPublishAdd).Value.(*opts.ListOpts).GetAll() ports, portBindings, _ := nat.ParsePortSpecs(values) for port := range ports { newConfigs := convertPortToPortConfig(port, portBindings) for _, entry := range newConfigs { if v, ok := portSet[portConfigToString(&entry)]; ok && v != entry { return fmt.Errorf("conflicting port mapping between %v:%v/%s and %v:%v/%s", entry.PublishedPort, entry.TargetPort, entry.Protocol, v.PublishedPort, v.TargetPort, v.Protocol) } portSet[portConfigToString(&entry)] = entry } } } // Override previous PortConfig in service if there is any duplicate for _, entry := range *portConfig { if _, ok := portSet[portConfigToString(&entry)]; !ok { portSet[portConfigToString(&entry)] = entry } } toRemove := flags.Lookup(flagPublishRemove).Value.(*opts.ListOpts).GetAll() newPorts := []swarm.PortConfig{} portLoop: for _, port := range portSet { for _, rawTargetPort := range toRemove { targetPort := nat.Port(rawTargetPort) if equalPort(targetPort, port) { continue portLoop } } newPorts = append(newPorts, port) } // Sort the PortConfig to avoid unnecessary updates sort.Sort(byPortConfig(newPorts)) *portConfig = newPorts return nil }
func updateLabels(flags *pflag.FlagSet, field *map[string]string) { if flags.Changed(flagLabelAdd) { if *field == nil { *field = map[string]string{} } values := flags.Lookup(flagLabelAdd).Value.(*opts.ListOpts).GetAll() for key, value := range runconfigopts.ConvertKVStringsToMap(values) { (*field)[key] = value } } if *field != nil && flags.Changed(flagLabelRemove) { toRemove := flags.Lookup(flagLabelRemove).Value.(*opts.ListOpts).GetAll() for _, label := range toRemove { delete(*field, label) } } }
func updateGroups(flags *pflag.FlagSet, groups *[]string) error { if flags.Changed(flagGroupAdd) { values := flags.Lookup(flagGroupAdd).Value.(*opts.ListOpts).GetAll() *groups = append(*groups, values...) } toRemove := buildToRemoveSet(flags, flagGroupRemove) newGroups := []string{} for _, group := range *groups { if _, exists := toRemove[group]; !exists { newGroups = append(newGroups, group) } } // Sort so that result is predictable. sort.Strings(newGroups) *groups = newGroups return nil }