diff --git a/pkg/odo/cli/component/common_push.go b/pkg/odo/cli/component/common_push.go index 4043bf1ce87..13875a3cca4 100644 --- a/pkg/odo/cli/component/common_push.go +++ b/pkg/odo/cli/component/common_push.go @@ -19,18 +19,27 @@ import ( // CommonPushOptions has data needed for all pushes type CommonPushOptions struct { + // Context + *genericclioptions.Context + + // Clients + prjClient project.Client + + //Flags // TODO(feloy) Fixme showFlag bool //nolint:structcheck componentContext string configFlag bool sourceFlag bool - EnvSpecificInfo *envinfo.EnvSpecificInfo - *genericclioptions.Context + + EnvSpecificInfo *envinfo.EnvSpecificInfo } // NewCommonPushOptions instantiates a commonPushOptions object -func NewCommonPushOptions() *CommonPushOptions { - return &CommonPushOptions{} +func NewCommonPushOptions(prjClient project.Client) *CommonPushOptions { + return &CommonPushOptions{ + prjClient: prjClient, + } } //InitEnvInfoFromContext initializes envinfo from the context @@ -60,12 +69,12 @@ func (cpo *CommonPushOptions) ResolveSrcAndConfigFlags() { func (cpo *CommonPushOptions) ResolveProject(prjName string) (err error) { // check if project exist - isPrjExists, err := project.Exists(cpo.Context.KClient, prjName) + isPrjExists, err := cpo.prjClient.Exists(prjName) if err != nil { return errors.Wrapf(err, "failed to check if project with name %s exists", prjName) } if !isPrjExists { - err = project.Create(cpo.Context.KClient, prjName, true) + err = cpo.prjClient.Create(prjName, true) if err != nil { return errors.Wrapf( err, diff --git a/pkg/odo/cli/component/create.go b/pkg/odo/cli/component/create.go index da3dd169167..853234a5684 100644 --- a/pkg/odo/cli/component/create.go +++ b/pkg/odo/cli/component/create.go @@ -6,8 +6,10 @@ import ( "path/filepath" "strings" + "github.com/redhat-developer/odo/pkg/kclient" registryUtil "github.com/redhat-developer/odo/pkg/odo/cli/registry/util" "github.com/redhat-developer/odo/pkg/odo/cmdline" + "github.com/redhat-developer/odo/pkg/project" "github.com/zalando/go-keyring" "github.com/devfile/library/pkg/devfile" @@ -113,9 +115,9 @@ odo catalog list components %[1]s nodejs --app myapp --project myproject`) // NewCreateOptions returns new instance of CreateOptions -func NewCreateOptions() *CreateOptions { +func NewCreateOptions(prjClient project.Client) *CreateOptions { return &CreateOptions{ - PushOptions: NewPushOptions(), + PushOptions: NewPushOptions(prjClient), } } @@ -345,7 +347,9 @@ func (co *CreateOptions) Run() (err error) { // NewCmdCreate implements the create odo command func NewCmdCreate(name, fullName string) *cobra.Command { - co := NewCreateOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + co := NewCreateOptions(project.NewClient(kubclient)) var componentCreateCmd = &cobra.Command{ Use: fmt.Sprintf("%s [component_name] [flags]", name), Short: "Create a new component", diff --git a/pkg/odo/cli/component/push.go b/pkg/odo/cli/component/push.go index be0c3bef8d7..283626d5329 100644 --- a/pkg/odo/cli/component/push.go +++ b/pkg/odo/cli/component/push.go @@ -5,6 +5,7 @@ import ( "path/filepath" "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/project" scontext "github.com/redhat-developer/odo/pkg/segment/context" "github.com/redhat-developer/odo/pkg/component" @@ -73,9 +74,9 @@ type PushOptions struct { // NewPushOptions returns new instance of PushOptions // with "default" values for certain values, for example, show is "false" -func NewPushOptions() *PushOptions { +func NewPushOptions(prjClient project.Client) *PushOptions { return &PushOptions{ - CommonPushOptions: NewCommonPushOptions(), + CommonPushOptions: NewCommonPushOptions(prjClient), } } @@ -228,7 +229,9 @@ func (po *PushOptions) Run() (err error) { // NewCmdPush implements the push odo command func NewCmdPush(name, fullName string) *cobra.Command { - po := NewPushOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + po := NewPushOptions(project.NewClient(kubclient)) var pushCmd = &cobra.Command{ Use: fmt.Sprintf("%s [component name]", name), diff --git a/pkg/odo/cli/config/set.go b/pkg/odo/cli/config/set.go index 2d2d5655cde..5c5e48c179d 100644 --- a/pkg/odo/cli/config/set.go +++ b/pkg/odo/cli/config/set.go @@ -4,7 +4,9 @@ import ( "fmt" "strings" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/odo/cmdline" + "github.com/redhat-developer/odo/pkg/project" "github.com/redhat-developer/odo/pkg/util" "github.com/pkg/errors" @@ -54,8 +56,10 @@ type SetOptions struct { } // NewSetOptions creates a new SetOptions instance -func NewSetOptions() *SetOptions { - return &SetOptions{PushOptions: clicomponent.NewPushOptions()} +func NewSetOptions(prjClient project.Client) *SetOptions { + return &SetOptions{ + PushOptions: clicomponent.NewPushOptions(prjClient), + } } // Complete completes SetOptions after they've been created @@ -174,7 +178,9 @@ func isValidArgumentList(args []string) error { // NewCmdSet implements the config set odo command func NewCmdSet(name, fullName string) *cobra.Command { - o := NewSetOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewSetOptions(project.NewClient(kubclient)) configurationSetCmd := &cobra.Command{ Use: name, Short: "Set a value in odo config file", diff --git a/pkg/odo/cli/config/unset.go b/pkg/odo/cli/config/unset.go index cde85144e15..f9c383a09ce 100644 --- a/pkg/odo/cli/config/unset.go +++ b/pkg/odo/cli/config/unset.go @@ -4,6 +4,8 @@ import ( "fmt" "strings" + "github.com/redhat-developer/odo/pkg/kclient" + "github.com/redhat-developer/odo/pkg/project" "github.com/redhat-developer/odo/pkg/util" "github.com/redhat-developer/odo/pkg/config" @@ -49,8 +51,10 @@ type UnsetOptions struct { } // NewUnsetOptions creates a new UnsetOptions instance -func NewUnsetOptions() *UnsetOptions { - return &UnsetOptions{PushOptions: clicomponent.NewPushOptions()} +func NewUnsetOptions(prjClient project.Client) *UnsetOptions { + return &UnsetOptions{ + PushOptions: clicomponent.NewPushOptions(prjClient), + } } // Complete completes UnsetOptions after they've been created @@ -125,7 +129,9 @@ func (o *UnsetOptions) Run() error { // NewCmdUnset implements the config unset odo command func NewCmdUnset(name, fullName string) *cobra.Command { - o := NewUnsetOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewUnsetOptions(project.NewClient(kubclient)) configurationUnsetCmd := &cobra.Command{ Use: name, Short: "Unset a value in odo config file", diff --git a/pkg/odo/cli/project/create.go b/pkg/odo/cli/project/create.go index 65d0e47e088..fec1818c5f0 100644 --- a/pkg/odo/cli/project/create.go +++ b/pkg/odo/cli/project/create.go @@ -3,6 +3,7 @@ package project import ( "fmt" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/machineoutput" "github.com/redhat-developer/odo/pkg/odo/cmdline" @@ -35,6 +36,9 @@ type ProjectCreateOptions struct { // Context *genericclioptions.Context + // Clients + prjClient project.Client + // Parameters projectName string @@ -43,8 +47,10 @@ type ProjectCreateOptions struct { } // NewProjectCreateOptions creates a ProjectCreateOptions instance -func NewProjectCreateOptions() *ProjectCreateOptions { - return &ProjectCreateOptions{} +func NewProjectCreateOptions(prjClient project.Client) *ProjectCreateOptions { + return &ProjectCreateOptions{ + prjClient: prjClient, + } } // Complete completes ProjectCreateOptions after they've been created @@ -77,7 +83,7 @@ func (pco *ProjectCreateOptions) Run() (err error) { } // Create the project & end the spinner (if there is any..) - err = project.Create(pco.Context.KClient, pco.projectName, pco.waitFlag) + err = pco.prjClient.Create(pco.projectName, pco.waitFlag) if err != nil { return err } @@ -87,7 +93,7 @@ func (pco *ProjectCreateOptions) Run() (err error) { log.Successf(successMessage) // Set the current project when created - err = project.SetCurrent(pco.Context.KClient, pco.projectName) + err = pco.prjClient.SetCurrent(pco.projectName) if err != nil { return err } @@ -105,7 +111,9 @@ func (pco *ProjectCreateOptions) Run() (err error) { // NewCmdProjectCreate creates the project create command func NewCmdProjectCreate(name, fullName string) *cobra.Command { - o := NewProjectCreateOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewProjectCreateOptions(project.NewClient(kubclient)) projectCreateCmd := &cobra.Command{ Use: name, diff --git a/pkg/odo/cli/project/delete.go b/pkg/odo/cli/project/delete.go index f86d1afb125..65c751fc95a 100644 --- a/pkg/odo/cli/project/delete.go +++ b/pkg/odo/cli/project/delete.go @@ -4,6 +4,7 @@ import ( "fmt" odoerrors "github.com/redhat-developer/odo/pkg/errors" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/machineoutput" "github.com/redhat-developer/odo/pkg/odo/cli/ui" @@ -36,6 +37,9 @@ type ProjectDeleteOptions struct { // Context *genericclioptions.Context + // Clients + prjClient project.Client + // Parameters projectName string @@ -45,8 +49,10 @@ type ProjectDeleteOptions struct { } // NewProjectDeleteOptions creates a ProjectDeleteOptions instance -func NewProjectDeleteOptions() *ProjectDeleteOptions { - return &ProjectDeleteOptions{} +func NewProjectDeleteOptions(prjClient project.Client) *ProjectDeleteOptions { + return &ProjectDeleteOptions{ + prjClient: prjClient, + } } // Complete completes ProjectDeleteOptions after they've been created @@ -59,7 +65,7 @@ func (pdo *ProjectDeleteOptions) Complete(name string, cmdline cmdline.Cmdline, // Validate validates the parameters of the ProjectDeleteOptions func (pdo *ProjectDeleteOptions) Validate() error { // Validate existence of the project to be deleted - isValidProject, err := project.Exists(pdo.Context.KClient, pdo.projectName) + isValidProject, err := pdo.prjClient.Exists(pdo.projectName) if kerrors.IsForbidden(err) { return &odoerrors.Unauthorized{} } @@ -76,7 +82,7 @@ func (pdo *ProjectDeleteOptions) Run() (err error) { s := &log.Status{} // This to set the project in the file and runtime - err = project.SetCurrent(pdo.Context.KClient, pdo.projectName) + err = pdo.prjClient.SetCurrent(pdo.projectName) if err != nil { return err } @@ -97,7 +103,7 @@ func (pdo *ProjectDeleteOptions) Run() (err error) { defer s.End(false) } - err := project.Delete(pdo.Context.KClient, pdo.projectName, pdo.waitFlag) + err := pdo.prjClient.Delete(pdo.projectName, pdo.waitFlag) if err != nil { return err } @@ -118,7 +124,9 @@ func (pdo *ProjectDeleteOptions) Run() (err error) { // NewCmdProjectDelete creates the project delete command func NewCmdProjectDelete(name, fullName string) *cobra.Command { - o := NewProjectDeleteOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewProjectDeleteOptions(project.NewClient(kubclient)) projectDeleteCmd := &cobra.Command{ Use: name, diff --git a/pkg/odo/cli/project/list.go b/pkg/odo/cli/project/list.go index 987f3d2e8b8..1bca671a445 100644 --- a/pkg/odo/cli/project/list.go +++ b/pkg/odo/cli/project/list.go @@ -6,6 +6,7 @@ import ( "os" "text/tabwriter" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/machineoutput" "github.com/redhat-developer/odo/pkg/odo/cmdline" @@ -30,11 +31,16 @@ var ( type ProjectListOptions struct { // Context *genericclioptions.Context + + // Clients + prjClient project.Client } // NewProjectListOptions creates a new ProjectListOptions instance -func NewProjectListOptions() *ProjectListOptions { - return &ProjectListOptions{} +func NewProjectListOptions(prjClient project.Client) *ProjectListOptions { + return &ProjectListOptions{ + prjClient: prjClient, + } } // Complete completes ProjectListOptions after they've been created @@ -50,7 +56,7 @@ func (plo *ProjectListOptions) Validate() (err error) { // Run contains the logic for the odo project list command func (plo *ProjectListOptions) Run() error { - projects, err := project.List(plo.Context.KClient) + projects, err := plo.prjClient.List() if err != nil { return err } @@ -68,7 +74,9 @@ func (plo *ProjectListOptions) Run() error { // NewCmdProjectList implements the odo project list command. func NewCmdProjectList(name, fullName string) *cobra.Command { - o := NewProjectListOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewProjectListOptions(project.NewClient(kubclient)) projectListCmd := &cobra.Command{ Use: name, Short: listLongDesc, diff --git a/pkg/odo/cli/project/set.go b/pkg/odo/cli/project/set.go index 8ca6d3c2434..4ec578f6a42 100644 --- a/pkg/odo/cli/project/set.go +++ b/pkg/odo/cli/project/set.go @@ -4,6 +4,7 @@ import ( "fmt" odoerrors "github.com/redhat-developer/odo/pkg/errors" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/odo/cmdline" "github.com/redhat-developer/odo/pkg/odo/genericclioptions" @@ -36,6 +37,9 @@ type ProjectSetOptions struct { // Context *genericclioptions.Context + // Clients + prjClient project.Client + // Parameters projectName string @@ -44,8 +48,10 @@ type ProjectSetOptions struct { } // NewProjectSetOptions creates a ProjectSetOptions instance -func NewProjectSetOptions() *ProjectSetOptions { - return &ProjectSetOptions{} +func NewProjectSetOptions(prjClient project.Client) *ProjectSetOptions { + return &ProjectSetOptions{ + prjClient: prjClient, + } } // Complete completes ProjectSetOptions after they've been created @@ -64,7 +70,7 @@ func (pso *ProjectSetOptions) Complete(name string, cmdline cmdline.Cmdline, arg // Validate validates the parameters of the ProjectSetOptions func (pso *ProjectSetOptions) Validate() (err error) { - exists, err := project.Exists(pso.Context.KClient, pso.projectName) + exists, err := pso.prjClient.Exists(pso.projectName) if kerrors.IsForbidden(err) { return &odoerrors.Unauthorized{} } @@ -78,7 +84,7 @@ func (pso *ProjectSetOptions) Validate() (err error) { // Run runs the project set command func (pso *ProjectSetOptions) Run() (err error) { current := pso.GetProject() - err = project.SetCurrent(pso.Context.KClient, pso.projectName) + err = pso.prjClient.SetCurrent(pso.projectName) if err != nil { return err } @@ -96,7 +102,9 @@ func (pso *ProjectSetOptions) Run() (err error) { // NewCmdProjectSet creates the project set command func NewCmdProjectSet(name, fullName string) *cobra.Command { - o := NewProjectSetOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewProjectSetOptions(project.NewClient(kubclient)) projectSetCmd := &cobra.Command{ Use: name, diff --git a/pkg/odo/cli/url/create.go b/pkg/odo/cli/url/create.go index ea71bebc952..01b4d9ef4c0 100644 --- a/pkg/odo/cli/url/create.go +++ b/pkg/odo/cli/url/create.go @@ -6,6 +6,7 @@ import ( devfilev1 "github.com/devfile/api/v2/pkg/apis/workspaces/v1alpha2" "github.com/pkg/errors" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/localConfigProvider" "github.com/redhat-developer/odo/pkg/log" "github.com/redhat-developer/odo/pkg/machineoutput" @@ -14,6 +15,7 @@ import ( "github.com/redhat-developer/odo/pkg/odo/genericclioptions" odoutil "github.com/redhat-developer/odo/pkg/odo/util" "github.com/redhat-developer/odo/pkg/odo/util/completion" + "github.com/redhat-developer/odo/pkg/project" "github.com/redhat-developer/odo/pkg/url" "github.com/redhat-developer/odo/pkg/util" @@ -75,8 +77,8 @@ type CreateOptions struct { } // NewURLCreateOptions creates a new CreateOptions instance -func NewURLCreateOptions() *CreateOptions { - return &CreateOptions{PushOptions: clicomponent.NewPushOptions()} +func NewURLCreateOptions(prjClient project.Client) *CreateOptions { + return &CreateOptions{PushOptions: clicomponent.NewPushOptions(prjClient)} } // Complete completes CreateOptions after they've been Created @@ -193,7 +195,9 @@ func (o *CreateOptions) Run() (err error) { // NewCmdURLCreate implements the odo url create command. func NewCmdURLCreate(name, fullName string) *cobra.Command { - o := NewURLCreateOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewURLCreateOptions(project.NewClient(kubclient)) urlCreateCmd := &cobra.Command{ Use: name + " [url name]", Short: urlCreateShortDesc, diff --git a/pkg/odo/cli/url/delete.go b/pkg/odo/cli/url/delete.go index d688b2b7494..6d8a9ea172a 100644 --- a/pkg/odo/cli/url/delete.go +++ b/pkg/odo/cli/url/delete.go @@ -3,6 +3,7 @@ package url import ( "fmt" + "github.com/redhat-developer/odo/pkg/kclient" "github.com/redhat-developer/odo/pkg/log" clicomponent "github.com/redhat-developer/odo/pkg/odo/cli/component" "github.com/redhat-developer/odo/pkg/odo/cli/ui" @@ -10,6 +11,7 @@ import ( "github.com/redhat-developer/odo/pkg/odo/genericclioptions" odoutil "github.com/redhat-developer/odo/pkg/odo/util" "github.com/redhat-developer/odo/pkg/odo/util/completion" + "github.com/redhat-developer/odo/pkg/project" "github.com/spf13/cobra" ktemplates "k8s.io/kubectl/pkg/util/templates" ) @@ -38,8 +40,8 @@ type DeleteOptions struct { } // NewURLDeleteOptions creates a new DeleteOptions instance -func NewURLDeleteOptions() *DeleteOptions { - return &DeleteOptions{PushOptions: clicomponent.NewPushOptions()} +func NewURLDeleteOptions(prjClient project.Client) *DeleteOptions { + return &DeleteOptions{PushOptions: clicomponent.NewPushOptions(prjClient)} } // Complete completes DeleteOptions after they've been Deleted @@ -104,7 +106,9 @@ func (o *DeleteOptions) Run() (err error) { // NewCmdURLDelete implements the odo url delete command. func NewCmdURLDelete(name, fullName string) *cobra.Command { - o := NewURLDeleteOptions() + // The error is not handled at this point, it will be handled during Context creation + kubclient, _ := kclient.New() + o := NewURLDeleteOptions(project.NewClient(kubclient)) urlDeleteCmd := &cobra.Command{ Use: name + " [url name]", Short: urlDeleteShortDesc, diff --git a/pkg/project/kubernetes.go b/pkg/project/kubernetes.go new file mode 100644 index 00000000000..2db4818bd20 --- /dev/null +++ b/pkg/project/kubernetes.go @@ -0,0 +1,142 @@ +package project + +import ( + "github.com/pkg/errors" + + "github.com/redhat-developer/odo/pkg/kclient" +) + +type kubernetesClient struct { + client kclient.ClientInterface +} + +func NewClient(client kclient.ClientInterface) Client { + return kubernetesClient{ + client: client, + } +} + +// SetCurrent sets projectName as the current project +func (o kubernetesClient) SetCurrent(projectName string) error { + err := o.client.SetCurrentNamespace(projectName) + if err != nil { + return errors.Wrap(err, "unable to set current project to"+projectName) + } + return nil +} + +// Create a new project, either by creating a `project.openshift.io` resource if supported by the cluster +// (which will trigger the creation of a namespace), +// or by creating directly a `namespace` resource. +// With the `wait` flag, the function will wait for the `default` service account +// to be created in the namespace before to return. +func (o kubernetesClient) Create(projectName string, wait bool) error { + if projectName == "" { + return errors.Errorf("no project name given") + } + + projectSupport, err := o.client.IsProjectSupported() + if err != nil { + return errors.Wrap(err, "unable to detect project support") + } + if projectSupport { + err = o.client.CreateNewProject(projectName, wait) + if err != nil { + return errors.Wrap(err, "unable to create new project") + } + + } else { + _, err = o.client.CreateNamespace(projectName) + if err != nil { + return errors.Wrap(err, "unable to create new project") + } + } + + if wait { + err = o.client.WaitForServiceAccountInNamespace(projectName, "default") + if err != nil { + return errors.Wrap(err, "unable to wait for service account") + } + } + return nil +} + +// Delete deletes the project (the `project` resource if supported, or directly the `namespace`) +// with the name projectName and returns an error if any +func (o kubernetesClient) Delete(projectName string, wait bool) error { + if projectName == "" { + return errors.Errorf("no project name given") + } + + projectSupport, err := o.client.IsProjectSupported() + if err != nil { + return errors.Wrap(err, "unable to detect project support") + } + + if projectSupport { + // Delete the requested project + err := o.client.DeleteProject(projectName, wait) + if err != nil { + return errors.Wrapf(err, "unable to delete project %s", projectName) + } + } else { + err := o.client.DeleteNamespace(projectName, wait) + if err != nil { + return errors.Wrapf(err, "unable to delete namespace %s", projectName) + } + } + return nil +} + +// List all the projects on the cluster and returns an error if any +func (o kubernetesClient) List() (ProjectList, error) { + currentProject := o.client.GetCurrentNamespace() + + projectSupport, err := o.client.IsProjectSupported() + if err != nil { + return ProjectList{}, errors.Wrap(err, "unable to detect project support") + } + + var allProjects []string + if projectSupport { + allProjects, err = o.client.ListProjectNames() + if err != nil { + return ProjectList{}, errors.Wrap(err, "cannot get all the projects") + } + } else { + allProjects, err = o.client.GetNamespaces() + if err != nil { + return ProjectList{}, errors.Wrap(err, "cannot get all the namespaces") + } + } + + projects := make([]Project, len(allProjects)) + for i, project := range allProjects { + isActive := project == currentProject + projects[i] = NewProject(project, isActive) + } + + return NewProjectList(projects), nil +} + +// Exists checks whether a project with the name `projectName` exists and returns an error if any +func (o kubernetesClient) Exists(projectName string) (bool, error) { + projectSupport, err := o.client.IsProjectSupported() + if err != nil { + return false, errors.Wrap(err, "unable to detect project support") + } + + if projectSupport { + project, err := o.client.GetProject(projectName) + if err != nil || project == nil { + return false, err + } + } else { + namespace, err := o.client.GetNamespace(projectName) + if err != nil || namespace == nil { + return false, err + } + } + + return true, nil +} diff --git a/pkg/project/project_test.go b/pkg/project/kubernetes_test.go similarity index 96% rename from pkg/project/project_test.go rename to pkg/project/kubernetes_test.go index 13d68de11be..18fb4b95503 100644 --- a/pkg/project/project_test.go +++ b/pkg/project/kubernetes_test.go @@ -62,6 +62,7 @@ func TestCreate(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) kc := kclient.NewMockClientInterface(ctrl) + appClient := NewClient(kc) if tt.expectedErr == false { kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr) @@ -75,7 +76,7 @@ func TestCreate(t *testing.T) { } } - err := Create(kc, tt.projectName, tt.wait) + err := appClient.Create(tt.projectName, tt.wait) if err != nil != tt.expectedErr { t.Errorf("expected error %v, got %v", tt.expectedErr, err) @@ -136,6 +137,7 @@ func TestDelete(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) kc := kclient.NewMockClientInterface(ctrl) + appClient := NewClient(kc) if tt.expectedErr == false { kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr) @@ -146,7 +148,7 @@ func TestDelete(t *testing.T) { } } - err := Delete(kc, tt.projectName, tt.wait) + err := appClient.Delete(tt.projectName, tt.wait) if err != nil != tt.expectedErr { t.Errorf("expected error %v, got %v", tt.expectedErr, err) @@ -214,6 +216,7 @@ func TestList(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) kc := kclient.NewMockClientInterface(ctrl) + appClient := NewClient(kc) kc.EXPECT().GetCurrentNamespace().Times(1) @@ -226,7 +229,7 @@ func TestList(t *testing.T) { } } - list, err := List(kc) + list, err := appClient.List() if err != nil != tt.expectedErr { t.Errorf("expected error %v, got %v", tt.expectedErr, err) @@ -269,6 +272,7 @@ func TestExists(t *testing.T) { t.Run(tt.name, func(t *testing.T) { ctrl := gomock.NewController(t) kc := kclient.NewMockClientInterface(ctrl) + appClient := NewClient(kc) if tt.expectedErr == false { kc.EXPECT().IsProjectSupported().Return(tt.isProjectSupported, tt.isProjectSupportedErr) @@ -279,7 +283,7 @@ func TestExists(t *testing.T) { } } - _, err := Exists(kc, tt.projectName) + _, err := appClient.Exists(tt.projectName) if err != nil != tt.expectedErr { t.Errorf("expected error %v, got %v", tt.expectedErr, err) diff --git a/pkg/project/project.go b/pkg/project/project.go index 64cf118e7ce..44a00739925 100644 --- a/pkg/project/project.go +++ b/pkg/project/project.go @@ -1,131 +1,9 @@ package project -import ( - "github.com/pkg/errors" - "github.com/redhat-developer/odo/pkg/kclient" -) - -// SetCurrent sets projectName as the current project -func SetCurrent(client kclient.ClientInterface, projectName string) error { - err := client.SetCurrentNamespace(projectName) - if err != nil { - return errors.Wrap(err, "unable to set current project to"+projectName) - } - return nil -} - -// Create a new project, either by creating a `project.openshift.io` resource if supported by the cluster -// (which will trigger the creation of a namespace), -// or by creating directly a `namespace` resource. -// With the `wait` flag, the function will wait for the `default` service account -// to be created in the namespace before to return. -func Create(client kclient.ClientInterface, projectName string, wait bool) error { - if projectName == "" { - return errors.Errorf("no project name given") - } - - projectSupport, err := client.IsProjectSupported() - if err != nil { - return errors.Wrap(err, "unable to detect project support") - } - if projectSupport { - err = client.CreateNewProject(projectName, wait) - if err != nil { - return errors.Wrap(err, "unable to create new project") - } - - } else { - _, err = client.CreateNamespace(projectName) - if err != nil { - return errors.Wrap(err, "unable to create new project") - } - } - - if wait { - err = client.WaitForServiceAccountInNamespace(projectName, "default") - if err != nil { - return errors.Wrap(err, "unable to wait for service account") - } - } - return nil -} - -// Delete deletes the project (the `project` resource if supported, or directly the `namespace`) -// with the name projectName and returns an error if any -func Delete(client kclient.ClientInterface, projectName string, wait bool) error { - if projectName == "" { - return errors.Errorf("no project name given") - } - - projectSupport, err := client.IsProjectSupported() - if err != nil { - return errors.Wrap(err, "unable to detect project support") - } - - if projectSupport { - // Delete the requested project - err := client.DeleteProject(projectName, wait) - if err != nil { - return errors.Wrapf(err, "unable to delete project %s", projectName) - } - } else { - err := client.DeleteNamespace(projectName, wait) - if err != nil { - return errors.Wrapf(err, "unable to delete namespace %s", projectName) - } - } - return nil -} - -// List all the projects on the cluster and returns an error if any -func List(client kclient.ClientInterface) (ProjectList, error) { - currentProject := client.GetCurrentNamespace() - - projectSupport, err := client.IsProjectSupported() - if err != nil { - return ProjectList{}, errors.Wrap(err, "unable to detect project support") - } - - var allProjects []string - if projectSupport { - allProjects, err = client.ListProjectNames() - if err != nil { - return ProjectList{}, errors.Wrap(err, "cannot get all the projects") - } - } else { - allProjects, err = client.GetNamespaces() - if err != nil { - return ProjectList{}, errors.Wrap(err, "cannot get all the namespaces") - } - } - - projects := make([]Project, len(allProjects)) - for i, project := range allProjects { - isActive := project == currentProject - projects[i] = NewProject(project, isActive) - } - - return NewProjectList(projects), nil -} - -// Exists checks whether a project with the name `projectName` exists and returns an error if any -func Exists(client kclient.ClientInterface, projectName string) (bool, error) { - projectSupport, err := client.IsProjectSupported() - if err != nil { - return false, errors.Wrap(err, "unable to detect project support") - } - - if projectSupport { - project, err := client.GetProject(projectName) - if err != nil || project == nil { - return false, err - } - } else { - namespace, err := client.GetNamespace(projectName) - if err != nil || namespace == nil { - return false, err - } - } - - return true, nil +type Client interface { + SetCurrent(projectName string) error + Create(projectName string, wait bool) error + Delete(projectName string, wait bool) error + List() (ProjectList, error) + Exists(projectName string) (bool, error) }