func RunWhoAmI(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, o *WhoAmIOptions) error { if kcmdutil.GetFlagBool(cmd, "token") { cfg, err := f.OpenShiftClientConfig.ClientConfig() if err != nil { return err } if len(cfg.BearerToken) == 0 { return fmt.Errorf("no token is currently in use for this session") } fmt.Fprintf(out, "%s\n", cfg.BearerToken) return nil } if kcmdutil.GetFlagBool(cmd, "context") { cfg, err := f.OpenShiftClientConfig.RawConfig() if err != nil { return err } if len(cfg.CurrentContext) == 0 { return fmt.Errorf("no context has been set") } fmt.Fprintf(out, "%s\n", cfg.CurrentContext) return nil } client, _, err := f.Clients() if err != nil { return err } o.UserInterface = client.Users() o.Out = out _, err = o.WhoAmI() return err }
// NewCmdWhoCan implements the OpenShift cli who-can command func NewCmdWhoCan(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { options := &whoCanOptions{} cmd := &cobra.Command{ Use: "who-can VERB RESOURCE", Short: "List who can perform the specified action on a resource", Long: "List who can perform the specified action on a resource", Run: func(cmd *cobra.Command, args []string) { if err := options.complete(args); err != nil { kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error())) } var err error if options.client, _, err = f.Clients(); err != nil { kcmdutil.CheckErr(err) } if options.bindingNamespace, err = f.DefaultNamespace(); err != nil { kcmdutil.CheckErr(err) } if err := options.run(); err != nil { kcmdutil.CheckErr(err) } }, } return cmd }
func setupAppConfig(f *clientcmd.Factory, c *cobra.Command, args []string, config *newcmd.AppConfig) error { namespace, err := f.DefaultNamespace() if err != nil { return err } dockerClient, _, err := dockerutil.NewHelper().GetClient() if err == nil { if err = dockerClient.Ping(); err == nil { config.SetDockerClient(dockerClient) } } if err != nil { glog.V(2).Infof("No local Docker daemon detected: %v", err) } osclient, _, err := f.Clients() if err != nil { return err } config.SetOpenShiftClient(osclient, namespace) unknown := config.AddArguments(args) if len(unknown) != 0 { return cmdutil.UsageError(c, "Did not recognize the following arguments: %v", unknown) } return nil }
func NewCmdRequestProject(name, fullName, oscLoginName, oscProjectName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { options := &NewProjectOptions{} options.Out = out cmd := &cobra.Command{ Use: fmt.Sprintf("%s NAME [--display-name=DISPLAYNAME] [--description=DESCRIPTION]", name), Short: "Request a new project", Long: fmt.Sprintf(requestProjectLong, oscLoginName, oscProjectName), Example: fmt.Sprintf(requestProjectExample, fullName), Run: func(cmd *cobra.Command, args []string) { if err := options.complete(cmd, f); err != nil { kcmdutil.CheckErr(err) } var err error if options.Client, _, err = f.Clients(); err != nil { kcmdutil.CheckErr(err) } if err := options.Run(); err != nil { kcmdutil.CheckErr(err) } }, } cmd.Flags().StringVar(&options.DisplayName, "display-name", "", "Project display name") cmd.Flags().StringVar(&options.Description, "description", "", "Project description") return cmd }
// NewCmdNewProject implements the OpenShift cli new-project command func NewCmdNewProject(name, fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { options := &NewProjectOptions{} cmd := &cobra.Command{ Use: name + " NAME [--display-name=DISPLAYNAME] [--description=DESCRIPTION]", Short: "Create a new project", Long: newProjectLong, Run: func(cmd *cobra.Command, args []string) { if err := options.complete(args); err != nil { kcmdutil.CheckErr(kcmdutil.UsageError(cmd, err.Error())) } var err error if options.Client, _, err = f.Clients(); err != nil { kcmdutil.CheckErr(err) } // We can't depend on len(options.NodeSelector) > 0 as node-selector="" is valid // and we want to populate node selector as project annotation only if explicitly set by user useNodeSelector := cmd.Flag("node-selector").Changed if err := options.Run(useNodeSelector); err != nil { kcmdutil.CheckErr(err) } }, } cmd.Flags().StringVar(&options.AdminRole, "admin-role", bootstrappolicy.AdminRoleName, "Project admin role name in the cluster policy") cmd.Flags().StringVar(&options.AdminUser, "admin", "", "Project admin username") cmd.Flags().StringVar(&options.DisplayName, "display-name", "", "Project display name") cmd.Flags().StringVar(&options.Description, "description", "", "Project description") cmd.Flags().StringVar(&options.NodeSelector, "node-selector", "", "Restrict pods onto nodes matching given label selector. Format: '<key1>=<value1>, <key2>=<value2>...'. Specifying \"\" means any node, not default. If unspecified, cluster default node selector will be used.") return cmd }
func (o *RoleModificationOptions) Complete(f *clientcmd.Factory, args []string, target *[]string, targetName string, isNamespaced bool) error { if len(args) < 2 { return fmt.Errorf("You must specify at least two arguments: <role> <%s> [%s]...", targetName, targetName) } o.RoleName = args[0] *target = append(*target, args[1:]...) osClient, _, err := f.Clients() if err != nil { return err } if isNamespaced { roleBindingNamespace, err := f.DefaultNamespace() if err != nil { return err } o.RoleBindingAccessor = NewLocalRoleBindingAccessor(roleBindingNamespace, osClient) } else { o.RoleBindingAccessor = NewClusterRoleBindingAccessor(osClient) } return nil }
func (o *ProjectOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { var err error argsLength := len(args) switch { case argsLength > 1: return errors.New("Only one argument is supported (project name or context name).") case argsLength == 1: o.ProjectName = args[0] } o.Config, err = f.OpenShiftClientConfig.RawConfig() if err != nil { return err } o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig() if err != nil { return err } o.Client, _, err = f.Clients() if err != nil { return err } o.Out = out return nil }
func (n *NodeOptions) Complete(f *clientcmd.Factory, c *cobra.Command, args []string, out io.Writer) error { defaultNamespace, err := f.DefaultNamespace() if err != nil { return err } _, kc, err := f.Clients() if err != nil { return err } cmdPrinter, output, err := kcmdutil.PrinterForCommand(c) if err != nil { return err } mapper, typer := f.Object() n.DefaultNamespace = defaultNamespace n.Kclient = kc n.Writer = out n.Mapper = mapper n.Typer = typer n.RESTClientFactory = f.Factory.RESTClient n.Printer = f.Printer n.NodeNames = []string{} n.CmdPrinter = cmdPrinter n.CmdPrinterOutput = false if output { n.CmdPrinterOutput = true } if len(args) != 0 { n.NodeNames = append(n.NodeNames, args...) } return nil }
// RunImportImage contains all the necessary functionality for the OpenShift cli import-image command. func RunImportImage(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) == 0 || len(args[0]) == 0 { return cmdutil.UsageError(cmd, "you must specify the name of an image stream.") } streamName := args[0] namespace, err := f.DefaultNamespace() if err != nil { return err } osClient, _, err := f.Clients() if err != nil { return err } imageStreamClient := osClient.ImageStreams(namespace) stream, err := imageStreamClient.Get(streamName) if err != nil { return err } if len(stream.Spec.DockerImageRepository) == 0 { return errors.New("only image streams with spec.dockerImageRepository set may have images imported") } if stream.Annotations == nil { stream.Annotations = make(map[string]string) } stream.Annotations[imageapi.DockerImageRepositoryCheckAnnotation] = "" updatedStream, err := imageStreamClient.Update(stream) if err != nil { return err } resourceVersion := updatedStream.ResourceVersion fmt.Fprintln(cmd.Out(), "Waiting for the import to complete, CTRL+C to stop waiting.") updatedStream, err = waitForImport(imageStreamClient, stream.Name, resourceVersion) if err != nil { return fmt.Errorf("unable to determine if the import completed successfully - please run 'oc describe -n %s imagestream/%s' to see if the tags were updated as expected: %v", stream.Namespace, stream.Name, err) } fmt.Fprintln(cmd.Out(), "The import completed successfully.\n") d := describe.ImageStreamDescriber{osClient} info, err := d.Describe(updatedStream.Namespace, updatedStream.Name) if err != nil { return err } fmt.Fprintln(out, info) return nil }
func (o *RemoveFromProjectOptions) Complete(f *clientcmd.Factory, args []string, target *[]string, targetName string) error { if len(args) < 1 { return fmt.Errorf("You must specify at least one argument: <%s> [%s]...", targetName, targetName) } *target = append(*target, args...) var err error if o.Client, _, err = f.Clients(); err != nil { return err } if o.BindingNamespace, err = f.DefaultNamespace(); err != nil { return err } return nil }
func (o *DeployOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { var err error o.osClient, o.kubeClient, err = f.Clients() if err != nil { return err } o.namespace, err = f.DefaultNamespace() if err != nil { return err } o.out = out if len(args) > 0 { o.deploymentConfigName = args[0] } return nil }
// RunBuildLogs contains all the necessary functionality for the OpenShift cli build-logs command func RunBuildLogs(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, opts api.BuildLogOptions, args []string) error { if len(args) != 1 { return cmdutil.UsageError(cmd, "A build name is required") } namespace, err := f.DefaultNamespace() if err != nil { return err } c, _, err := f.Clients() if err != nil { return err } readCloser, err := c.BuildLogs(namespace).Get(args[0], opts).Stream() if err != nil { return err } defer readCloser.Close() _, err = io.Copy(out, readCloser) return err }
// RunBuildChain contains all the necessary functionality for the OpenShift // experimental build-chain command func RunBuildChain(f *clientcmd.Factory, cmd *cobra.Command, args []string) error { all := cmdutil.GetFlagBool(cmd, "all") allTags := cmdutil.GetFlagBool(cmd, "all-tags") if len(args) > 1 || (len(args) == 1 && all) || (len(args) == 0 && allTags) || (all && allTags) { return cmdutil.UsageError(cmd, "Must pass nothing, an ImageStream name:tag combination, or specify the --all flag") } oc, _, err := f.Clients() if err != nil { return err } // Retrieve namespace(s) namespace := cmdutil.GetFlagString(cmd, "namespace") if len(namespace) == 0 { namespace, err = f.DefaultNamespace() if err != nil { return err } } namespaces := make([]string, 0) if all { projectList, err := oc.Projects().List(labels.Everything(), fields.Everything()) if err != nil { return err } for _, project := range projectList.Items { glog.V(4).Infof("Found namespace %s", project.Name) namespaces = append(namespaces, project.Name) } } if len(namespaces) == 0 { namespaces = append(namespaces, namespace) } // Get all build configurations buildConfigList := make([]buildapi.BuildConfig, 0) for _, namespace := range namespaces { cfgList, err := oc.BuildConfigs(namespace).List(labels.Everything(), fields.Everything()) if err != nil { return err } buildConfigList = append(buildConfigList, cfgList.Items...) } // Parse user input and validate specified image stream streams := make(map[string][]string) if !all && len(args) != 0 { name, specifiedTag, err := parseTag(args[0]) if err != nil { return err } // Validate the specified image stream is, err := oc.ImageStreams(namespace).Get(name) if err != nil { return err } stream := join(namespace, name) // Validate specified tag tags := make([]string, 0) exists := false for tag := range is.Status.Tags { tags = append(tags, tag) if specifiedTag == tag { exists = true } } if !exists && !allTags { // The specified tag isn't a part of our image stream return fmt.Errorf("no tag %s exists in %s", specifiedTag, stream) } else if !allTags { // Use only the specified tag tags = []string{specifiedTag} } // Set the specified stream as the only one to output dependencies for streams[stream] = tags } else { streams = getStreams(buildConfigList) } if len(streams) == 0 { return fmt.Errorf("no ImageStream available for building its dependency tree") } output := cmdutil.GetFlagString(cmd, "output") for stream, tags := range streams { for _, tag := range tags { glog.V(4).Infof("Checking dependencies of stream %s tag %s", stream, tag) root, err := findStreamDeps(stream, tag, buildConfigList) if err != nil { return err } // Check if the given image stream doesn't have any dependencies if treeSize(root) < 2 { glog.Infof("%s:%s has no dependencies\n", root.FullName, tag) continue } switch output { case "json": jsonDump, err := json.MarshalIndent(root, "", "\t") if err != nil { return err } fmt.Println(string(jsonDump)) case "dot": g := dot.NewGraph() _, name, err := split(stream) if err != nil { return err } graphName := validDOT(name) g.SetName(graphName) // Directed graph since we illustrate dependencies g.SetDir(true) // Explicitly allow multiple pairs of edges between // the same pair of nodes g.SetStrict(false) out, err := dotDump(root, g, graphName) if err != nil { return err } fmt.Println(out) case "ast": fmt.Println(root) default: return cmdutil.UsageError(cmd, "Wrong output format specified: %s", output) } } } 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 { var name string switch len(args) { case 0: name = "router" case 1: name = args[0] default: return cmdutil.UsageError(cmd, "You may pass zero or one arguments to provide a name for the router") } if len(cfg.StatsUsername) > 0 { if strings.Contains(cfg.StatsUsername, ":") { return cmdutil.UsageError(cmd, "username %s must not contain ':'", cfg.StatsUsername) } } ports, err := app.ContainerPortsFromString(cfg.Ports) if err != nil { glog.Fatal(err) } if cfg.StatsPort > 0 { ports = append(ports, kapi.ContainerPort{ Name: "stats", HostPort: cfg.StatsPort, ContainerPort: cfg.StatsPort, Protocol: kapi.ProtocolTCP, }) } 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 cmdutil.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 cmdutil.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) } p, output, err := cmdutil.PrinterForCommand(cmd) if err != nil { return fmt.Errorf("unable to configure printer: %v", err) } generate := output if !generate { _, 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) } generate = true } } if generate { if cfg.DryRun && !output { return fmt.Errorf("router %q does not exist (no service)", name) } // create new router if len(cfg.Credentials) == 0 { return fmt.Errorf("router could not be created; you must specify a .kubeconfig file path containing credentials for connecting the router to the master with --credentials") } 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 := kclient.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" } defaultCert, err := loadDefaultCert(cfg.DefaultCertificate) if err != nil { return fmt.Errorf("router could not be created; error reading default certificate file", err) } if len(cfg.StatsPassword) == 0 { cfg.StatsPassword = generateStatsPassword() fmt.Fprintf(out, "password for stats user %s has been set to %s\n", cfg.StatsUsername, cfg.StatsPassword) } env := 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, "DEFAULT_CERTIFICATE": defaultCert, "ROUTER_SERVICE_NAME": name, "ROUTER_SERVICE_NAMESPACE": namespace, "STATS_PORT": strconv.Itoa(cfg.StatsPort), "STATS_USERNAME": cfg.StatsUsername, "STATS_PASSWORD": cfg.StatsPassword, } objects := []runtime.Object{ &dapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: name, Labels: label, }, Triggers: []dapi.DeploymentTriggerPolicy{ {Type: dapi.DeploymentTriggerOnConfigChange}, }, Template: dapi.DeploymentTemplate{ ControllerTemplate: kapi.ReplicationControllerSpec{ Replicas: cfg.Replicas, Selector: label, Template: &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{Labels: label}, Spec: kapi.PodSpec{ ServiceAccount: cfg.ServiceAccount, NodeSelector: nodeSelector, Containers: []kapi.Container{ { Name: "router", Image: image, Ports: ports, Env: env.List(), LivenessProbe: &kapi.Probe{ Handler: kapi.Handler{ TCPSocket: &kapi.TCPSocketAction{ Port: kutil.IntOrString{ IntVal: ports[0].ContainerPort, }, }, }, InitialDelaySeconds: 10, }, ImagePullPolicy: kapi.PullIfNotPresent, }, }, }, }, }, }, }, } objects = app.AddServices(objects) // TODO: label all created objects with the same label - router=<name> list := &kapi.List{Items: objects} if output { if err := p.PrintObj(list, out); err != nil { return fmt.Errorf("Unable to print object: %v", err) } return nil } mapper, typer := f.Factory.Object() bulk := configcmd.Bulk{ Mapper: mapper, Typer: typer, RESTClientFactory: f.Factory.RESTClient, After: configcmd.NewPrintNameOrErrorAfter(out, os.Stderr), } if errs := bulk.Create(list, namespace); len(errs) != 0 { return errExit } return nil } fmt.Fprintf(out, "Router %q service exists\n", name) return nil }
// validate adds one layer of validation prior to calling the upstream // expose command. Used only for validating services that are about // to be exposed as routes. func validate(cmd *cobra.Command, f *clientcmd.Factory, args []string) error { if cmdutil.GetFlagString(cmd, "generator") != "route/v1" { if len(cmdutil.GetFlagString(cmd, "hostname")) > 0 { return fmt.Errorf("cannot use --hostname without generating a route") } return nil } if err := validateFlags(cmd); err != nil { return err } namespace, err := f.DefaultNamespace() if err != nil { return err } _, kc, err := f.Clients() if err != nil { return err } mapper, typer := f.Object() r := resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). ContinueOnError(). NamespaceParam(namespace).DefaultNamespace(). ResourceTypeOrNameArgs(false, args...). Flatten(). Do() err = r.Err() if err != nil { return err } mapping, err := r.ResourceMapping() if err != nil { return err } infos, err := r.Infos() if err != nil { return err } if len(infos) > 1 { return fmt.Errorf("multiple resources provided: %v", args) } info := infos[0] switch mapping.Kind { case "Service": svc, err := kc.Services(info.Namespace).Get(info.Name) if err != nil { return err } supportsTCP := false for _, port := range svc.Spec.Ports { if port.Protocol == kapi.ProtocolTCP { supportsTCP = true break } } if !supportsTCP { return fmt.Errorf("service %s doesn't support TCP", info.Name) } default: return fmt.Errorf("cannot expose a %s as a route", mapping.Kind) } return nil }
// RunCmdRegistry contains all the necessary functionality for the OpenShift cli registry command func RunCmdRegistry(f *clientcmd.Factory, cmd *cobra.Command, out io.Writer, cfg *RegistryConfig, args []string) error { var name string switch len(args) { case 0: name = "docker-registry" default: return cmdutil.UsageError(cmd, "No arguments are allowed to this command") } ports, err := app.ContainerPortsFromString(cfg.Ports) if err != nil { return err } label := map[string]string{ "docker-registry": "default", } if cfg.Labels != defaultLabel { valid, remove, err := app.LabelsFromSpec(strings.Split(cfg.Labels, ",")) if err != nil { return err } if len(remove) > 0 { return cmdutil.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 { return err } if len(remove) > 0 { return cmdutil.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) } p, output, err := cmdutil.PrinterForCommand(cmd) if err != nil { return fmt.Errorf("unable to configure printer: %v", err) } // Check if the specified service account already exists _, err = kClient.ServiceAccounts(namespace).Get(cfg.ServiceAccount) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("Unable to create the registry service account: can't check for existing service-account %q: %v", cfg.ServiceAccount, err) } generateServiceAccount := err != nil generate := output if !generate { _, err = kClient.Services(namespace).Get(name) if err != nil { if !errors.IsNotFound(err) { return fmt.Errorf("can't check for existing docker-registry %q: %v", name, err) } generate = true } } if generate { if cfg.DryRun && !output { return fmt.Errorf("docker-registry %q does not exist (no service).", name) } // create new registry if len(cfg.Credentials) == 0 { return fmt.Errorf("registry does not exist; you must specify a .kubeconfig file path containing credentials for connecting the registry to the master with --credentials") } clientConfigLoadingRules := &kclientcmd.ClientConfigLoadingRules{ExplicitPath: cfg.Credentials} credentials, err := clientConfigLoadingRules.Load() if err != nil { return fmt.Errorf("registry does not exist; 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("registry does not exist; the provided credentials %q could not be used: %v", cfg.Credentials, err) } if err := kclient.LoadTLSFiles(config); err != nil { return fmt.Errorf("registry does not exist; the provided credentials %q could not load certificate info: %v", cfg.Credentials, err) } insecure := "false" if config.Insecure { insecure = "true" } else { if len(config.KeyData) == 0 || len(config.CertData) == 0 { return fmt.Errorf("registry does not exist; the provided credentials %q are missing the client certificate and/or key", cfg.Credentials) } } env := 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, } mountHost := len(cfg.HostMount) > 0 podTemplate := &kapi.PodTemplateSpec{ ObjectMeta: kapi.ObjectMeta{Labels: label}, Spec: kapi.PodSpec{ ServiceAccount: cfg.ServiceAccount, NodeSelector: nodeSelector, Containers: []kapi.Container{ { Name: "registry", Image: image, Ports: ports, Env: env.List(), VolumeMounts: []kapi.VolumeMount{ { Name: "registry-storage", MountPath: cfg.Volume, }, }, SecurityContext: &kapi.SecurityContext{ Privileged: &mountHost, }, // TODO reenable the liveness probe when we no longer support the v1 registry. /* LivenessProbe: &kapi.Probe{ InitialDelaySeconds: 3, TimeoutSeconds: 5, Handler: kapi.Handler{ HTTPGet: &kapi.HTTPGetAction{ Path: "/healthz", Port: util.NewIntOrStringFromInt(5000), }, }, }, */ }, }, Volumes: []kapi.Volume{ { Name: "registry-storage", VolumeSource: kapi.VolumeSource{}, }, }, }, } if mountHost { podTemplate.Spec.Volumes[0].HostPath = &kapi.HostPathVolumeSource{Path: cfg.HostMount} } else { podTemplate.Spec.Volumes[0].EmptyDir = &kapi.EmptyDirVolumeSource{} } objects := []runtime.Object{ &dapi.DeploymentConfig{ ObjectMeta: kapi.ObjectMeta{ Name: name, Labels: label, }, Triggers: []dapi.DeploymentTriggerPolicy{ {Type: dapi.DeploymentTriggerOnConfigChange}, }, Template: dapi.DeploymentTemplate{ ControllerTemplate: kapi.ReplicationControllerSpec{ Replicas: cfg.Replicas, Selector: label, Template: podTemplate, }, }, }, } objects = app.AddServices(objects) if generateServiceAccount { // Add the new service account to "privileged" scc, err := kClient.SecurityContextConstraints().Get("privileged") if err != nil { return fmt.Errorf("Unable to create the registry service account: can't check for existing security context constraints privileged: %v", err) } userName := "******" + namespace + ":" + cfg.ServiceAccount inList := false for _, u := range scc.Users { if u == userName { inList = true break } } if !inList { scc.Users = append(scc.Users, userName) _, err = kClient.SecurityContextConstraints().Update(scc) if err != nil && !errors.IsNotFound(err) { return fmt.Errorf("error updating security context constraints: %v", err) } } // Create the service account before anything else objects = append([]runtime.Object{&kapi.ServiceAccount{ObjectMeta: kapi.ObjectMeta{Name: cfg.ServiceAccount}}}, objects...) } // TODO: label all created objects with the same label list := &kapi.List{Items: objects} if output { if err := p.PrintObj(list, out); err != nil { return fmt.Errorf("unable to print object: %v", err) } return nil } mapper, typer := f.Factory.Object() bulk := configcmd.Bulk{ Mapper: mapper, Typer: typer, RESTClientFactory: f.Factory.RESTClient, After: configcmd.NewPrintNameOrErrorAfter(out, os.Stderr), } if errs := bulk.Create(list, namespace); len(errs) != 0 { return errExit } return nil } fmt.Fprintf(out, "Docker registry %q service exists\n", name) return nil }
// RunCancelBuild contains all the necessary functionality for the OpenShift cli cancel-build command func RunCancelBuild(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { if len(args) == 0 || len(args[0]) == 0 { return cmdutil.UsageError(cmd, "You must specify the name of a build to cancel.") } buildName := args[0] namespace, err := f.DefaultNamespace() if err != nil { return err } client, _, err := f.Clients() if err != nil { return err } buildClient := client.Builds(namespace) build, err := buildClient.Get(buildName) if err != nil { return err } if !isBuildCancellable(build) { return nil } // Print build logs before cancelling build. if cmdutil.GetFlagBool(cmd, "dump-logs") { opts := buildapi.BuildLogOptions{ NoWait: true, Follow: false, } response, err := client.BuildLogs(namespace).Get(buildName, opts).Do().Raw() if err != nil { glog.Errorf("Could not fetch build logs for %s: %v", buildName, err) } else { glog.Infof("Build logs for %s:\n%v", buildName, string(response)) } } // Mark build to be cancelled. for { build.Cancelled = true if _, err = buildClient.Update(build); err != nil && errors.IsConflict(err) { build, err = buildClient.Get(buildName) if err != nil { return err } continue } if err != nil { return err } break } glog.V(2).Infof("Build %s was cancelled.", buildName) // Create a new build with the same configuration. if cmdutil.GetFlagBool(cmd, "restart") { request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: build.Name}, } newBuild, err := client.Builds(namespace).Clone(request) if err != nil { return err } glog.V(2).Infof("Restarted build %s.", buildName) fmt.Fprintf(out, "%s\n", newBuild.Name) } else { fmt.Fprintf(out, "%s\n", build.Name) } return nil }
func getClients(f *clientcmd.Factory, cfg *pruneImagesConfig) (*client.Client, *kclient.Client, *http.Client, error) { clientConfig, err := f.OpenShiftClientConfig.ClientConfig() if err != nil { return nil, nil, nil, err } var ( token string osClient *client.Client kClient *kclient.Client registryClient *http.Client ) switch { case len(clientConfig.BearerToken) > 0: osClient, kClient, err = f.Clients() if err != nil { return nil, nil, nil, err } token = clientConfig.BearerToken default: err = errors.New("You must use a client config with a token") return nil, nil, nil, err } // copy the config registryClientConfig := *clientConfig // zero out everything we don't want to use registryClientConfig.BearerToken = "" registryClientConfig.CertFile = "" registryClientConfig.CertData = []byte{} registryClientConfig.KeyFile = "" registryClientConfig.KeyData = []byte{} // we have to set a username to something for the Docker login // but it's not actually used registryClientConfig.Username = "******" // set the "password" to be the token registryClientConfig.Password = token tlsConfig, err := kclient.TLSConfigFor(®istryClientConfig) if err != nil { return nil, nil, nil, err } // if the user specified a CA on the command line, add it to the // client config's CA roots if len(cfg.CABundle) > 0 { data, err := ioutil.ReadFile(cfg.CABundle) if err != nil { return nil, nil, nil, err } if tlsConfig.RootCAs == nil { tlsConfig.RootCAs = x509.NewCertPool() } tlsConfig.RootCAs.AppendCertsFromPEM(data) } transport := http.Transport{ TLSClientConfig: tlsConfig, } wrappedTransport, err := kclient.HTTPWrappersForConfig(®istryClientConfig, &transport) if err != nil { return nil, nil, nil, err } registryClient = &http.Client{ Transport: wrappedTransport, } return osClient, kClient, registryClient, nil }
// RunListBuildWebHooks prints the webhooks for the provided build config. func RunListBuildWebHooks(f *clientcmd.Factory, out, errOut io.Writer, name string, isBuild bool, webhookFilter string) error { generic, github := false, false prefix := false switch webhookFilter { case "all": generic, github = true, true prefix = true case "generic": generic = true case "github": github = true default: return fmt.Errorf("--list-webhooks must be 'all', 'generic', or 'github'") } client, _, err := f.Clients() if err != nil { return err } namespace, err := f.DefaultNamespace() if err != nil { return err } if isBuild { build, err := client.Builds(namespace).Get(name) if err != nil { return err } ref := build.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 } config, err := client.BuildConfigs(namespace).Get(name) if err != nil { return err } for _, t := range config.Triggers { hookType := "" switch { case t.GenericWebHook != nil && generic: if prefix { hookType = "generic " } case t.GitHubWebHook != nil && github: if prefix { hookType = "github " } default: continue } url, err := client.BuildConfigs(namespace).WebHookURL(name, &t) if err != nil { if err != osclient.ErrTriggerIsNotAWebHook { fmt.Fprintf(errOut, "error: unable to get webhook for %s: %v", name, err) } continue } fmt.Fprintf(out, "%s%s\n", hookType, url.String()) } return nil }
// RunStartBuild contains all the necessary functionality for the OpenShift cli start-build command func RunStartBuild(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, webhooks util.StringFlag) error { webhook := cmdutil.GetFlagString(cmd, "from-webhook") buildName := cmdutil.GetFlagString(cmd, "from-build") follow := cmdutil.GetFlagBool(cmd, "follow") switch { case len(webhook) > 0: if len(args) > 0 || len(buildName) > 0 { return cmdutil.UsageError(cmd, "The '--from-webhook' flag is incompatible with arguments or '--from-build'") } path := cmdutil.GetFlagString(cmd, "git-repository") postReceivePath := cmdutil.GetFlagString(cmd, "git-post-receive") repo := git.NewRepository() return RunStartBuildWebHook(f, out, webhook, path, postReceivePath, repo) case len(args) != 1 && len(buildName) == 0: return cmdutil.UsageError(cmd, "Must pass a name of a BuildConfig or specify build name with '--from-build' flag") } name := buildName isBuild := true if len(name) == 0 { name = args[0] isBuild = false } if webhooks.Provided() { return RunListBuildWebHooks(f, out, cmd.Out(), name, isBuild, webhooks.String()) } client, _, err := f.Clients() if err != nil { return err } namespace, err := f.DefaultNamespace() if err != nil { return err } request := &buildapi.BuildRequest{ ObjectMeta: kapi.ObjectMeta{Name: name}, } var newBuild *buildapi.Build if isBuild { if newBuild, err = client.Builds(namespace).Clone(request); err != nil { return err } } else { if newBuild, err = client.BuildConfigs(namespace).Instantiate(request); err != nil { return err } } fmt.Fprintf(out, "%s\n", newBuild.Name) if follow { opts := buildapi.BuildLogOptions{ Follow: true, NoWait: false, } rd, err := client.BuildLogs(namespace).Get(newBuild.Name, opts).Stream() if err != nil { return fmt.Errorf("error getting logs: %v", err) } defer rd.Close() _, err = io.Copy(out, rd) if err != nil { return fmt.Errorf("error streaming logs: %v", err) } } return nil }
// NewCmdRollback creates a CLI rollback command. func NewCmdRollback(fullName string, f *clientcmd.Factory, out io.Writer) *cobra.Command { rollback := &deployapi.DeploymentConfigRollback{ Spec: deployapi.DeploymentConfigRollbackSpec{ IncludeTemplate: true, }, } cmd := &cobra.Command{ Use: "rollback DEPLOYMENT", Short: "Revert part of an application back to a previous deployment", Long: rollbackLong, Example: fmt.Sprintf(rollbackExample, fullName), Run: func(cmd *cobra.Command, args []string) { // Validate arguments if len(args) == 0 || len(args[0]) == 0 { cmdutil.CheckErr(cmdutil.UsageError(cmd, "A deployment name is required.")) } // Extract arguments format := cmdutil.GetFlagString(cmd, "output") template := cmdutil.GetFlagString(cmd, "template") dryRun := cmdutil.GetFlagBool(cmd, "dry-run") // Get globally provided stuff namespace, err := f.DefaultNamespace() cmdutil.CheckErr(err) oClient, kClient, err := f.Clients() cmdutil.CheckErr(err) // Set up the rollback config rollback.Spec.From.Name = args[0] // Make a helper and generate a rolled back config helper := newHelper(oClient, kClient) config, err := helper.Generate(namespace, rollback) cmdutil.CheckErr(err) // If this is a dry run, print and exit if dryRun { err := helper.Describe(config, out) cmdutil.CheckErr(err) return } // If an output format is specified, print and exit if len(format) > 0 { err := helper.Print(config, format, template, out) cmdutil.CheckErr(err) return } // Perform the rollback rolledback, err := helper.Update(config) cmdutil.CheckErr(err) // Notify the user of any disabled image triggers fmt.Fprintf(out, "#%d rolled back to %s\n", rolledback.LatestVersion, rollback.Spec.From.Name) for _, trigger := range rolledback.Triggers { disabled := []string{} if trigger.Type == deployapi.DeploymentTriggerOnImageChange && !trigger.ImageChangeParams.Automatic { disabled = append(disabled, trigger.ImageChangeParams.From.Name) } if len(disabled) > 0 { reenable := fmt.Sprintf("%s deploy %s --enable-triggers", fullName, rolledback.Name) fmt.Fprintf(cmd.Out(), "Warning: the following images triggers were disabled: %s\n You can re-enable them with: %s\n", strings.Join(disabled, ","), reenable) } } }, } cmd.Flags().BoolVar(&rollback.Spec.IncludeTriggers, "change-triggers", false, "Include the previous deployment's triggers in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeStrategy, "change-strategy", false, "Include the previous deployment's strategy in the rollback") cmd.Flags().BoolVar(&rollback.Spec.IncludeReplicationMeta, "change-scaling-settings", false, "Include the previous deployment's replicationController replica count and selector in the rollback") cmd.Flags().BoolP("dry-run", "d", false, "Instead of performing the rollback, describe what the rollback will look like in human-readable form") cmd.Flags().StringP("output", "o", "", "Instead of performing the rollback, print the updated deployment configuration in the specified format (json|yaml|template|templatefile)") cmd.Flags().StringP("template", "t", "", "Template string or path to template file to use when -o=template or -o=templatefile.") return cmd }
func NewCmdPruneBuilds(f *clientcmd.Factory, parentName, name string, out io.Writer) *cobra.Command { cfg := &pruneBuildsConfig{ Confirm: false, KeepYoungerThan: 60 * time.Minute, Orphans: false, KeepComplete: 5, KeepFailed: 1, } cmd := &cobra.Command{ Use: name, Short: "Remove completed and failed builds", Long: fmt.Sprintf(buildsLongDesc, parentName, name), Run: func(cmd *cobra.Command, args []string) { if len(args) > 0 { glog.Fatalf("No arguments are allowed to this command") } osClient, _, err := f.Clients() if err != nil { cmdutil.CheckErr(err) } buildConfigList, err := osClient.BuildConfigs(kapi.NamespaceAll).List(labels.Everything(), fields.Everything()) if err != nil { cmdutil.CheckErr(err) } buildList, err := osClient.Builds(kapi.NamespaceAll).List(labels.Everything(), fields.Everything()) if err != nil { cmdutil.CheckErr(err) } buildConfigs := []*buildapi.BuildConfig{} for i := range buildConfigList.Items { buildConfigs = append(buildConfigs, &buildConfigList.Items[i]) } builds := []*buildapi.Build{} for i := range buildList.Items { builds = append(builds, &buildList.Items[i]) } var buildPruneFunc prune.PruneFunc w := tabwriter.NewWriter(out, 10, 4, 3, ' ', 0) defer w.Flush() describingPruneBuildFunc := func(build *buildapi.Build) error { fmt.Fprintf(w, "%s\t%s\n", build.Namespace, build.Name) return nil } switch cfg.Confirm { case true: buildPruneFunc = func(build *buildapi.Build) error { describingPruneBuildFunc(build) err := osClient.Builds(build.Namespace).Delete(build.Name) if err != nil { return err } return nil } default: fmt.Fprintln(os.Stderr, "Dry run enabled - no modifications will be made.") buildPruneFunc = describingPruneBuildFunc } fmt.Fprintln(w, "NAMESPACE\tNAME") pruneTask := prune.NewPruneTasker(buildConfigs, builds, cfg.KeepYoungerThan, cfg.Orphans, cfg.KeepComplete, cfg.KeepFailed, buildPruneFunc) err = pruneTask.PruneTask() if err != nil { cmdutil.CheckErr(err) } }, } cmd.Flags().BoolVar(&cfg.Confirm, "confirm", cfg.Confirm, "Specify that build pruning should proceed. Defaults to false, displaying what would be deleted but not actually deleting anything.") cmd.Flags().BoolVar(&cfg.Orphans, "orphans", cfg.Orphans, "Prune all builds whose associated BuildConfig no longer exists and whose status is complete, failed, error, or canceled.") cmd.Flags().DurationVar(&cfg.KeepYoungerThan, "keep-younger-than", cfg.KeepYoungerThan, "Specify the minimum age of a Build for it to be considered a candidate for pruning.") cmd.Flags().IntVar(&cfg.KeepComplete, "keep-complete", cfg.KeepComplete, "Per BuildConfig, specify the number of builds whose status is complete that will be preserved.") cmd.Flags().IntVar(&cfg.KeepFailed, "keep-failed", cfg.KeepFailed, "Per BuildConfig, specify the number of builds whose status is failed, error, or canceled that will be preserved.") return cmd }
// RunProject contains all the necessary functionality for the OpenShift cli process command func RunProcess(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { storedTemplate := "" if len(args) > 0 { storedTemplate = args[0] } filename := kcmdutil.GetFlagString(cmd, "filename") if len(storedTemplate) == 0 && len(filename) == 0 { return kcmdutil.UsageError(cmd, "Must pass a filename or name of stored template") } namespace, err := f.DefaultNamespace() if err != nil { return err } mapper, typer := f.Object() client, _, err := f.Clients() if err != nil { return err } var ( objects []runtime.Object infos []*resource.Info mapping *meta.RESTMapping ) version, kind, err := mapper.VersionAndKindForResource("template") if mapping, err = mapper.RESTMapping(kind, version); err != nil { return err } // When storedTemplate is not empty, then we fetch the template from the // server, otherwise we require to set the `-f` parameter. if len(storedTemplate) > 0 { templateObj, err := client.Templates(namespace).Get(storedTemplate) if err != nil { if errors.IsNotFound(err) { return fmt.Errorf("template %q could not be found", storedTemplate) } return err } templateObj.CreationTimestamp = util.Now() infos = append(infos, &resource.Info{Object: templateObj}) } else { infos, err = resource.NewBuilder(mapper, typer, f.ClientMapperForCommand()). NamespaceParam(namespace).RequireNamespace(). FilenameParam(filename). Do(). Infos() if err != nil { return err } } outputFormat := kcmdutil.GetFlagString(cmd, "output") for i := range infos { obj, ok := infos[i].Object.(*api.Template) if !ok { sourceName := filename if len(storedTemplate) > 0 { sourceName = namespace + "/" + storedTemplate } fmt.Fprintf(cmd.Out(), "unable to parse %q, not a valid Template but %s\n", sourceName, reflect.TypeOf(infos[i].Object)) continue } // If 'parameters' flag is set it does not do processing but only print // the template parameters to console for inspection. // If multiple templates are passed, this will print combined output for all // templates. if kcmdutil.GetFlagBool(cmd, "parameters") { if len(infos) > 1 { fmt.Fprintf(out, "\n%s:\n", obj.Name) } if err := describe.PrintTemplateParameters(obj.Parameters, out); err != nil { fmt.Fprintf(cmd.Out(), "error printing parameters for %q: %v\n", obj.Name, err) } continue } if label := kcmdutil.GetFlagString(cmd, "labels"); len(label) > 0 { lbl, err := kubectl.ParseLabels(label) if err != nil { fmt.Fprintf(cmd.Out(), "error parsing labels: %v\n", err) continue } if obj.ObjectLabels == nil { obj.ObjectLabels = make(map[string]string) } for key, value := range lbl { obj.ObjectLabels[key] = value } } // Override the values for the current template parameters // when user specify the --value if cmd.Flag("value").Changed { injectUserVars(cmd, obj) } resultObj, err := client.TemplateConfigs(namespace).Create(obj) if err != nil { fmt.Fprintf(cmd.Out(), "error processing the template %q: %v\n", obj.Name, err) continue } if outputFormat == "describe" { if s, err := (&describe.TemplateDescriber{ MetadataAccessor: meta.NewAccessor(), ObjectTyper: kapi.Scheme, ObjectDescriber: nil, }).DescribeTemplate(resultObj); err != nil { fmt.Fprintf(cmd.Out(), "error describing %q: %v\n", obj.Name, err) } else { fmt.Fprintf(out, s) } continue } objects = append(objects, resultObj.Objects...) } // Do not print the processed templates when asked to only show parameters or // describe. if kcmdutil.GetFlagBool(cmd, "parameters") || outputFormat == "describe" { return nil } p, _, err := kubectl.GetPrinter(outputFormat, "") if err != nil { return err } p = kubectl.NewVersionedPrinter(p, kapi.Scheme, kcmdutil.OutputVersion(cmd, mapping.APIVersion)) // use generic output if kcmdutil.GetFlagBool(cmd, "raw") { for i := range objects { p.PrintObj(objects[i], out) } return nil } return p.PrintObj(&kapi.List{ ListMeta: kapi.ListMeta{}, Items: objects, }, out) }
// RunTag contains all the necessary functionality for the OpenShift cli tag command. func RunTag(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string, sourceKind string) error { if len(args) < 2 { return cmdutil.UsageError(cmd, "you must specify a source and at least one destination") } original := sourceKind if len(sourceKind) > 0 { sourceKind = determineSourceKind(f, sourceKind) } if len(sourceKind) > 0 { validSources := util.NewStringSet("imagestreamtag", "istag", "imagestreamimage", "isimage", "docker", "dockerimage") if !validSources.Has(strings.ToLower(sourceKind)) { cmdutil.CheckErr(cmdutil.UsageError(cmd, "invalid source %q; valid values are %v", original, strings.Join(validSources.List(), ", "))) } } namespace, err := f.DefaultNamespace() if err != nil { return err } sourceNamespace, sourceNameAndRef, err := parseStreamName(args[0], namespace) if err != nil { return err } osClient, _, err := f.Clients() if err != nil { return err } if len(sourceKind) == 0 { if sourceName, sourceTag, ok := imageapi.SplitImageStreamTag(sourceNameAndRef); ok { if _, err := osClient.ImageStreamTags(sourceNamespace).Get(sourceName, sourceTag); err == nil { sourceKind = "ImageStreamTag" } } } if len(sourceKind) == 0 { if sourceName, sourceID, err := imagestreamimage.ParseNameAndID(sourceNameAndRef); err == nil { if _, err := osClient.ImageStreamImages(sourceNamespace).Get(sourceName, sourceID); err == nil { sourceKind = "ImageStreamImage" } } } if len(sourceKind) == 0 { sourceKind = "DockerImage" } for _, arg := range args[1:] { destNamespace, destNameAndTag, err := parseStreamName(arg, namespace) if err != nil { return err } destName, destTag, ok := imageapi.SplitImageStreamTag(destNameAndTag) if !ok { return fmt.Errorf("%q must be of the form <namespace>/<stream name>:<tag>", arg) } isc := osClient.ImageStreams(destNamespace) target, err := isc.Get(destName) if err != nil { if !kerrors.IsNotFound(err) { return err } // try to create the target if it doesn't exist target = &imageapi.ImageStream{ ObjectMeta: kapi.ObjectMeta{ Name: destName, }, } target, err = isc.Create(target) if err != nil { return nil } } if target.Spec.Tags == nil { target.Spec.Tags = make(map[string]imageapi.TagReference) } targetRef, ok := target.Spec.Tags[destTag] if !ok { targetRef = imageapi.TagReference{} } targetRef.From = &kapi.ObjectReference{ Kind: sourceKind, } switch sourceKind { case "DockerImage": targetRef.From.Name = args[0] default: targetRef.From.Namespace = sourceNamespace targetRef.From.Name = sourceNameAndRef } target.Spec.Tags[destTag] = targetRef if _, err = isc.Update(target); err != nil { return err } } return nil }