diff --git a/Dockerfile b/Dockerfile index bedb4262097879c2f2429853929755dd84e52b70..b3cd263df3bfaf8e3073a3165daa340abd5e5722 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,6 +1,6 @@ # NOTE: USING THIS IMAGE UNTIL registry1 credentials are added to IL2 runners # Build the manager binary -FROM registry.il2.dso.mil/platform-one/devops/pipeline-templates/valkyrie/golang-builder-1.6:1.0 as builder +FROM registry.il2.dso.mil/platform-one/devops/pipeline-templates/pipeline-job/golang-builder-1.6:1.0 as builder WORKDIR /workspace # Copy the Go Modules manifests diff --git a/apis/gitlab/v1alpha1/project_types.go b/apis/gitlab/v1alpha1/project_types.go index 2cd50a0ff92390f0fbfa7ea5f3a766d182a08190..af6abe31335252eb95f96f8a7624d4462de959ef 100644 --- a/apis/gitlab/v1alpha1/project_types.go +++ b/apis/gitlab/v1alpha1/project_types.go @@ -60,6 +60,9 @@ type ProjectSpec struct { type ProjectStatus struct { // URL is the url for the project in GitLab URL string `json:"url"` + + // State is the current state of the object + State string `json:"state"` } //+kubebuilder:object:root=true diff --git a/clients/gitlab/client.go b/clients/gitlab/client.go index 42fb342b2b78360c564a63161dc8b110944a5e23..26fd3526924f8f018eb5dd826c5587fdbd38df2f 100644 --- a/clients/gitlab/client.go +++ b/clients/gitlab/client.go @@ -264,9 +264,7 @@ func (r Client) DeleteUser(userID int, waitInterval int, waitCount int) (int, er } // DeleteUserByUsername - convenience method -func (r Client) DeleteUserByUsername(username string, waitInterval int, waitCount int) (int, error) { - // waiting will be skilled if waitCount is 0 - // setting wait will use a loop to wait until resource has completed deletion +func (r Client) DeleteUserByUsername(username string) (int, error) { // expect return status code of http.StatusNoContent 204 or http.StatusNotFound 404 logPrefix := "Completed call to DeleteUserByUsername." @@ -285,7 +283,7 @@ func (r Client) DeleteUserByUsername(username string, waitInterval int, waitCoun return statusCode, nil } - statusCode, err := r.DeleteUser(users[0].ID, waitInterval, waitCount) + statusCode, err := r.DeleteUser(users[0].ID, 0, 0) if err != nil { processError(logPrefix, err) diff --git a/clients/gitlab/client_test.go b/clients/gitlab/client_test.go index 5c9e86d2345b67ca89e9946a60798f1acec9528c..bdb96d73a8b977bf27a773d677789edb1eeb7b59 100644 --- a/clients/gitlab/client_test.go +++ b/clients/gitlab/client_test.go @@ -406,7 +406,7 @@ func TestClient_DeleteUser(t *testing.T) { token: tt.fields.token, apiURL: tt.fields.apiURL, } - got, err := r.DeleteUser(tt.args.userID, 1000, 10) + got, err := r.DeleteUser(tt.args.userID) if (err != nil) != tt.wantErr { t.Errorf("Client.DeleteUser() error = %v, wantErr %v", err, tt.wantErr) return @@ -476,7 +476,7 @@ func TestClient_DeleteUserByUsername(t *testing.T) { token: tt.fields.token, apiURL: tt.fields.apiURL, } - got, err := r.DeleteUserByUsername(tt.args.username, 0, 0) + got, err := r.DeleteUserByUsername(tt.args.username) if (err != nil) != tt.wantErr { t.Errorf("Client.DeleteUserByUsername() error = %v, wantErr %v", err, tt.wantErr) return @@ -718,13 +718,7 @@ func TestClient_DeleteGroup(t *testing.T) { ) httpmock.RegisterResponder("GET", `=~^https://test/api/v4/groups.*`, - func(req *http.Request) (*http.Response, error) { - counter = counter + 1 - if counter%4 == 0 { - return httpmock.NewJsonResponse(404, testGroup1) - } - return httpmock.NewJsonResponse(202, testGroup1) - }, + httpmock.NewJsonResponderOrPanic(200, testGroupArray), ) // test objects @@ -764,7 +758,7 @@ func TestClient_DeleteGroup(t *testing.T) { token: tt.fields.token, apiURL: tt.fields.apiURL, } - got, err := r.DeleteGroup(tt.args.groupID, 1000, 10) + got, err := r.DeleteGroup(tt.args.groupID) if (err != nil) != tt.wantErr { t.Errorf("Client.DeleteGroup() error = %v, wantErr %v", err, tt.wantErr) return diff --git a/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml b/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml index ee5f57aad84a5bac7a0be37b4152e2fe211d6810..2e29585e44899057195631c86ced887ee9dbf9f6 100644 --- a/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml +++ b/config/crd/bases/gitlab.valkyrie.dso.mil_projects.yaml @@ -87,10 +87,14 @@ spec: status: description: ProjectStatus defines the observed state of Project properties: + state: + description: State is the current state of the object + type: string url: description: URL is the url for the project in GitLab type: string required: + - state - url type: object type: object diff --git a/controllers/gitlab/gitlab_client.go b/controllers/gitlab/gitlab_client.go index 57999a45219a1679388f6482a674d5e3463ecc11..9db79bf5e8cd1ba4fa4fee4e99ec5c33053146cc 100644 --- a/controllers/gitlab/gitlab_client.go +++ b/controllers/gitlab/gitlab_client.go @@ -9,6 +9,7 @@ type Client interface { ListGroupsByName(name string) ([]*gitlab.Group, *gitlab.Response, error) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) UpdateGroup(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) + GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) } // ClientImpl is the Default implementation for the facade. @@ -45,7 +46,7 @@ func (c ClientImpl) CreateGroup(name string, description string) (*gitlab.Group, return c.client.Groups.CreateGroup(&opt) } -// UpdateGroup is a facade for the go-gitlab client.Group.UpdateGroup +// UpdateGroup is a facade for the go-gitlab client.Groups.UpdateGroup func (c ClientImpl) UpdateGroup(id string, name string, descrption string) (*gitlab.Group, *gitlab.Response, error) { opt := gitlab.UpdateGroupOptions{ Name: &name, @@ -53,3 +54,8 @@ func (c ClientImpl) UpdateGroup(id string, name string, descrption string) (*git } return c.client.Groups.UpdateGroup(id, &opt) } + +// GetGroup is a facade for go-gitlab client.Groups.GetGroup +func (c ClientImpl) GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) { + return c.client.Groups.GetGroup(groupID) +} diff --git a/controllers/gitlab/group_controller_test.go b/controllers/gitlab/group_controller_test.go index 2c0e40728722df9516ff34748ff0e61dfacb80bc..84fdeb7355305ef6c57996654fa125495530bdb4 100755 --- a/controllers/gitlab/group_controller_test.go +++ b/controllers/gitlab/group_controller_test.go @@ -26,7 +26,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} clientMock.expectedObjects = make(map[client.ObjectKey]client.Object) @@ -48,6 +48,7 @@ var _ = Describe("Reconcile", func() { }) }) }) + var _ = Describe("Reconcile", func() { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) scheme, _ := builder.Build() @@ -60,7 +61,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -96,6 +97,7 @@ var _ = Describe("Reconcile", func() { }) }) }) + var _ = Describe("Reconcile", func() { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) scheme, _ := builder.Build() @@ -108,7 +110,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -163,6 +165,7 @@ var _ = Describe("Reconcile", func() { }) }) }) + var _ = Describe("Reconcile", func() { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) scheme, _ := builder.Build() @@ -175,7 +178,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -262,7 +265,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -374,7 +377,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -513,6 +516,7 @@ var _ = Describe("Reconcile", func() { }) }) }) + var _ = Describe("Reconcile", func() { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Group{}, &gitlabv1alpha1.GroupList{}) scheme, _ := builder.Build() @@ -524,7 +528,7 @@ var _ = Describe("Reconcile", func() { WithNameCalled: false, } contextMock := context.TODO() - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} requestMock := ctrl.Request{} @@ -942,6 +946,7 @@ var _ = Describe("groupExists", func() { }) }) }) + var _ = Describe("createGroup", func() { expectedGroup := &gitlab.Group{ID: 1, Name: "A test group"} expectedResponse := &gitlab.Response{ @@ -1028,7 +1033,7 @@ var _ = Describe("SetupWithManager", func() { WithNameValue: "", WithNameCalled: false, } - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} sut := GroupReconciler{ @@ -1058,7 +1063,7 @@ var _ = Describe("updateStatus", func() { WithNameValue: "", WithNameCalled: false, } - clientMock := MockClient{statusWriter: MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + clientMock := MockClient{statusWriter: &MockStatusWriter{updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }}} sut := GroupReconciler{ @@ -1104,7 +1109,7 @@ var _ = Describe("updateProject", func() { } mockError := &MockError{"true"} clientMock := MockClient{ - statusWriter: MockStatusWriter{ + statusWriter: &MockStatusWriter{ updateFunction: func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { return nil }, diff --git a/controllers/gitlab/mocks_test.go b/controllers/gitlab/mocks_test.go index 4c1d10580d4ce9baa076f52a27fc2171a7856916..bde2409714d2981413e818021f9b6f6399f71b04 100755 --- a/controllers/gitlab/mocks_test.go +++ b/controllers/gitlab/mocks_test.go @@ -99,17 +99,23 @@ func (m *MockClient) DeleteAllOf(ctx context.Context, obj client.Object, opts .. type MockStatusWriter struct { updateFunction func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error + updateFunctionCalled bool patchFunction func(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error + updatedObject client.Object + updatedOptions []client.UpdateOption } -func (m MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { +func (m *MockStatusWriter) Update(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error { + m.updateFunctionCalled = true if m.updateFunction == nil { + m.updatedObject = obj + m.updatedOptions = opts return nil } return m.updateFunction(ctx, obj, opts...) } -func (m MockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { +func (m *MockStatusWriter) Patch(ctx context.Context, obj client.Object, patch client.Patch, opts ...client.PatchOption) error { if m.patchFunction == nil { return nil } @@ -412,6 +418,20 @@ type MockGitlabClient struct { listGroupsByNameFunction func(name string) ([]*gitlab.Group, *gitlab.Response, error) createGroupFunction func(name string, description string) (*gitlab.Group, *gitlab.Response, error) updateGroupFunction func(id string, name string, description string) (*gitlab.Group, *gitlab.Response, error) + getGroupFunction func(groupID int64) (*gitlab.Group, *gitlab.Response, error) + expectedGroups map[int64]*gitlab.Group +} + +func (m *MockGitlabClient) GetGroup(groupID int64) (*gitlab.Group, *gitlab.Response, error) { + if m.getGroupFunction != nil { + return m.getGroupFunction(groupID) + } + + if m.expectedGroups == nil { + m.expectedGroups = make(map[int64]*gitlab.Group) + } + + return m.expectedGroups[groupID], nil, nil } func (m *MockGitlabClient) CreateGroup(name string, description string) (*gitlab.Group, *gitlab.Response, error) { diff --git a/controllers/gitlab/project_controller.go b/controllers/gitlab/project_controller.go index 1109f5304f1c6d2a4934ba3f7aa672de5f1668aa..aa0974e37d3ba8e162f71b073c4dbb155bd9214e 100644 --- a/controllers/gitlab/project_controller.go +++ b/controllers/gitlab/project_controller.go @@ -19,10 +19,10 @@ package gitlab import ( "context" "github.com/go-logr/logr" + "github.com/xanzy/go-gitlab" "k8s.io/apimachinery/pkg/runtime" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/client" - gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" ) @@ -38,33 +38,48 @@ type ProjectReconciler struct { //+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=projects/status,verbs=get;update;patch //+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=projects/finalizers,verbs=update -// Reconcile is part of the main kubernetes reconciliation loop which aims to -// move the current state of the cluster closer to the desired state. -// TODO(user): Modify the Reconcile function to compare the state specified by -// the Project object against the actual cluster state, and then -// perform operations to make the cluster state reflect the state specified by -// the user. -// -// For more details, check Reconcile and its Result here: -// - https://pkg.go.dev/sigs.k8s.io/controller-runtime@v0.7.2/pkg/reconcile - // errors const ( errorWhileLookingUpProject string = "error while looking up project" + errorGettingGroupFromGitlab string = "Error while getting Group from Gitlab." + errorUpdatingStatusOfProject = "Error updating status of project" +) + +// statuses +const ( + groupDoesntExist string = "GitlabGroupDoesNotExist" ) -// Reconcile is the main reconcilation loop that will create/edit/delete Gitlab Projects. +// Reconcile is the main reconciliation loop that will create/edit/delete Gitlab Projects. func (r *ProjectReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { _ = r.Log.WithValues("project", req.NamespacedName) - if _, err := r.getProject(ctx, req); err != nil { + var err error + var project *gitlabv1alpha1.Project + + if project, err = r.getProject(ctx, req); err != nil { r.Log.Error(err, errorWhileLookingUpProject, "request", req) return ctrl.Result{Requeue: client.IgnoreNotFound(err) != nil}, client.IgnoreNotFound(err) } + if _, err = r.getGroup(project.Spec.GroupID); err != nil { + r.Log.Error(err, errorGettingGroupFromGitlab, "request", req) + r.updateStatus(ctx, project, groupDoesntExist) + return ctrl.Result{Requeue: true}, err + } + return ctrl.Result{}, nil } +func (r *ProjectReconciler) updateStatus(ctx context.Context, project *gitlabv1alpha1.Project, status string) error { + project.Status.State = status + if err := r.Status().Update(ctx, project); err != nil { + r.Log.Error(err, errorUpdatingStatusOfProject, "project", project, "status", status) + return err + } + return nil +} + // SetupWithManager sets up the controller with the Manager. func (r *ProjectReconciler) SetupWithManager(mgr ctrl.Manager) error { r.gitlabClient = ClientImpl{} @@ -85,3 +100,16 @@ func (r *ProjectReconciler) getProject(ctx context.Context, request ctrl.Request } return &project, nil } + +func (r *ProjectReconciler) getGroup(groupID int64) (*gitlab.Group, error) { + var group *gitlab.Group + var response *gitlab.Response + var err error + if group, response, err = r.gitlabClient.GetGroup(groupID); err != nil { + + r.Log.Error(err, errorGettingGroupFromGitlab, "response", response, "groupID", groupID) + return nil, err + } + + return group, nil +} diff --git a/controllers/gitlab/project_controller_test.go b/controllers/gitlab/project_controller_test.go index e79344f9d2e982bd835f7ed0617fb1be91c69eb4..0668288f23a36c0de4b263068ab31dc3a0b5088a 100644 --- a/controllers/gitlab/project_controller_test.go +++ b/controllers/gitlab/project_controller_test.go @@ -4,6 +4,7 @@ import ( "context" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" + "github.com/xanzy/go-gitlab" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/types" ctrl "sigs.k8s.io/controller-runtime" @@ -11,10 +12,21 @@ import ( gitlabv1alpha1 "valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1" ) -func getControllerWithMocksInGreenTestState() (ProjectReconciler, *MockManager, *MockLogger) { +func getGreenRequest() ctrl.Request { + request := ctrl.Request{ + NamespacedName: types.NamespacedName{ + Namespace: "default", + Name: "TestProject", + }, + } + return request +} + +func getControllerWithMocksInGreenTestState() (ProjectReconciler, *MockManager, *MockLogger, *MockStatusWriter) { builder := gitlabv1alpha1.SchemeBuilder.Register(&gitlabv1alpha1.Project{}, &gitlabv1alpha1.ProjectList{}) scheme, _ := builder.Build() + mockStatusWriter := MockStatusWriter{} loggerMock := MockLogger{ WithValuesKeysAndValues: nil, WithValuesCalled: false, @@ -22,7 +34,7 @@ func getControllerWithMocksInGreenTestState() (ProjectReconciler, *MockManager, WithNameCalled: false, } clientMock := MockClient{ - statusWriter: MockStatusWriter{}, + statusWriter: &mockStatusWriter, expectedObjects: make(map[client.ObjectKey]client.Object), } clientMock.expectedObjects[getRequestWithDefaultNamespacedTestProject().NamespacedName] = &gitlabv1alpha1.Project{ @@ -40,19 +52,25 @@ func getControllerWithMocksInGreenTestState() (ProjectReconciler, *MockManager, ServicePort: 8081, Language: "golang", }, - Status: gitlabv1alpha1.ProjectStatus{}, + Status: gitlabv1alpha1.ProjectStatus{ + URL: "", + State: "", + }, } mockManager := &MockManager{ Log: &loggerMock, builder: builder, } + gitlabClient := MockGitlabClient{} + sut := ProjectReconciler{ Client: &clientMock, Log: &loggerMock, Scheme: scheme, } - return sut, mockManager, &loggerMock + sut.gitlabClient = &gitlabClient + return sut, mockManager, &loggerMock, &mockStatusWriter } func getRequestWithDefaultNamespacedTestProject() ctrl.Request { @@ -65,7 +83,7 @@ func getRequestWithDefaultNamespacedTestProject() ctrl.Request { } var _ = Describe("SetupWithManager", func() { - sut, mgr, _ := getControllerWithMocksInGreenTestState() + sut, mgr, _, _ := getControllerWithMocksInGreenTestState() err := sut.SetupWithManager(mgr) @@ -79,7 +97,7 @@ var _ = Describe("SetupWithManager", func() { var _ = Describe("reconcile", func() { Context("green state", func() { - sut, _, _ := getControllerWithMocksInGreenTestState() + sut, _, _, _ := getControllerWithMocksInGreenTestState() request := getRequestWithDefaultNamespacedTestProject() result, err := sut.Reconcile(context.TODO(), request) It("should return an empty result", func() { @@ -90,7 +108,7 @@ var _ = Describe("reconcile", func() { }) }) Context("project isn't found", func() { - sut, _, log := getControllerWithMocksInGreenTestState() + sut, _, log, _ := getControllerWithMocksInGreenTestState() request := getRequestWithDefaultNamespacedTestProject() request.NamespacedName.Name = "not going to find it" result, err := sut.Reconcile(context.TODO(), request) @@ -105,7 +123,7 @@ var _ = Describe("reconcile", func() { }) }) Context("getProject returns an error", func() { - sut, _, log := getControllerWithMocksInGreenTestState() + sut, _, log, _ := getControllerWithMocksInGreenTestState() failingClient := MockClient{ GetFunction: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { return &MockError{ @@ -131,11 +149,38 @@ var _ = Describe("reconcile", func() { Expect(log.loggedMessage).To(Equal(errorWhileLookingUpProject)) }) }) + Context("getGroup returns an error", func() { + failingGitlabClient := MockGitlabClient{ + getGroupFunction: func(groupID int64) (*gitlab.Group, *gitlab.Response, error) { + return nil, &gitlab.Response{}, &MockError{ + message: "failure in getGroup", + } + }, + } + sut, _, log, status := getControllerWithMocksInGreenTestState() + sut.gitlabClient = &failingGitlabClient + + request := getGreenRequest() + + result, err := sut.Reconcile(context.TODO(), request) + It("should return an error", func() { + Expect(err).ToNot(BeNil()) + }) + It("should requeue the object", func() { + Expect(result).To(Equal(ctrl.Result{Requeue: true})) + }) + It("should log that there was an error while looking up the group in gitlab", func() { + Expect(log.loggedMessage).To(Equal(errorGettingGroupFromGitlab)) + }) + It("should set the project status to GroupDoesntExist", func() { + Expect(status.updateFunctionCalled).To(BeTrue()) + }) + }) }) var _ = Describe("getProject", func() { Context("green state", func() { - sut, _, _ := getControllerWithMocksInGreenTestState() + sut, _, _, _ := getControllerWithMocksInGreenTestState() request := getRequestWithDefaultNamespacedTestProject() project, err := sut.getProject(context.TODO(), request) It("should return a project from the client", func() { @@ -147,7 +192,7 @@ var _ = Describe("getProject", func() { }) }) Context("object is not found.", func() { - sut, _, _ := getControllerWithMocksInGreenTestState() + sut, _, _, _ := getControllerWithMocksInGreenTestState() request := ctrl.Request{ NamespacedName: types.NamespacedName{ Namespace: "default", @@ -164,7 +209,7 @@ var _ = Describe("getProject", func() { }) }) Context("an error occurs", func() { - sut, _, _ := getControllerWithMocksInGreenTestState() + sut, _, _, _ := getControllerWithMocksInGreenTestState() failingClient := MockClient{ GetFunction: func(ctx context.Context, key client.ObjectKey, obj client.Object) error { return &MockError{ @@ -191,6 +236,34 @@ var _ = Describe("getProject", func() { var _ = Describe("getGroup", func() { Context("green state", func() { - + var fakeGroupID = int64(1) + sut, _, _, _ := getControllerWithMocksInGreenTestState() + group, err := sut.getGroup(fakeGroupID) + It("should return a group, and no error.", func() { + Expect(group).To(BeAssignableToTypeOf(&gitlab.Group{})) + Expect(err).To(BeNil()) + }) + }) + Context("gitlab client returns error", func() { + var fakeGroupID = int64(1) + failingGitlabClient := MockGitlabClient{ + getGroupFunction: func(groupID int64) (*gitlab.Group, *gitlab.Response, error) { + return nil, &gitlab.Response{}, &MockError{ + message: "failure in getGroup", + } + }, + } + sut, _, log, _ := getControllerWithMocksInGreenTestState() + sut.gitlabClient = &failingGitlabClient + group, err := sut.getGroup(fakeGroupID) + It("should return an error", func() { + Expect(err).ToNot(BeNil()) + }) + It("should log the error", func() { + Expect(log.loggedMessage).To(Equal(errorGettingGroupFromGitlab)) + }) + It("should return no group", func() { + Expect(group).To(BeNil()) + }) }) }) diff --git a/controllers/twistlock/twistlockpipelineconfiguration_controller.go b/controllers/twistlock/twistlockpipelineconfiguration_controller.go index 5887060b6ebbbfcdfacff51d093fa481acf9a1a2..712dfeecf8b6001c79ae2c0872b3cb92fd76bdea 100644 --- a/controllers/twistlock/twistlockpipelineconfiguration_controller.go +++ b/controllers/twistlock/twistlockpipelineconfiguration_controller.go @@ -168,7 +168,7 @@ func (r *PipelineConfigurationReconciler) handleUpdate(ctx context.Context, twis return } -func (r *PipelineConfigurationReconciler) handleCreate(ctx context.Context, twistlockConfig twistlockv1alpha1.TwistlockPipelineConfiguration, +func (r *PipelineConfigurationReconciler) handleCrate(ctx context.Context, twistlockConfig twistlockv1alpha1.TwistlockPipelineConfiguration, log logr.Logger, tlc *twistlock.Client) (err error) { //if spec doesn't exist, we create it @@ -247,7 +247,7 @@ func (r *PipelineConfigurationReconciler) handleCreateOrUpdate(ctx context.Conte if needUpdate { err = r.handleUpdate(ctx, twistlockConfig, log, tlc, specsToUpdate) } else { - err = r.handleCreate(ctx, twistlockConfig, log, tlc) + err = r.handleCrate(ctx, twistlockConfig, log, tlc) } return } diff --git a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go index b07cf688a036694616b83a9f1d50dabc6fd9ce9e..b21e399c74ead84d0d5a8cb45083733477391648 100644 --- a/integration-tests/gitlab/api/gitlab_api_adhoc_test.go +++ b/integration-tests/gitlab/api/gitlab_api_adhoc_test.go @@ -3,19 +3,15 @@ package integration import ( + "testing" "errors" - "fmt" - "net/http" "os" - "testing" - gitlab "valkyrie.dso.mil/valkyrie-api/clients/gitlab" - "github.com/romana/rlog" gogitlab "github.com/xanzy/go-gitlab" ) -// getClient_AdHoc - +// getClient_AdHoc - func getClient_AdHoc() (gitlab.Client, error) { gitlabAPIURL, ok := os.LookupEnv("GITLAB_API_URL") if !ok { @@ -25,7 +21,7 @@ func getClient_AdHoc() (gitlab.Client, error) { if !ok { return gitlab.Client{}, errors.New("env variable GITLAB_API_TOKEN undefinded") } - var client = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken, nil) + var client = gitlab.NewClient(gitlabAPIURL, gitlabAPIToken,nil) return client, nil } func TestClient_AdHoc_getUsers_All(t *testing.T) { @@ -41,7 +37,7 @@ func TestClient_AdHoc_getUsers_All(t *testing.T) { return } t.Logf("GetUsers %d", len(got)) - for x := 0; x < len(got); x++ { + for x:=0;x>>>>>>> delete group %d", statusCode) - - } + groupName := "adam root" + groupPath := "adam-root" groupObj := gogitlab.Group{Name: groupName, Path: groupPath} - group, statusCode, err = c.AddGroup(&groupObj, nil) + group, statusCode, err := c.AddGroup(&groupObj, nil) if err != nil { t.Errorf("AddGroup error = %v", err) return } t.Logf("AddGroup: %s %d", group.FullPath, statusCode) - groupName = "adam subgroup1" - groupPath = "adam-subgroup1" - groupObj = gogitlab.Group{Name: groupName, Path: groupPath} - subgroup1, statusCode, err := c.AddGroup(&groupObj, &group.ID) - if err != nil { - t.Errorf("AddGroup error = %v", err) - return - } - t.Logf("AddGroup: %s %d", subgroup1.FullPath, statusCode) - - groupName = "adam subgroup2" - groupPath = "adam-subgroup2" + groupName = "adam subgroup" + groupPath = "adam-subgroup" groupObj = gogitlab.Group{Name: groupName, Path: groupPath} - subgroup2, statusCode, err := c.AddGroup(&groupObj, &group.ID) + subgroup, statusCode, err := c.AddGroup(&groupObj, &group.ID) if err != nil { t.Errorf("AddGroup error = %v", err) return @@ -210,15 +192,10 @@ func TestClient_AdHoc_addGroups_SubGroup(t *testing.T) { projectObj := gogitlab.CreateProjectOptions{Name: &projectName} got, statusCode, err := c.AddProject(projectObj, subgroup1.ID) - if err != nil { - t.Errorf("Client.AddProject() error = %v %d", err, statusCode) - } else { - t.Logf("AddProject: [%s, %s, %d]", got.NameWithNamespace, got.HTTPURLToRepo, statusCode) - } - } }) } + func TestClient_AdHoc_getProjects_ALL(t *testing.T) { t.Run("test", func(t *testing.T) { c, err := getClient_AdHoc() @@ -232,7 +209,7 @@ func TestClient_AdHoc_getProjects_ALL(t *testing.T) { return } t.Logf("GetProjects %d", len(got)) - for x := 0; x < len(got); x++ { + for x:=0;x -RLOG_LOG_LEVEL = WARN +RLOG_LOG_LEVEL = DEBUG RLOG_LOG_STREAM = stdout # time format - use ! to prevent override by environment variable RLOG_TIME_FORMAT="2006/01/06 15:04:05.00" # RLOG_TIME_FORMAT= UnixDate # optional list caller information -RLOG_CALLER_INFO= 0 +RLOG_CALLER_INFO= 1 # RLOG_LOG_FILE = /var/log/myapp.log