diff --git a/examples/sample-app/README.md b/examples/sample-app/README.md index c4274395fe10..4b41ad6faf8f 100644 --- a/examples/sample-app/README.md +++ b/examples/sample-app/README.md @@ -122,24 +122,26 @@ This section covers how to perform all the steps of building, deploying, and upd need to accept the server certificates and present its own client certificate. These are generated as part of the `openshift start` command in whatever the current directory is at the time. You will - need to point osc and curl at the appropriate .kubeconfig in order + need to point osc and curl at the appropriate certificates in order to connect to OpenShift. Assuming you are running as a user other than root, you will also need to make the .kubeconfig readable by that user. (Note: this is just for example purposes; in a real installation, users would generate their own keys and not have access to the system keys.) - $ export OPENSHIFTCONFIG=`pwd`/openshift.local.certificates/admin/.kubeconfig $ export CURL_CA_BUNDLE=`pwd`/openshift.local.certificates/ca/cert.crt - $ sudo chmod a+rwX "$OPENSHIFTCONFIG" + $ sudo chmod a+rwX `pwd`/openshift.local.certificates/admin/.kubeconfig 4. Bind a user names `test-admin` to the `view` role in the default namespace so you can observe progress in the web console - $ openshift ex policy add-role-to-user view test-admin + $ osadm policy add-role-to-user view test-admin --config=openshift.local.certificates/admin/.kubeconfig +5. Login as `test-admin` using any password + $ osc login --certificate-authority=`pwd`/openshift.local.certificates/ca/cert.crt -5. *Optional:* View the OpenShift web console in your browser by browsing to `https://:8443/console`. Login using the user `test-admin` and any password. + +6. *Optional:* View the OpenShift web console in your browser by browsing to `https://:8443/console`. Login using the user `test-admin` and any password. * You will need to have the browser accept the certificate at `https://:8443` before the console can consult the OpenShift @@ -150,10 +152,10 @@ This section covers how to perform all the steps of building, deploying, and upd and run builds. -6. Deploy a private docker registry within OpenShift with the certs necessary for access to master: +7. Deploy a private docker registry within OpenShift with the certs necessary for access to master: $ sudo chmod +r ./openshift.local.certificates/openshift-registry/.kubeconfig - $ openshift ex registry --create --credentials=./openshift.local.certificates/openshift-registry/.kubeconfig + $ openshift ex registry --create --credentials=./openshift.local.certificates/openshift-registry/.kubeconfig --config=openshift.local.certificates/admin/.kubeconfig docker-registry # the service docker-registry # the deployment config @@ -163,7 +165,7 @@ This section covers how to perform all the steps of building, deploying, and upd of this tutorial. -7. Confirm the registry is started (this can take a few minutes): +8. Confirm the registry is started (this can take a few minutes): $ osc describe service docker-registry @@ -181,7 +183,7 @@ This section covers how to perform all the steps of building, deploying, and upd be added to the docker-registry service list so that it's reachable from other places. -8. Confirm the registry is accessible (you may need to run this more than once): +9. Confirm the registry is accessible (you may need to run this more than once): $ curl `osc get service docker-registry --template="{{ .spec.portalIP }}:{{ with index .spec.ports 0 }}{{ .port }}{{ end }}"` @@ -190,12 +192,12 @@ This section covers how to perform all the steps of building, deploying, and upd "docker-registry server (dev) (v0.9.0)" -9. Create a new project in OpenShift. This creates a namespace `test` to contain the builds and app that we will generate below. +10. Create a new project in OpenShift. This creates a namespace `test` to contain the builds and app that we will generate below. - $ openshift ex new-project test --display-name="OpenShift 3 Sample" --description="This is an example project to demonstrate OpenShift v3" --admin=test-admin + $ osc new-project test --display-name="OpenShift 3 Sample" --description="This is an example project to demonstrate OpenShift v3" -10. *Optional:* View the OpenShift web console in your browser by browsing to `https://:8443/console`. Login using the user `test-admin` and any password. +11. *Optional:* View the OpenShift web console in your browser by browsing to `https://:8443/console`. Login using the user `test-admin` and any password. * You will need to have the browser accept the certificate at `https://:8443` before the console can consult the OpenShift @@ -206,7 +208,7 @@ This section covers how to perform all the steps of building, deploying, and upd and run builds. -11. *Optional:* Fork the [ruby sample repository](https://github.com/openshift/ruby-hello-world) +12. *Optional:* Fork the [ruby sample repository](https://github.com/openshift/ruby-hello-world) to an OpenShift-visible git account that you control, preferably somewhere that can also reach your OpenShift server with a webhook. A github.com account is an obvious place for this, but an in-house @@ -220,7 +222,7 @@ This section covers how to perform all the steps of building, deploying, and upd OpenShift's public repository, just not a changed build. -12. *Optional:* Add the following webhook under the settings in your new GitHub repository: +13. *Optional:* Add the following webhook under the settings in your new GitHub repository: $ https://:8443/osapi/v1beta1/buildConfigHooks/ruby-sample-build/secret101/github?namespace=test @@ -230,20 +232,12 @@ This section covers how to perform all the steps of building, deploying, and upd instance as the certificate chain generated is not publicly verified. -13. Edit application-template-stibuild.json which will define the sample application +14. Edit application-template-stibuild.json which will define the sample application * Update the BuildConfig's sourceURI (git://github.com/openshift/ruby-hello-world.git) to point to your forked repository. *Note:* You can skip this step if you did not create a forked repository. -14. Log in with the "test-admin" user and switch to the "test" project which will be used by every command from now on. This - will update the file pointed by $OPENSHIFTCONFIG and will make it easy to switch betwen the "master" context and the - "test-admin" user: - - $ osc login -u test-admin -p pass - $ osc project test - - 15. Submit the application template for processing (generating shared parameters requested in the template) and then request creation of the processed template: @@ -379,23 +373,26 @@ the ip address shown below with the correct one for your environment. $ docker pull openshift/origin-haproxy-router $ sudo chmod +r `pwd`/openshift.local.certificates/openshift-router/.kubeconfig - $ openshift ex router --create --credentials="`pwd`/openshift.local.certificates/openshift-router/.kubeconfig" + $ openshift ex router --create --credentials="`pwd`/openshift.local.certificates/openshift-router/.kubeconfig" --config=openshift.local.certificates/admin/.kubeconfig router # the service router # the deployment config -3. Wait for the router to start. +3. Switch to the `default` project to watch for router to start + $ osc project default + +4. Wait for the router to start. $ osc describe dc router # watch for the number of deployed pods to go to 1 -4. *Optional:* View the logs of the router. +5. *Optional:* View the logs of the router. $ osc log router-1- -5. Curl the url, substituting the ip address shown for the correct value in your environment. +6. Curl the url, substituting the ip address shown for the correct value in your environment. $ curl -s -k --resolve www.example.com:443:10.0.2.15 https://www.example.com ... removed for readability ... @@ -403,7 +400,7 @@ the ip address shown below with the correct one for your environment. ... removed for readability ... -6. *Optional*: View the certificate being used for the secure route. +7. *Optional*: View the certificate being used for the secure route. $ openssl s_client -servername www.example.com -connect 10.0.2.15:443 ... removed for readability ... diff --git a/hack/test-cmd.sh b/hack/test-cmd.sh index 76e47af30086..f91f2f9dc8c1 100755 --- a/hack/test-cmd.sh +++ b/hack/test-cmd.sh @@ -123,7 +123,7 @@ if [[ "${API_SCHEME}" == "https" ]]; then fi # set the home directory so we don't pick up the users .config -export HOME="${CERT_DIR}/admin" +export HOME="${TEMP_DIR}/home" wait_for_url "${KUBELET_SCHEME}://${KUBELET_HOST}:${KUBELET_PORT}/healthz" "kubelet: " 0.25 80 wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/healthz" "apiserver: " 0.25 80 @@ -146,11 +146,14 @@ export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}" if [[ "${API_SCHEME}" == "https" ]]; then # test bad certificate [ "$(osc get services 2>&1 | grep 'certificate signed by unknown authority')" ] - - # ignore anything in the running user's $HOME dir - export HOME="${CERT_DIR}/admin" fi + +osc login --server=${KUBERNETES_MASTER} --certificate-authority="${CERT_DIR}/ca/cert.crt" -u test-user -p anything +osc new-project project-foo --display-name="my project" --description="boring project description" +[ "$(osc project | grep 'Using project "project-foo"')" ] + + # test config files from the --config flag osc get services --config="${CERT_DIR}/admin/.kubeconfig" diff --git a/pkg/cmd/cli/cmd/login.go b/pkg/cmd/cli/cmd/login.go index 9d1eb845f146..b7d47b40ead0 100644 --- a/pkg/cmd/cli/cmd/login.go +++ b/pkg/cmd/cli/cmd/login.go @@ -11,6 +11,7 @@ import ( kapierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" kclientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" + kcmdconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/config" kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" "github.com/openshift/origin/pkg/cmd/cli/config" @@ -47,8 +48,7 @@ type LoginOptions struct { KeyFile string InsecureTLS bool - // Optional, if provided will only try to save in it - PathToSaveConfig string + PathOptions *kcmdconfig.PathOptions } const longDescription = `Logs in to the OpenShift server and saves a config file that @@ -75,7 +75,9 @@ func NewCmdLogin(f *osclientcmd.Factory, reader io.Reader, out io.Writer) *cobra Short: "Logs in and save the configuration", Long: longDescription, Run: func(cmd *cobra.Command, args []string) { - options.Complete(f, cmd, args) + if err := options.Complete(f, cmd, args); err != nil { + kcmdutil.CheckErr(err) + } if err := options.Validate(args, kcmdutil.GetFlagString(cmd, "server")); err != nil { kcmdutil.CheckErr(err) @@ -118,10 +120,14 @@ func NewCmdLogin(f *osclientcmd.Factory, reader io.Reader, out io.Writer) *cobra func (o *LoginOptions) Complete(f *osclientcmd.Factory, cmd *cobra.Command, args []string) error { kubeconfig, err := f.OpenShiftClientConfig.RawConfig() + o.StartingKubeConfig = &kubeconfig if err != nil { - return err + if !os.IsNotExist(err) { + return err + } + // build a valid object to use if we failed on a non-existent file + o.StartingKubeConfig = kclientcmdapi.NewConfig() } - o.StartingKubeConfig = &kubeconfig if serverFlag := kcmdutil.GetFlagString(cmd, "server"); len(serverFlag) > 0 { o.Server = serverFlag @@ -148,13 +154,14 @@ func (o *LoginOptions) Complete(f *osclientcmd.Factory, cmd *cobra.Command, args if keyFile := kcmdutil.GetFlagString(cmd, "client-key"); len(keyFile) > 0 { o.KeyFile = keyFile } - o.PathToSaveConfig = kcmdutil.GetFlagString(cmd, config.OpenShiftConfigFlagName) o.CAFile = kcmdutil.GetFlagString(cmd, "certificate-authority") o.InsecureTLS = kcmdutil.GetFlagBool(cmd, "insecure-skip-tls-verify") o.DefaultNamespace, _ = f.OpenShiftClientConfig.Namespace() + o.PathOptions = config.NewPathOptions(cmd) + return nil } @@ -171,6 +178,10 @@ func (o LoginOptions) Validate(args []string, serverFlag string) error { return errors.New("A server URL must be specified") } + if o.StartingKubeConfig == nil { + return errors.New("Must have a config file already created") + } + return nil } diff --git a/pkg/cmd/cli/cmd/loginoptions.go b/pkg/cmd/cli/cmd/loginoptions.go index 6545ece7444c..ef3815058d47 100644 --- a/pkg/cmd/cli/cmd/loginoptions.go +++ b/pkg/cmd/cli/cmd/loginoptions.go @@ -243,17 +243,11 @@ func (o *LoginOptions) gatherProjectInfo() error { switch len(projectsItems) { case 0: - // TODO most users will not be allowed to run the suggested commands below, so we should check it and/or - // have a server endpoint that allows an admin to describe to users how to request projects - fmt.Fprintf(o.Out, `You don't have any projects. If you have access to create a new project, run + fmt.Fprintf(o.Out, `You don't have any projects. You can try to create a new project, by running - $ openshift ex new-project --admin=%q + $ osc new-project -To be added as an admin to an existing project, run - - $ openshift ex policy add-role-to-user admin %q -n - -`, o.Username, o.Username) +`) case 1: o.Project = projectsItems[0].Name @@ -304,25 +298,13 @@ func (o *LoginOptions) SaveConfig() (bool, error) { return false, fmt.Errorf("Insufficient data to merge configuration.") } - pathOptions := &kubecmdconfig.PathOptions{ - GlobalFile: config.RecommendedHomeFile, - EnvVar: config.OpenShiftConfigPathEnvVar, - ExplicitFileFlag: config.OpenShiftConfigFlagName, - - GlobalFileSubpath: config.OpenShiftConfigHomeDirFileName, - - LoadingRules: &kclientcmd.ClientConfigLoadingRules{ - ExplicitPath: o.PathToSaveConfig, - }, - } - globalExistedBefore := true - if _, err := os.Stat(pathOptions.GlobalFile); os.IsNotExist(err) { + if _, err := os.Stat(o.PathOptions.GlobalFile); os.IsNotExist(err) { globalExistedBefore = false } newConfig := config.CreateConfig(o.Username, o.Project, o.Config) - baseDir := filepath.Dir(pathOptions.GetDefaultFilename()) + baseDir := filepath.Dir(o.PathOptions.GetDefaultFilename()) if err := config.RelativizeClientConfigPaths(&newConfig, baseDir); err != nil { return false, err } @@ -332,12 +314,12 @@ func (o *LoginOptions) SaveConfig() (bool, error) { return false, err } - if err := kubecmdconfig.ModifyConfig(pathOptions, *configToWrite); err != nil { + if err := kubecmdconfig.ModifyConfig(o.PathOptions, *configToWrite); err != nil { return false, err } created := false - if _, err := os.Stat(pathOptions.GlobalFile); err == nil { + if _, err := os.Stat(o.PathOptions.GlobalFile); err == nil { created = created || !globalExistedBefore } diff --git a/pkg/cmd/cli/cmd/project.go b/pkg/cmd/cli/cmd/project.go index 3dde1c118782..84812737ca06 100644 --- a/pkg/cmd/cli/cmd/project.go +++ b/pkg/cmd/cli/cmd/project.go @@ -2,13 +2,13 @@ package cmd import ( "bytes" + "errors" "fmt" "io" "os" - "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + kapierrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" - kclientcmd "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" "github.com/GoogleCloudPlatform/kubernetes/pkg/fields" kubecmdconfig "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/config" @@ -24,14 +24,30 @@ import ( "github.com/spf13/cobra" ) +type ProjectOptions struct { + Config clientcmdapi.Config + Client *client.Client + ClientConfig *kclient.Config + Out io.Writer + PathOptions *kubecmdconfig.PathOptions + + ProjectName string + ProjectOnly bool +} + // NewCmdProject implements the OpenShift cli rollback command func NewCmdProject(f *clientcmd.Factory, out io.Writer) *cobra.Command { + options := &ProjectOptions{} + cmd := &cobra.Command{ Use: "project ", Short: "switch to another project", Long: `Switch to another project and make it the default in your configuration.`, Run: func(cmd *cobra.Command, args []string) { - err := RunProject(f, out, cmd, args) + options.PathOptions = cliconfig.NewPathOptions(cmd) + options.Complete(f, args, out) + + err := options.RunProject() if err == errExit { os.Exit(1) } @@ -41,38 +57,55 @@ func NewCmdProject(f *clientcmd.Factory, out io.Writer) *cobra.Command { return cmd } -// RunProject contains all the necessary functionality for the OpenShift cli project command -func RunProject(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args []string) error { - argsLength := len(args) +func (o *ProjectOptions) Complete(f *clientcmd.Factory, args []string, out io.Writer) error { + var err error - if argsLength > 1 { - return cmdutil.UsageError(cmd, "Only one argument is supported (project name).") + argsLength := len(args) + switch { + case argsLength > 1: + return errors.New("Only one argument is supported (project name).") + case argsLength == 1: + o.ProjectName = args[0] } - config, err := f.OpenShiftClientConfig.RawConfig() + o.Config, err = f.OpenShiftClientConfig.RawConfig() if err != nil { return err } - clientCfg, err := f.OpenShiftClientConfig.ClientConfig() + o.ClientConfig, err = f.OpenShiftClientConfig.ClientConfig() if err != nil { return err } - oClient, _, err := f.Clients() + o.Client, _, err = f.Clients() if err != nil { return err } + o.Out = out + + return nil +} +func (o ProjectOptions) Validate() error { + return nil +} + +// RunProject contains all the necessary functionality for the OpenShift cli project command +func (o ProjectOptions) RunProject() error { + config := o.Config + clientCfg := o.ClientConfig + out := o.Out + // No argument provided, we will just print info - if argsLength == 0 { + if len(o.ProjectName) == 0 { currentContext := config.Contexts[config.CurrentContext] currentProject := currentContext.Namespace if len(currentProject) > 0 { - _, err := oClient.Projects().Get(currentProject) + _, err := o.Client.Projects().Get(currentProject) if err != nil { - if errors.IsNotFound(err) { + if kapierrors.IsNotFound(err) { return fmt.Errorf("the project %q specified in your config does not exist.", currentProject) } if clientcmd.IsForbidden(err) { @@ -98,23 +131,23 @@ func RunProject(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args [] } // We have an argument that can be either a context or project - argument := args[0] + argument := o.ProjectName contextInUse := "" namespaceInUse := "" // Check if argument is an existing context, if so just set it as the context in use. // If not a context then we will try to handle it as a project. - if context, ok := config.Contexts[argument]; ok && len(context.Namespace) > 0 { + if context, ok := config.Contexts[argument]; !o.ProjectOnly && (ok && len(context.Namespace) > 0) { contextInUse = argument namespaceInUse = context.Namespace config.CurrentContext = argument } else { - project, err := oClient.Projects().Get(argument) + project, err := o.Client.Projects().Get(argument) if err != nil { - if isNotFound, isForbidden := errors.IsNotFound(err), clientcmd.IsForbidden(err); isNotFound || isForbidden { + if isNotFound, isForbidden := kapierrors.IsNotFound(err), clientcmd.IsForbidden(err); isNotFound || isForbidden { msg := "" if isNotFound { @@ -123,7 +156,7 @@ func RunProject(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args [] msg = fmt.Sprintf("You do not have rights to view project %q on server %q.", argument, clientCfg.Host) } - projects, err := getProjects(oClient) + projects, err := getProjects(o.Client) if err == nil { msg += "\nYour projects are:" for _, project := range projects { @@ -183,19 +216,7 @@ func RunProject(f *clientcmd.Factory, out io.Writer, cmd *cobra.Command, args [] } } - pathOptions := &kubecmdconfig.PathOptions{ - GlobalFile: cliconfig.RecommendedHomeFile, - EnvVar: cliconfig.OpenShiftConfigPathEnvVar, - ExplicitFileFlag: cliconfig.OpenShiftConfigFlagName, - - GlobalFileSubpath: cliconfig.OpenShiftConfigHomeDirFileName, - - LoadingRules: &kclientcmd.ClientConfigLoadingRules{ - ExplicitPath: cmdutil.GetFlagString(cmd, cliconfig.OpenShiftConfigFlagName), - }, - } - - if err := kubecmdconfig.ModifyConfig(pathOptions, config); err != nil { + if err := kubecmdconfig.ModifyConfig(o.PathOptions, config); err != nil { return err } diff --git a/pkg/cmd/cli/cmd/request_project.go b/pkg/cmd/cli/cmd/request_project.go index a6aadd185c9c..00b4964690ff 100644 --- a/pkg/cmd/cli/cmd/request_project.go +++ b/pkg/cmd/cli/cmd/request_project.go @@ -1,13 +1,16 @@ package cmd import ( + "errors" "fmt" "io" - "github.com/golang/glog" "github.com/spf13/cobra" + kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" + "github.com/openshift/origin/pkg/client" + cliconfig "github.com/openshift/origin/pkg/cmd/cli/config" "github.com/openshift/origin/pkg/cmd/util/clientcmd" projectapi "github.com/openshift/origin/pkg/project/api" ) @@ -18,6 +21,9 @@ type NewProjectOptions struct { Description string Client client.Interface + + ProjectOptions *ProjectOptions + Out io.Writer } const requestProjectLongDesc = ` @@ -40,22 +46,23 @@ After your project is created you can switch to it using %[3]s . 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 [--display-name= --description=