// Complete sets any default behavior for the command func (o *NewAppOptions) Complete(commandName string, f *clientcmd.Factory, c *cobra.Command, args []string, out io.Writer) error { o.Out = out o.ErrOut = c.OutOrStderr() o.Output = kcmdutil.GetFlagString(c, "output") // Only output="" should print descriptions of intermediate steps. Everything // else should print only some specific output (json, yaml, go-template, ...) if len(o.Output) == 0 { o.Config.Out = o.Out } else { o.Config.Out = ioutil.Discard } o.Config.ErrOut = o.ErrOut o.Action.Out, o.Action.ErrOut = o.Out, o.ErrOut o.Action.Bulk.Mapper = clientcmd.ResourceMapper(f) o.Action.Bulk.Op = configcmd.Create // Retry is used to support previous versions of the API server that will // consider the presence of an unknown trigger type to be an error. o.Action.Bulk.Retry = retryBuildConfig o.Config.DryRun = o.Action.DryRun o.CommandPath = c.CommandPath() o.CommandName = commandName mapper, _ := f.Object(false) o.PrintObject = cmdutil.VersionedPrintObject(f.PrintObject, c, mapper, out) o.LogsForObject = f.LogsForObject if err := CompleteAppConfig(o.Config, f, c, args); err != nil { return err } if err := setAppConfigLabels(c, o.Config); err != nil { return err } return nil }
// Complete completes any options that are required by validate or run steps. func (opts *RegistryOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, out io.Writer, args []string) error { if len(args) > 0 { return kcmdutil.UsageError(cmd, "No arguments are allowed to this command") } opts.image = opts.Config.ImageTemplate.ExpandOrDie(opts.Config.Type) opts.label = map[string]string{ "docker-registry": "default", } if opts.Config.Labels != defaultLabel { valid, remove, err := app.LabelsFromSpec(strings.Split(opts.Config.Labels, ",")) if err != nil { return err } if len(remove) > 0 { return kcmdutil.UsageError(cmd, "You may not pass negative labels in %q", opts.Config.Labels) } opts.label = valid } opts.nodeSelector = map[string]string{} if len(opts.Config.Selector) > 0 { valid, remove, err := app.LabelsFromSpec(strings.Split(opts.Config.Selector, ",")) if err != nil { return err } if len(remove) > 0 { return kcmdutil.UsageError(cmd, "You may not pass negative labels in selector %q", opts.Config.Selector) } opts.nodeSelector = valid } var portsErr error if opts.ports, portsErr = app.ContainerPortsFromString(opts.Config.Ports); portsErr != nil { return portsErr } var nsErr error if opts.namespace, _, nsErr = f.OpenShiftClientConfig.Namespace(); nsErr != nil { return fmt.Errorf("error getting namespace: %v", nsErr) } var kClientErr error if _, opts.serviceClient, kClientErr = f.Clients(); kClientErr != nil { return fmt.Errorf("error getting client: %v", kClientErr) } opts.Config.Action.Bulk.Mapper = clientcmd.ResourceMapper(f) opts.Config.Action.Out, opts.Config.Action.ErrOut = out, cmd.OutOrStderr() opts.Config.Action.Bulk.Op = configcmd.Create opts.out = out opts.cmd = cmd opts.factory = f return nil }
func runInit(cmd *cobra.Command, args []string) { db, err := bolt.Open(database, 0600, nil) if err != nil { fmt.Fprintf(cmd.OutOrStderr(), "Could not create database: %v\n", err) os.Exit(-1) } if err := db.Update(func(tx *bolt.Tx) error { if _, err := tx.CreateBucketIfNotExists([]byte("feeds")); err != nil { return fmt.Errorf("could not create feeds bucket: %v", err) } return nil }); err != nil { fmt.Fprintf(cmd.OutOrStderr(), "Could not initialize database: %v\n", err) os.Exit(-1) } }
func (options *NodeOptions) Run(c *cobra.Command, args []string) { kcmdutil.CheckErr(options.Complete()) kcmdutil.CheckErr(options.Validate(args)) startProfiler() if err := options.StartNode(); err != nil { if kerrors.IsInvalid(err) { if details := err.(*kerrors.StatusError).ErrStatus.Details; details != nil { fmt.Fprintf(c.OutOrStderr(), "Invalid %s %s\n", details.Kind, details.Name) for _, cause := range details.Causes { fmt.Fprintf(c.OutOrStderr(), " %s: %s\n", cause.Field, cause.Message) } os.Exit(255) } } glog.Fatal(err) } }
func runAdd(cmd *cobra.Command, args []string) { if feedName == "" { fail(cmd, "--name is required.") } if feedURL == "" { fail(cmd, "--url is required.") } db, err := bolt.Open(database, 0600, nil) if err != nil { fmt.Fprintf(cmd.OutOrStderr(), "Could not create database: %v\n", err) os.Exit(-1) } if err := db.Update(func(tx *bolt.Tx) error { b := tx.Bucket([]byte("feeds")) if b == nil { return fmt.Errorf("could not get feeds bucket (need to run `rss init`?)") } if b.Get([]byte(feedName)) != nil { return fmt.Errorf("feed %q already exists", feedName) } var buf bytes.Buffer feed := data.Feed{ Name: feedName, URL: feedURL, DayOfWeek: dayOfWeek, Seconds: seconds, } if err := gob.NewEncoder(&buf).Encode(feed); err != nil { return fmt.Errorf("error encoding feed configuration: %v", err) } if err := b.Put([]byte(feedName), buf.Bytes()); err != nil { return fmt.Errorf("error writing feed configuration: %v", err) } return nil }); err != nil { fmt.Fprintf(cmd.OutOrStderr(), "Could not add new feed: %v\n", err) os.Exit(-1) } }
func (o *StartBuildOptions) Complete(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, cmdFullName string, args []string) error { o.In = in o.Out = out o.ErrOut = cmd.OutOrStderr() o.Git = git.NewRepository() o.ClientConfig = f.OpenShiftClientConfig o.Mapper, _ = f.Object(false) webhook := o.FromWebhook buildName := o.FromBuild fromFile := o.FromFile fromDir := o.FromDir fromRepo := o.FromRepo buildLogLevel := o.LogLevel outputFormat := kcmdutil.GetFlagString(cmd, "output") if outputFormat != "name" && outputFormat != "" { return kcmdutil.UsageError(cmd, "Unsupported output format: %s", outputFormat) } o.ShortOutput = outputFormat == "name" switch { case len(webhook) > 0: if len(args) > 0 || len(buildName) > 0 || len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0 { return kcmdutil.UsageError(cmd, "The '--from-webhook' flag is incompatible with arguments and all '--from-*' flags") } return nil case len(args) != 1 && len(buildName) == 0: return kcmdutil.UsageError(cmd, "Must pass a name of a build config or specify build name with '--from-build' flag.\nUse \"%s get bc\" to list all available build configs.", cmdFullName) } if len(buildName) != 0 && (len(fromFile) != 0 || len(fromDir) != 0 || len(fromRepo) != 0) { // TODO: we should support this, it should be possible to clone a build to run again with new uploaded artifacts. // Doing so requires introducing a new clonebinary endpoint. return kcmdutil.UsageError(cmd, "Cannot use '--from-build' flag with binary builds") } o.AsBinary = len(fromFile) > 0 || len(fromDir) > 0 || len(fromRepo) > 0 namespace, _, err := f.DefaultNamespace() if err != nil { return err } client, _, err := f.Clients() if err != nil { return err } o.Client = client var ( name = buildName resource = buildapi.Resource("builds") ) if len(name) == 0 && len(args) > 0 && len(args[0]) > 0 { mapper, _ := f.Object(false) resource, name, err = cmdutil.ResolveResource(buildapi.Resource("buildconfigs"), args[0], mapper) if err != nil { return err } switch resource { case buildapi.Resource("buildconfigs"): // no special handling required case buildapi.Resource("builds"): if len(o.ListWebhooks) == 0 { return fmt.Errorf("use --from-build to rerun your builds") } default: return fmt.Errorf("invalid resource provided: %v", resource) } } // when listing webhooks, allow --from-build to lookup a build config if resource == buildapi.Resource("builds") && len(o.ListWebhooks) > 0 { build, err := client.Builds(namespace).Get(name) if err != nil { return err } ref := build.Status.Config if ref == nil { return fmt.Errorf("the provided Build %q was not created from a BuildConfig and cannot have webhooks", name) } if len(ref.Namespace) > 0 { namespace = ref.Namespace } name = ref.Name } if len(name) == 0 { return fmt.Errorf("a resource name is required either as an argument or by using --from-build") } o.Namespace = namespace o.Name = name env, _, err := cmdutil.ParseEnv(o.Env, in) if err != nil { return err } if len(buildLogLevel) > 0 { env = append(env, kapi.EnvVar{Name: "BUILD_LOGLEVEL", Value: buildLogLevel}) } o.EnvVar = env return nil }
// Complete completes all the required options. func (o *CancelBuildOptions) Complete(f *clientcmd.Factory, cmd *cobra.Command, args []string, in io.Reader, out io.Writer) error { o.In = in o.Out = out o.ErrOut = cmd.OutOrStderr() o.ReportError = func(err error) { o.HasError = true fmt.Fprintf(o.ErrOut, "error: %s\n", err.Error()) } if len(args) == 0 { return kcmdutil.UsageError(cmd, "Must pass a name of a build or a buildconfig to cancel") } namespace, _, err := f.DefaultNamespace() if err != nil { return err } if len(o.States) == 0 { // If --state is not specified, set the default to "new", "pending" and // "running". o.States = []string{"new", "pending", "running"} } else { for _, state := range o.States { if len(state) > 0 && !isStateCancellable(state) { return kcmdutil.UsageError(cmd, "The '--state' flag has invalid value. Must be one of 'new', 'pending', or 'running'") } } } client, _, err := f.Clients() if err != nil { return err } o.Namespace = namespace o.Client = client o.BuildLister = buildclient.NewOSClientBuildClient(client) o.BuildClient = client.Builds(namespace) o.Mapper, _ = f.Object(false) for _, item := range args { resource, name, err := cmdutil.ResolveResource(buildapi.Resource("builds"), item, o.Mapper) if err != nil { return err } switch resource { case buildapi.Resource("buildconfigs"): list, err := buildutil.BuildConfigBuilds(o.BuildLister, o.Namespace, name, nil) if err != nil { return err } for _, b := range list.Items { o.BuildNames = append(o.BuildNames, b.Name) } case buildapi.Resource("builds"): o.BuildNames = append(o.BuildNames, strings.TrimSpace(name)) default: return fmt.Errorf("invalid resource provided: %v", resource) } } return nil }
// RunCmdRouter contains all the necessary functionality for the // OpenShift CLI router command. func RunCmdRouter(f *clientcmd.Factory, cmd *cobra.Command, out io.Writer, cfg *RouterConfig, args []string) error { switch len(args) { case 0: // uses default value case 1: cfg.Name = args[0] default: return kcmdutil.UsageError(cmd, "You may pass zero or one arguments to provide a name for the router") } name := cfg.Name var defaultOutputErr error if len(cfg.StatsUsername) > 0 { if strings.Contains(cfg.StatsUsername, ":") { return kcmdutil.UsageError(cmd, "username %s must not contain ':'", cfg.StatsUsername) } } if len(cfg.Subdomain) > 0 && len(cfg.ForceSubdomain) > 0 { return kcmdutil.UsageError(cmd, "only one of --subdomain, --force-subdomain can be specified") } ports, err := app.ContainerPortsFromString(cfg.Ports) if err != nil { return fmt.Errorf("unable to parse --ports: %v", err) } // HostNetwork overrides HostPorts if cfg.HostNetwork { cfg.HostPorts = false } // For the host networking case, ensure the ports match. if cfg.HostNetwork { for i := 0; i < len(ports); i++ { if ports[i].HostPort != 0 && ports[i].ContainerPort != ports[i].HostPort { return fmt.Errorf("when using host networking mode, container port %d and host port %d must be equal", ports[i].ContainerPort, ports[i].HostPort) } } } if cfg.StatsPort > 0 { port := kapi.ContainerPort{ Name: "stats", ContainerPort: int32(cfg.StatsPort), Protocol: kapi.ProtocolTCP, } if cfg.HostPorts { port.HostPort = int32(cfg.StatsPort) } ports = append(ports, port) } label := map[string]string{"router": name} if cfg.Labels != defaultLabel { valid, remove, err := app.LabelsFromSpec(strings.Split(cfg.Labels, ",")) if err != nil { glog.Fatal(err) } if len(remove) > 0 { return kcmdutil.UsageError(cmd, "You may not pass negative labels in %q", cfg.Labels) } label = valid } nodeSelector := map[string]string{} if len(cfg.Selector) > 0 { valid, remove, err := app.LabelsFromSpec(strings.Split(cfg.Selector, ",")) if err != nil { glog.Fatal(err) } if len(remove) > 0 { return kcmdutil.UsageError(cmd, "You may not pass negative labels in selector %q", cfg.Selector) } nodeSelector = valid } image := cfg.ImageTemplate.ExpandOrDie(cfg.Type) namespace, _, err := f.OpenShiftClientConfig.Namespace() if err != nil { return fmt.Errorf("error getting client: %v", err) } _, kClient, err := f.Clients() if err != nil { return fmt.Errorf("error getting client: %v", err) } cfg.Action.Bulk.Mapper = clientcmd.ResourceMapper(f) cfg.Action.Out, cfg.Action.ErrOut = out, cmd.OutOrStderr() cfg.Action.Bulk.Op = configcmd.Create var clusterIP string output := cfg.Action.ShouldPrint() generate := output if !generate { service, err := kClient.Services(namespace).Get(name) if err != nil { if !errors.IsNotFound(err) { return fmt.Errorf("can't check for existing router %q: %v", name, err) } if !output && cfg.Action.DryRun { return fmt.Errorf("Router %q service does not exist", name) } generate = true } else { clusterIP = service.Spec.ClusterIP } } if !generate { fmt.Fprintf(out, "Router %q service exists\n", name) return nil } if len(cfg.ServiceAccount) == 0 { return fmt.Errorf("you must specify a service account for the router with --service-account") } if err := validateServiceAccount(kClient, namespace, cfg.ServiceAccount, cfg.HostNetwork, cfg.HostPorts); err != nil { err = fmt.Errorf("router could not be created; %v", err) if !cfg.Action.ShouldPrint() { return err } fmt.Fprintf(cmd.OutOrStderr(), "error: %v\n", err) defaultOutputErr = cmdutil.ErrExit } // create new router secretEnv := app.Environment{} switch { case len(cfg.Credentials) == 0 && len(cfg.ServiceAccount) == 0: return fmt.Errorf("router could not be created; you must specify a service account with --service-account, or a .kubeconfig file path containing credentials for connecting the router to the master with --credentials") case len(cfg.Credentials) > 0: clientConfigLoadingRules := &kclientcmd.ClientConfigLoadingRules{ExplicitPath: cfg.Credentials, Precedence: []string{}} credentials, err := clientConfigLoadingRules.Load() if err != nil { return fmt.Errorf("router could not be created; the provided credentials %q could not be loaded: %v", cfg.Credentials, err) } config, err := kclientcmd.NewDefaultClientConfig(*credentials, &kclientcmd.ConfigOverrides{}).ClientConfig() if err != nil { return fmt.Errorf("router could not be created; the provided credentials %q could not be used: %v", cfg.Credentials, err) } if err := restclient.LoadTLSFiles(config); err != nil { return fmt.Errorf("router could not be created; the provided credentials %q could not load certificate info: %v", cfg.Credentials, err) } insecure := "false" if config.Insecure { insecure = "true" } secretEnv.Add(app.Environment{ "OPENSHIFT_MASTER": config.Host, "OPENSHIFT_CA_DATA": string(config.CAData), "OPENSHIFT_KEY_DATA": string(config.KeyData), "OPENSHIFT_CERT_DATA": string(config.CertData), "OPENSHIFT_INSECURE": insecure, }) } createServiceAccount := len(cfg.ServiceAccount) > 0 && len(cfg.Credentials) == 0 defaultCert, err := fileutil.LoadData(cfg.DefaultCertificate) if err != nil { return fmt.Errorf("router could not be created; error reading default certificate file: %v", err) } if len(cfg.StatsPassword) == 0 { cfg.StatsPassword = generateStatsPassword() if !cfg.Action.ShouldPrint() { fmt.Fprintf(cmd.OutOrStderr(), "info: password for stats user %s has been set to %s\n", cfg.StatsUsername, cfg.StatsPassword) } } env := app.Environment{ "ROUTER_SUBDOMAIN": cfg.Subdomain, "ROUTER_SERVICE_NAME": name, "ROUTER_SERVICE_NAMESPACE": namespace, "ROUTER_SERVICE_HTTP_PORT": "80", "ROUTER_SERVICE_HTTPS_PORT": "443", "ROUTER_EXTERNAL_HOST_HOSTNAME": cfg.ExternalHost, "ROUTER_EXTERNAL_HOST_USERNAME": cfg.ExternalHostUsername, "ROUTER_EXTERNAL_HOST_PASSWORD": cfg.ExternalHostPassword, "ROUTER_EXTERNAL_HOST_HTTP_VSERVER": cfg.ExternalHostHttpVserver, "ROUTER_EXTERNAL_HOST_HTTPS_VSERVER": cfg.ExternalHostHttpsVserver, "ROUTER_EXTERNAL_HOST_INSECURE": strconv.FormatBool(cfg.ExternalHostInsecure), "ROUTER_EXTERNAL_HOST_PARTITION_PATH": cfg.ExternalHostPartitionPath, "ROUTER_EXTERNAL_HOST_PRIVKEY": privkeyPath, "STATS_PORT": strconv.Itoa(cfg.StatsPort), "STATS_USERNAME": cfg.StatsUsername, "STATS_PASSWORD": cfg.StatsPassword, } if len(cfg.ForceSubdomain) > 0 { env["ROUTER_SUBDOMAIN"] = cfg.ForceSubdomain env["ROUTER_OVERRIDE_HOSTNAME"] = "true" } env.Add(secretEnv) if len(defaultCert) > 0 { if cfg.SecretsAsEnv { env.Add(app.Environment{"DEFAULT_CERTIFICATE": string(defaultCert)}) } else { // TODO: make --credentials create secrets and bypass service account env.Add(app.Environment{"DEFAULT_CERTIFICATE_PATH": defaultCertificatePath}) } } secrets, volumes, mounts, err := generateSecretsConfig(cfg, kClient, namespace, defaultCert) if err != nil { return fmt.Errorf("router could not be created: %v", err) } livenessProbe := generateLivenessProbeConfig(cfg, ports) readinessProbe := generateReadinessProbeConfig(cfg, ports) exposedPorts := make([]kapi.ContainerPort, len(ports)) copy(exposedPorts, ports) if !cfg.HostPorts { for i := range exposedPorts { exposedPorts[i].HostPort = 0 } } containers := []kapi.Container{ { Name: "router", Image: image, Ports: exposedPorts, Env: env.List(), LivenessProbe: livenessProbe, ReadinessProbe: readinessProbe, ImagePullPolicy: kapi.PullIfNotPresent, VolumeMounts: mounts, Resources: kapi.ResourceRequirements{ Requests: kapi.ResourceList{ kapi.ResourceCPU: resource.MustParse("100m"), kapi.ResourceMemory: resource.MustParse("256Mi"), }, }, }, } if cfg.StatsPort > 0 && cfg.ExposeMetrics { pc := generateMetricsExporterContainer(cfg, env) if pc != nil { containers = append(containers, *pc) } } objects := []runtime.Object{} for _, s := range secrets { objects = append(objects, s) } if createServiceAccount { objects = append(objects, &kapi.ServiceAccount{ObjectMeta: kapi.ObjectMeta{Name: cfg.ServiceAccount}}, &authapi.ClusterRoleBinding{ ObjectMeta: kapi.ObjectMeta{Name: fmt.Sprintf("router-%s-role", cfg.Name)}, Subjects: []kapi.ObjectReference{ { Kind: "ServiceAccount", Name: cfg.ServiceAccount, Namespace: namespace, }, }, RoleRef: kapi.ObjectReference{ Kind: "ClusterRole", Name: "system:router", }, }, ) } updatePercent := int32(-25) objects = append(objects, &deployapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: name, Labels: label, }, Spec: deployapi.DeploymentConfigSpec{ Strategy: deployapi.DeploymentStrategy{ Type: deployapi.DeploymentStrategyTypeRolling, RollingParams: &deployapi.RollingDeploymentStrategyParams{UpdatePercent: &updatePercent}, }, Replicas: cfg.Replicas, Selector: label, Triggers: []deployapi.DeploymentTriggerPolicy{ {Type: deployapi.DeploymentTriggerOnConfigChange}, }, Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{Labels: label}, Spec: kapi.PodSpec{ SecurityContext: &kapi.PodSecurityContext{ HostNetwork: cfg.HostNetwork, }, ServiceAccountName: cfg.ServiceAccount, NodeSelector: nodeSelector, Containers: containers, Volumes: volumes, }, }, }, }) objects = app.AddServices(objects, false) // set the service port to the provided output port value for i := range objects { switch t := objects[i].(type) { case *kapi.Service: t.Spec.ClusterIP = clusterIP for j, servicePort := range t.Spec.Ports { for _, targetPort := range ports { if targetPort.ContainerPort == servicePort.Port && targetPort.HostPort != 0 { t.Spec.Ports[j].Port = targetPort.HostPort } } } } } // TODO: label all created objects with the same label - router=<name> list := &kapi.List{Items: objects} if cfg.Action.ShouldPrint() { mapper, _ := f.Object(false) fn := cmdutil.VersionedPrintObject(f.PrintObject, cmd, mapper, out) if err := fn(list); err != nil { return fmt.Errorf("unable to print object: %v", err) } return defaultOutputErr } if errs := cfg.Action.WithMessage(fmt.Sprintf("Creating router %s", cfg.Name), "created").Run(list, namespace); len(errs) > 0 { return cmdutil.ErrExit } return nil }
func fail(cmd *cobra.Command, msg string) { fmt.Fprintf(cmd.OutOrStderr(), "%s\n\n", msg) cmd.Usage() os.Exit(-1) }
// RunEnv contains all the necessary functionality for the OpenShift cli env command // TODO: refactor to share the common "patch resource" pattern of probe func RunEnv(f *clientcmd.Factory, in io.Reader, out io.Writer, cmd *cobra.Command, args []string, envParams, filenames []string) error { resources, envArgs, ok := cmdutil.SplitEnvironmentFromResources(args) if !ok { return kcmdutil.UsageError(cmd, "all resources must be specified before environment changes: %s", strings.Join(args, " ")) } if len(filenames) == 0 && len(resources) < 1 { return kcmdutil.UsageError(cmd, "one or more resources must be specified as <resource> <name> or <resource>/<name>") } containerMatch := kcmdutil.GetFlagString(cmd, "containers") list := kcmdutil.GetFlagBool(cmd, "list") resolve := kcmdutil.GetFlagBool(cmd, "resolve") selector := kcmdutil.GetFlagString(cmd, "selector") all := kcmdutil.GetFlagBool(cmd, "all") overwrite := kcmdutil.GetFlagBool(cmd, "overwrite") resourceVersion := kcmdutil.GetFlagString(cmd, "resource-version") outputFormat := kcmdutil.GetFlagString(cmd, "output") from := kcmdutil.GetFlagString(cmd, "from") prefix := kcmdutil.GetFlagString(cmd, "prefix") if list && len(outputFormat) > 0 { return kcmdutil.UsageError(cmd, "--list and --output may not be specified together") } clientConfig, err := f.ClientConfig() if err != nil { return err } cmdNamespace, explicit, err := f.DefaultNamespace() if err != nil { return err } env, remove, err := cmdutil.ParseEnv(append(envParams, envArgs...), in) if err != nil { return err } if len(from) != 0 { mapper, typer := f.Object(false) b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, false, filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, from). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } for _, info := range infos { switch from := info.Object.(type) { case *kapi.Secret: for key := range from.Data { envVar := kapi.EnvVar{ Name: keyToEnvName(key), ValueFrom: &kapi.EnvVarSource{ SecretKeyRef: &kapi.SecretKeySelector{ LocalObjectReference: kapi.LocalObjectReference{ Name: from.Name, }, Key: key, }, }, } env = append(env, envVar) } case *kapi.ConfigMap: for key := range from.Data { envVar := kapi.EnvVar{ Name: keyToEnvName(key), ValueFrom: &kapi.EnvVarSource{ ConfigMapKeyRef: &kapi.ConfigMapKeySelector{ LocalObjectReference: kapi.LocalObjectReference{ Name: from.Name, }, Key: key, }, }, } env = append(env, envVar) } default: return fmt.Errorf("unsupported resource specified in --from") } } } if len(prefix) != 0 { for i := range env { env[i].Name = fmt.Sprintf("%s%s", prefix, env[i].Name) } } mapper, typer := f.Object(false) b := resource.NewBuilder(mapper, typer, resource.ClientMapperFunc(f.ClientForMapping), kapi.Codecs.UniversalDecoder()). ContinueOnError(). NamespaceParam(cmdNamespace).DefaultNamespace(). FilenameParam(explicit, false, filenames...). SelectorParam(selector). ResourceTypeOrNameArgs(all, resources...). Flatten() one := false infos, err := b.Do().IntoSingular(&one).Infos() if err != nil { return err } // only apply resource version locking on a single resource if !one && len(resourceVersion) > 0 { return kcmdutil.UsageError(cmd, "--resource-version may only be used with a single resource") } // Keep a copy of the original objects prior to updating their environment. // Used in constructing the patch(es) that will be applied in the server. gv := *clientConfig.GroupVersion oldObjects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv)) if err != nil { return err } if len(oldObjects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } oldData := make([][]byte, len(infos)) for i := range oldObjects { old, err := json.Marshal(oldObjects[i]) if err != nil { return err } oldData[i] = old } skipped := 0 errored := []*resource.Info{} for _, info := range infos { ok, err := f.UpdatePodSpecForObject(info.Object, func(spec *kapi.PodSpec) error { resolutionErrorsEncountered := false containers, _ := selectContainers(spec.Containers, containerMatch) if len(containers) == 0 { fmt.Fprintf(cmd.OutOrStderr(), "warning: %s/%s does not have any containers matching %q\n", info.Mapping.Resource, info.Name, containerMatch) return nil } for _, c := range containers { if !overwrite { if err := validateNoOverwrites(c.Env, env); err != nil { errored = append(errored, info) return err } } c.Env = updateEnv(c.Env, env, remove) if list { resolveErrors := map[string][]string{} store := newResourceStore() fmt.Fprintf(out, "# %s %s, container %s\n", info.Mapping.Resource, info.Name, c.Name) for _, env := range c.Env { // Print the simple value if env.ValueFrom == nil { fmt.Fprintf(out, "%s=%s\n", env.Name, env.Value) continue } // Print the reference version if !resolve { fmt.Fprintf(out, "# %s from %s\n", env.Name, getEnvVarRefString(env.ValueFrom)) continue } value, err := getEnvVarRefValue(f, store, env.ValueFrom, info.Object, c) // Print the resolved value if err == nil { fmt.Fprintf(out, "%s=%s\n", env.Name, value) continue } // Print the reference version and save the resolve error fmt.Fprintf(out, "# %s from %s\n", env.Name, getEnvVarRefString(env.ValueFrom)) errString := err.Error() resolveErrors[errString] = append(resolveErrors[errString], env.Name) resolutionErrorsEncountered = true } // Print any resolution errors errs := []string{} for err, vars := range resolveErrors { sort.Strings(vars) errs = append(errs, fmt.Sprintf("error retrieving reference for %s: %v", strings.Join(vars, ", "), err)) } sort.Strings(errs) for _, err := range errs { fmt.Fprintln(cmd.OutOrStderr(), err) } } } if resolutionErrorsEncountered { errored = append(errored, info) return errors.New("failed to retrieve valueFrom references") } return nil }) if !ok { // This is a fallback function for objects that don't have pod spec. ok, err = f.UpdateObjectEnvironment(info.Object, func(vars *[]kapi.EnvVar) error { if vars == nil { return fmt.Errorf("no environment variables provided") } if !overwrite { if err := validateNoOverwrites(*vars, env); err != nil { errored = append(errored, info) return err } } *vars = updateEnv(*vars, env, remove) if list { fmt.Fprintf(out, "# %s %s\n", info.Mapping.Resource, info.Name) for _, env := range *vars { fmt.Fprintf(out, "%s=%s\n", env.Name, env.Value) } } return nil }) if !ok { skipped++ continue } } if err != nil { fmt.Fprintf(cmd.OutOrStderr(), "error: %s/%s %v\n", info.Mapping.Resource, info.Name, err) continue } } if one && skipped == len(infos) { return fmt.Errorf("%s/%s is not a pod or does not have a pod template", infos[0].Mapping.Resource, infos[0].Name) } if len(errored) == len(infos) { return cmdutil.ErrExit } if list { return nil } if len(outputFormat) != 0 { outputVersion, err := kcmdutil.OutputVersion(cmd, clientConfig.GroupVersion) if err != nil { return err } objects, err := resource.AsVersionedObjects(infos, outputVersion, kapi.Codecs.LegacyCodec(outputVersion)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", outputVersion) } p, _, err := kubectl.GetPrinter(outputFormat, "", false) if err != nil { return err } for _, object := range objects { if err := p.PrintObj(object, out); err != nil { return err } } return nil } objects, err := resource.AsVersionedObjects(infos, gv, kapi.Codecs.LegacyCodec(gv)) if err != nil { return err } if len(objects) != len(infos) { return fmt.Errorf("could not convert all objects to API version %q", clientConfig.GroupVersion) } failed := false updates: for i, info := range infos { for _, erroredInfo := range errored { if info == erroredInfo { continue updates } } newData, err := json.Marshal(objects[i]) if err != nil { return err } patchBytes, err := strategicpatch.CreateTwoWayMergePatch(oldData[i], newData, objects[i]) if err != nil { return err } obj, err := resource.NewHelper(info.Client, info.Mapping).Patch(info.Namespace, info.Name, kapi.StrategicMergePatchType, patchBytes) if err != nil { handlePodUpdateError(cmd.OutOrStderr(), err, "environment variables") failed = true continue } info.Refresh(obj, true) // make sure arguments to set or replace environment variables are set // before returning a successful message if len(env) == 0 && len(envArgs) == 0 { return fmt.Errorf("at least one environment variable must be provided") } shortOutput := kcmdutil.GetFlagString(cmd, "output") == "name" kcmdutil.PrintSuccess(mapper, shortOutput, out, info.Mapping.Resource, info.Name, "updated") } if failed { return cmdutil.ErrExit } return nil }