diff --git a/hack/test-end-to-end.sh b/hack/test-end-to-end.sh index 1c18a3672621..85e1a3c32ebb 100755 --- a/hack/test-end-to-end.sh +++ b/hack/test-end-to-end.sh @@ -188,9 +188,10 @@ wait_for_url "${API_SCHEME}://${API_HOST}:${API_PORT}/api/v1beta1/minions/127.0. export KUBERNETES_MASTER="${API_SCHEME}://${API_HOST}:${API_PORT}" # create test project so that this shows up in the console -osc create project -f examples/sample-app/project.json +openshift ex new-project test --description="This is an example project to demonstrate OpenShift v3" --admin="anypassword:e2e-user" echo "The console should be available at ${API_SCHEME}://${PUBLIC_MASTER_HOST}:$(($API_PORT + 1)). You may need to visit ${API_SCHEME}://${PUBLIC_MASTER_HOST}:${API_PORT} first to accept the certificate." +echo "Log in as 'e2e-user' to see the 'test' project." # install the registry diff --git a/pkg/authorization/authorizer/authorizer.go b/pkg/authorization/authorizer/authorizer.go index 0fd649c7e801..4a28a63974d1 100644 --- a/pkg/authorization/authorizer/authorizer.go +++ b/pkg/authorization/authorizer/authorizer.go @@ -382,6 +382,10 @@ func (a *openshiftAuthorizationAttributeBuilder) GetAttributes(req *http.Request return nil, err } + if (requestInfo.Resource == "projects") && (len(requestInfo.Name) > 0) { + requestInfo.Namespace = requestInfo.Name + } + userInterface, ok := a.requestsToUsers.Get(req) if !ok { return nil, errors.New("could not get user") @@ -691,7 +695,7 @@ func GetBootstrapPolicyBinding(masterNamespace string) *authorizationapi.PolicyB }, "system:deployer-binding": { ObjectMeta: kapi.ObjectMeta{ - Name: "system:deployer", + Name: "system:deployer-binding", Namespace: masterNamespace, }, RoleRef: kapi.ObjectReference{ diff --git a/pkg/client/projects.go b/pkg/client/projects.go index f101ec4ae9d9..82bc2e50073e 100644 --- a/pkg/client/projects.go +++ b/pkg/client/projects.go @@ -13,6 +13,8 @@ type ProjectsInterface interface { // UserInterface exposes methods on user resources. type ProjectInterface interface { + Create(p *projectapi.Project) (*projectapi.Project, error) + Delete(name string) error Get(name string) (*projectapi.Project, error) List(label, field labels.Selector) (*projectapi.ProjectList, error) } diff --git a/pkg/cmd/experimental/login/login.go b/pkg/cmd/experimental/login/login.go index 4cea2d2dce0a..214b262bc88f 100644 --- a/pkg/cmd/experimental/login/login.go +++ b/pkg/cmd/experimental/login/login.go @@ -6,22 +6,22 @@ import ( "github.com/golang/glog" "github.com/spf13/cobra" - "github.com/spf13/pflag" kclient "github.com/GoogleCloudPlatform/kubernetes/pkg/client" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" clientcmdapi "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd/api" - cmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" + kcmdutil "github.com/GoogleCloudPlatform/kubernetes/pkg/kubectl/cmd/util" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/openshift/origin/pkg/client" "github.com/openshift/origin/pkg/cmd/cli/cmd" "github.com/openshift/origin/pkg/cmd/flagtypes" + cmdutil "github.com/openshift/origin/pkg/cmd/util" "github.com/openshift/origin/pkg/cmd/util/tokencmd" ) func NewCmdLogin(name string, parent *cobra.Command) *cobra.Command { - clientConfig := defaultClientConfig(parent.PersistentFlags()) + clientConfig := cmdutil.DefaultClientConfig(parent.PersistentFlags()) f := cmd.NewFactory(clientConfig) f.BindFlags(parent.PersistentFlags()) @@ -49,8 +49,8 @@ prompt for user input if not provided. username = userFullName } else { - usernameFlag := cmdutil.GetFlagString(cmd, "username") - passwordFlag := cmdutil.GetFlagString(cmd, "password") + usernameFlag := kcmdutil.GetFlagString(cmd, "username") + passwordFlag := kcmdutil.GetFlagString(cmd, "password") accessToken, err := tokencmd.RequestToken(clientCfg, os.Stdin, usernameFlag, passwordFlag) if err != nil { @@ -94,22 +94,6 @@ func whoami(clientCfg *kclient.Config) (string, error) { return me.FullName, nil } -// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig -// TODO find and merge duplicates, this is also in other places -func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { - loadingRules := clientcmd.NewClientConfigLoadingRules() - loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar) - flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") - - overrides := &clientcmd.ConfigOverrides{} - overrideFlags := clientcmd.RecommendedConfigOverrideFlags("") - overrideFlags.ContextOverrideFlags.NamespaceShort = "n" - clientcmd.BindOverrideFlags(overrides, flags, overrideFlags) - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) - - return clientConfig -} - func updateKubeconfigFile(username, token string, clientCfg clientcmd.ClientConfig) error { rawMergedConfig, err := clientCfg.RawConfig() if err != nil { diff --git a/pkg/cmd/experimental/policy/policy.go b/pkg/cmd/experimental/policy/policy.go index 3610c7836957..c6ddce4317d2 100644 --- a/pkg/cmd/experimental/policy/policy.go +++ b/pkg/cmd/experimental/policy/policy.go @@ -2,17 +2,16 @@ package policy import ( "fmt" - "os" "strings" "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" "github.com/GoogleCloudPlatform/kubernetes/pkg/util" "github.com/golang/glog" "github.com/spf13/cobra" - "github.com/spf13/pflag" authorizationapi "github.com/openshift/origin/pkg/authorization/api" "github.com/openshift/origin/pkg/client" + cmdutil "github.com/openshift/origin/pkg/cmd/util" ) func NewCommandPolicy(name string) *cobra.Command { @@ -26,7 +25,7 @@ func NewCommandPolicy(name string) *cobra.Command { // Override global default to https and port 8443 clientcmd.DefaultCluster.Server = "https://localhost:8443" - clientConfig := defaultClientConfig(cmds.PersistentFlags()) + clientConfig := cmdutil.DefaultClientConfig(cmds.PersistentFlags()) cmds.AddCommand(NewCmdAddUser(clientConfig)) cmds.AddCommand(NewCmdRemoveUser(clientConfig)) @@ -51,19 +50,6 @@ func getFlagString(cmd *cobra.Command, flag string) string { return f.Value.String() } -// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig -func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { - loadingRules := clientcmd.NewClientConfigLoadingRules() - loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar) - flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") - - overrides := &clientcmd.ConfigOverrides{} - clientcmd.BindOverrideFlags(overrides, flags, clientcmd.RecommendedConfigOverrideFlags("")) - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) - - return clientConfig -} - func getUniqueName(basename string, existingNames *util.StringSet) string { if !existingNames.Has(basename) { return basename diff --git a/pkg/cmd/experimental/project/new_project.go b/pkg/cmd/experimental/project/new_project.go new file mode 100644 index 000000000000..00a5e74b66c5 --- /dev/null +++ b/pkg/cmd/experimental/project/new_project.go @@ -0,0 +1,119 @@ +package project + +import ( + "fmt" + + kerrors "github.com/GoogleCloudPlatform/kubernetes/pkg/api/errors" + "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" + "github.com/spf13/cobra" + + authorizationapi "github.com/openshift/origin/pkg/authorization/api" + "github.com/openshift/origin/pkg/client" + cmdutil "github.com/openshift/origin/pkg/cmd/util" + projectapi "github.com/openshift/origin/pkg/project/api" +) + +type newProjectOptions struct { + projectName string + displayName string + description string + clientConfig clientcmd.ClientConfig + + adminRole string + masterPolicyNamespace string + adminUser string +} + +func NewCmdNewProject(name string) *cobra.Command { + options := &newProjectOptions{} + + cmd := &cobra.Command{ + Use: name + " ", + Short: "create a new project", + Long: `create a new project`, + Run: func(cmd *cobra.Command, args []string) { + if !options.complete(cmd) { + return + } + + err := options.run() + if err != nil { + fmt.Printf("%v\n", err) + } + }, + } + + // Override global default to https and port 8443 + clientcmd.DefaultCluster.Server = "https://localhost:8443" + clientConfig := cmdutil.DefaultClientConfig(cmd.Flags()) + options.clientConfig = clientConfig + + // TODO remove once we have global policy objects + cmd.Flags().StringVar(&options.masterPolicyNamespace, "master-policy-namespace", "master", "master policy namespace") + cmd.Flags().StringVar(&options.adminRole, "admin-role", "admin", "project admin role name in the master policy namespace") + 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") + + return cmd +} + +func (o *newProjectOptions) complete(cmd *cobra.Command) bool { + args := cmd.Flags().Args() + if len(args) != 1 { + cmd.Help() + return false + } + + o.projectName = args[0] + + return true +} + +func (o *newProjectOptions) run() error { + clientConfig, err := o.clientConfig.ClientConfig() + if err != nil { + return err + } + client, err := client.New(clientConfig) + if err != nil { + return err + } + + _, err = client.Projects().Get(o.projectName) + projectFound := !kerrors.IsNotFound(err) + if (err != nil) && (projectFound) { + return err + } + if projectFound { + return fmt.Errorf("project %v already exists", o.projectName) + } + + project := &projectapi.Project{} + project.Name = o.projectName + project.DisplayName = o.displayName + project.Annotations = make(map[string]string) + project.Annotations["description"] = o.description + project, err = client.Projects().Create(project) + if err != nil { + return err + } + + if len(o.adminUser) != 0 { + adminRoleBinding := &authorizationapi.RoleBinding{} + + adminRoleBinding.Name = "admins" + adminRoleBinding.RoleRef.Namespace = o.masterPolicyNamespace + adminRoleBinding.RoleRef.Name = o.adminRole + adminRoleBinding.UserNames = []string{o.adminUser} + + _, err := client.RoleBindings(project.Name).Create(adminRoleBinding) + if err != nil { + fmt.Printf("The project %v was created, but %v could not be added to the %v role.\n", o.projectName, o.adminUser, o.adminRole) + fmt.Printf("To add the user to the existing project, run\n\n\topenshift ex policy add-user --namespace=%v --role-namespace=%v %v %v\n", o.projectName, o.masterPolicyNamespace, o.adminRole, o.adminUser) + return err + } + } + + return nil +} diff --git a/pkg/cmd/experimental/tokens/tokens.go b/pkg/cmd/experimental/tokens/tokens.go index 0b52205c6ecb..6b18532ea673 100644 --- a/pkg/cmd/experimental/tokens/tokens.go +++ b/pkg/cmd/experimental/tokens/tokens.go @@ -7,11 +7,11 @@ import ( "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" "github.com/golang/glog" "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/openshift/origin/pkg/auth/server/tokenrequest" "github.com/openshift/origin/pkg/cmd/cli/cmd" "github.com/openshift/origin/pkg/cmd/server/origin" + cmdutil "github.com/openshift/origin/pkg/cmd/util" ) const ( @@ -34,7 +34,7 @@ func NewCmdTokens(name string) *cobra.Command { clientcmd.DefaultCluster.Server = "https://localhost:8443" // TODO: there should be two client configs, one for OpenShift, and one for Kubernetes - f := cmd.NewFactory(defaultClientConfig(cmds.PersistentFlags())) + f := cmd.NewFactory(cmdutil.DefaultClientConfig(cmds.PersistentFlags())) f.BindFlags(cmds.PersistentFlags()) cmds.AddCommand(NewCmdValidateToken(f)) @@ -55,17 +55,3 @@ func getFlagString(cmd *cobra.Command, flag string) string { func getRequestTokenURL(clientCfg *client.Config) string { return clientCfg.Host + origin.OpenShiftLoginPrefix + tokenrequest.RequestTokenEndpoint } - -// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig -// TODO find and merge duplicates, this is also in other places -func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { - loadingRules := clientcmd.NewClientConfigLoadingRules() - loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar) - flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") - - overrides := &clientcmd.ConfigOverrides{} - clientcmd.BindOverrideFlags(overrides, flags, clientcmd.RecommendedConfigOverrideFlags("")) - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) - - return clientConfig -} diff --git a/pkg/cmd/openshift/openshift.go b/pkg/cmd/openshift/openshift.go index 387f60143ed5..2c1d9c357758 100644 --- a/pkg/cmd/openshift/openshift.go +++ b/pkg/cmd/openshift/openshift.go @@ -12,6 +12,7 @@ import ( "github.com/openshift/origin/pkg/cmd/experimental/generate" "github.com/openshift/origin/pkg/cmd/experimental/login" "github.com/openshift/origin/pkg/cmd/experimental/policy" + "github.com/openshift/origin/pkg/cmd/experimental/project" "github.com/openshift/origin/pkg/cmd/experimental/tokens" "github.com/openshift/origin/pkg/cmd/flagtypes" "github.com/openshift/origin/pkg/cmd/infra/builder" @@ -114,6 +115,7 @@ func newExperimentalCommand(parentName, name string) *cobra.Command { experimental.AddCommand(policy.NewCommandPolicy("policy")) experimental.AddCommand(generate.NewCmdGenerate("generate")) experimental.AddCommand(login.NewCmdLogin("login", experimental)) + experimental.AddCommand(project.NewCmdNewProject("new-project")) return experimental } diff --git a/pkg/cmd/server/start.go b/pkg/cmd/server/start.go index e4d2b5f6b96b..005acc29f32f 100644 --- a/pkg/cmd/server/start.go +++ b/pkg/cmd/server/start.go @@ -30,7 +30,6 @@ import ( etcdclient "github.com/coreos/go-etcd/etcd" "github.com/golang/glog" "github.com/spf13/cobra" - "github.com/spf13/pflag" "github.com/openshift/origin/pkg/api/latest" "github.com/openshift/origin/pkg/auth/authenticator" @@ -49,6 +48,7 @@ import ( "github.com/openshift/origin/pkg/cmd/server/kubernetes" "github.com/openshift/origin/pkg/cmd/server/origin" "github.com/openshift/origin/pkg/cmd/util" + cmdutil "github.com/openshift/origin/pkg/cmd/util" "github.com/openshift/origin/pkg/cmd/util/docker" "github.com/openshift/origin/pkg/cmd/util/variable" pkgutil "github.com/openshift/origin/pkg/util" @@ -184,27 +184,13 @@ func NewCommandStartServer(name string) *cobra.Command { flag.Var(&cfg.NodeList, "nodes", "The hostnames of each node. This currently must be specified up front. Comma delimited list") flag.Var(&cfg.CORSAllowedOrigins, "cors-allowed-origins", "List of allowed origins for CORS, comma separated. An allowed origin can be a regular expression to support subdomain matching. CORS is enabled for localhost, 127.0.0.1, and the asset server by default.") - cfg.ClientConfig = defaultClientConfig(flag) + cfg.ClientConfig = cmdutil.DefaultClientConfig(flag) cfg.Docker.InstallFlags(flag) return cmd } -// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig -// TODO: there should be two client configs, one for OpenShift, and one for Kubernetes -func defaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { - clientcmd.DefaultCluster.Server = "https://localhost:8443" - loadingRules := clientcmd.NewClientConfigLoadingRules() - loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar) - flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for connecting to the master.") - - overrides := &clientcmd.ConfigOverrides{} - //clientcmd.BindOverrideFlags(overrides, flags, clientcmd.RecommendedConfigOverrideFlags("")) - clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) - return clientConfig -} - // run launches the appropriate startup modes or returns an error. func start(cfg *config, args []string) error { if len(args) > 1 { diff --git a/pkg/cmd/util/clientconfig.go b/pkg/cmd/util/clientconfig.go new file mode 100644 index 000000000000..b741536a74be --- /dev/null +++ b/pkg/cmd/util/clientconfig.go @@ -0,0 +1,25 @@ +package util + +import ( + "os" + + "github.com/spf13/pflag" + + "github.com/GoogleCloudPlatform/kubernetes/pkg/client/clientcmd" +) + +// Copy of kubectl/cmd/DefaultClientConfig, using NewNonInteractiveDeferredLoadingClientConfig +func DefaultClientConfig(flags *pflag.FlagSet) clientcmd.ClientConfig { + loadingRules := clientcmd.NewClientConfigLoadingRules() + loadingRules.EnvVarPath = os.Getenv(clientcmd.RecommendedConfigPathEnvVar) + flags.StringVar(&loadingRules.CommandLinePath, "kubeconfig", "", "Path to the kubeconfig file to use for CLI requests.") + + overrides := &clientcmd.ConfigOverrides{} + overrideFlags := clientcmd.RecommendedConfigOverrideFlags("") + overrideFlags.ContextOverrideFlags.NamespaceShort = "n" + clientcmd.BindOverrideFlags(overrides, flags, overrideFlags) + + clientConfig := clientcmd.NewNonInteractiveDeferredLoadingClientConfig(loadingRules, overrides) + + return clientConfig +}