UNCLASSIFIED

Commit d1591d15 authored by Jason van Brackel's avatar Jason van Brackel
Browse files

refactor: Remove pipeline and pipeline reconciler from the APIs

parent 93c5bb4c
package v1alpha1
import (
"reflect"
"testing"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// Reusable test variables
type testVarsPipeline = struct {
testKind string
testApiversion string
testSpec string
testStatus string
expectedKind string
expectedApiversion string
expectedSpec string
expectedStatus string
testObject1 Pipeline
testObject2 Pipeline
objectItems1 []Pipeline
objectList1 PipelineList
objectItems2 []Pipeline
objectList2 PipelineList
// leave scaffold Foo value for testing?
testObjectSpec1 PipelineSpec
testObjectSpec2 PipelineSpec
// leave scaffold Foo value for testing?
testObjectStatus1 PipelineStatus
testObjectStatus2 PipelineStatus
}
func initVarsPipeline() testVarsPipeline {
testVars := testVarsPipeline{}
testVars.testKind = "TestKind"
testVars.testApiversion = "v22"
testVars.testSpec = "test spec value"
testVars.testStatus = "test status value"
testVars.expectedApiversion = testVars.testApiversion
testVars.expectedKind = testVars.testKind
testVars.expectedSpec = testVars.testSpec
testVars.expectedStatus = testVars.testStatus
var object1MetaType metav1.TypeMeta = metav1.TypeMeta{Kind: testVars.testKind, APIVersion: testVars.testApiversion}
testVars.testObject1 = Pipeline{TypeMeta: object1MetaType}
var object2MetaType metav1.TypeMeta = metav1.TypeMeta{Kind: "TestKind2", APIVersion: "V99"}
testVars.testObject2 = Pipeline{TypeMeta: object2MetaType}
var objectList1MetaType metav1.TypeMeta = metav1.TypeMeta{Kind: "TestKind_List", APIVersion: "V12"}
var objectItems1 []Pipeline = []Pipeline{testVars.testObject1, testVars.testObject2}
// test_object_list = PipelineList(objectList1MetaType,nil,object_items)
testVars.objectList1 = PipelineList{TypeMeta: objectList1MetaType, Items: objectItems1}
var objectList2MetaType metav1.TypeMeta = metav1.TypeMeta{Kind: "TestKind_List", APIVersion: "V12"}
var objectItems2 []Pipeline = []Pipeline{testVars.testObject2}
// test_object_list = PipelineList(objectList1MetaType,nil,object_items)
testVars.objectList2 = PipelineList{TypeMeta: objectList2MetaType, Items: objectItems2}
// leave scaffold Foo value for testing?
testVars.testObjectSpec1 = PipelineSpec{ProjectName: testVars.testSpec}
testVars.testObjectSpec2 = PipelineSpec{ProjectName: "other value"}
// leave scaffold Foo value for testing?
testVars.testObjectStatus1 = PipelineStatus{State: testVars.testStatus}
testVars.testObjectStatus2 = PipelineStatus{State: "other value"}
return testVars
}
func TestGroupVars_Pipeline(t *testing.T) {
xType := reflect.TypeOf(GroupVersion)
// convert object type to string
got := xType.String()
want := "schema.GroupVersion"
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
// Test Type called Pipeline
func TestTypes_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
want := lTestVars.expectedApiversion
got := lTestVars.testObject1.APIVersion
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
// DeepCopy
func TestDeepCopy_DeepCopy_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newObject := lTestVars.testObject1.DeepCopy()
// check api version
got := newObject.APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
// check kind
got = newObject.Kind
want = lTestVars.expectedKind
if got != want {
t.Errorf("got %s want %s", got, want)
}
var nilTestPtr *Pipeline = nil
var val = nilTestPtr.DeepCopyObject()
if val != nil {
t.Errorf("got %s want %s", "not nil", "nil")
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyInto_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
lTestVars.testObject1.DeepCopyInto(&lTestVars.testObject2)
got := lTestVars.testObject2.APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyObject_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newRuntimeObject := lTestVars.testObject1.DeepCopyObject()
newObject := newRuntimeObject.(*Pipeline)
got := newObject.APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyList_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newObjectList := lTestVars.objectList1.DeepCopy()
got := newObjectList.Items[0].APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
// a typed pointer set to nil
var nilTestPtr *PipelineList = nil
var val = nilTestPtr.DeepCopy()
if val != nil {
t.Errorf("got %s want %s", "not nil", "nil")
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyIntoList_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
lTestVars.objectList1.DeepCopyInto(&lTestVars.objectList2)
got := lTestVars.objectList2.Items[0].APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyListObject_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newRuntimeObject := lTestVars.objectList1.DeepCopyObject()
newObject := newRuntimeObject.(*PipelineList)
got := newObject.Items[0].APIVersion
want := lTestVars.expectedApiversion
if got != want {
t.Errorf("got %s want %s", got, want)
}
var nilTestPtr *PipelineList = nil
var val = nilTestPtr.DeepCopyObject()
if val != nil {
t.Errorf("got %s want %s", "not nil", "nil")
}
t.Log("Success")
}
func TestDeepCopy_DeepCopySpec_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newObjectList := lTestVars.testObjectSpec1.DeepCopy()
got := newObjectList.ProjectName
want := lTestVars.expectedSpec
if got != want {
t.Errorf("got %s want %s", got, want)
}
var nilTestPtr *PipelineSpec = nil
var val = nilTestPtr.DeepCopy()
if val != nil {
t.Errorf("got %s want %s", "not nil", "nil")
}
t.Log("Success")
}
func TestDeepCopy_DeepCopySpecInto_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
lTestVars.testObjectSpec1.DeepCopyInto(&lTestVars.testObjectSpec2)
got := lTestVars.testObjectSpec2.ProjectName
want := lTestVars.expectedSpec
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyStatus_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
newObjectStatus := lTestVars.testObjectStatus1.DeepCopy()
got := newObjectStatus.State
want := lTestVars.expectedStatus
if got != want {
t.Errorf("got %s want %s", got, want)
}
// a typed pointer set to nil
var nilTestPtr *PipelineStatus = nil
var val = nilTestPtr.DeepCopy()
if val != nil {
t.Errorf("got %s want %s", "not nil", "nil")
}
t.Log("Success")
}
func TestDeepCopy_DeepCopyStatusInto_Pipeline(t *testing.T) {
lTestVars := initVarsPipeline()
lTestVars.testObjectStatus1.DeepCopyInto(&lTestVars.testObjectStatus2)
got := lTestVars.testObjectStatus2.State
want := lTestVars.expectedStatus
if got != want {
t.Errorf("got %s want %s", got, want)
}
t.Log("Success")
}
/*
Copyright 2021.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package v1alpha1
import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
// EDIT THIS FILE! THIS IS SCAFFOLDING FOR YOU TO OWN!
// NOTE: json tags are required. Any new fields you add must have json tags for the fields to be serialized.
// PipelineSpec defines the desired state of Pipeline
type PipelineSpec struct {
// test dummy - do not remove
ProjectName string `json:"projectName,omitempty"`
}
// PipelineStatus defines the observed state of Pipeline
type PipelineStatus struct {
// State is the current state of the Pipeline, used mostly for error states.
State string `json:"state,omitempty"`
}
//+kubebuilder:object:root=true
//+kubebuilder:subresource:status
// Pipeline is the Schema for the pipelines API
type Pipeline struct {
metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata,omitempty"`
Spec PipelineSpec `json:"spec,omitempty"`
Status PipelineStatus `json:"status,omitempty"`
}
//+kubebuilder:object:root=true
// PipelineList contains a list of Pipeline
type PipelineList struct {
metav1.TypeMeta `json:",inline"`
metav1.ListMeta `json:"metadata,omitempty"`
Items []Pipeline `json:"items"`
}
func init() {
SchemeBuilder.Register(&Pipeline{}, &PipelineList{})
}
This diff is collapsed.
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.4.1
creationTimestamp: null
name: pipelines.gitlab.valkyrie.dso.mil
spec:
group: gitlab.valkyrie.dso.mil
names:
kind: Pipeline
listKind: PipelineList
plural: pipelines
singular: pipeline
scope: Namespaced
versions:
- name: v1alpha1
schema:
openAPIV3Schema:
description: Pipeline is the Schema for the pipelines API
properties:
apiVersion:
description: 'APIVersion defines the versioned schema of this representation
of an object. Servers should convert recognized schemas to the latest
internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources'
type: string
kind:
description: 'Kind is a string value representing the REST resource this
object represents. Servers may infer this from the endpoint the client
submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds'
type: string
metadata:
type: object
spec:
description: PipelineSpec defines the desired state of Pipeline
properties:
projectName:
description: test dummy - do not remove
type: string
type: object
status:
description: PipelineStatus defines the observed state of Pipeline
properties:
state:
description: State is the current state of the Pipeline, used mostly
for error states.
type: string
type: object
type: object
served: true
storage: true
subresources:
status: {}
status:
acceptedNames:
kind: ""
plural: ""
conditions: []
storedVersions: []
......@@ -6,7 +6,6 @@ resources:
- bases/customer.valkyrie.dso.mil_organizations.yaml
- bases/gitlab.valkyrie.dso.mil_groups.yaml
- bases/gitlab.valkyrie.dso.mil_projects.yaml
- bases/gitlab.valkyrie.dso.mil_pipelines.yaml
- bases/gitlab.valkyrie.dso.mil_sonarqubepipelineconfigurations.yaml
- bases/gitlab.valkyrie.dso.mil_sdelementspipelineconfigurations.yaml
- bases/customer.valkyrie.dso.mil_authorizingofficials.yaml
......@@ -29,7 +28,6 @@ patchesStrategicMerge:
#- patches/webhook_in_organizations.yaml
#- patches/webhook_in_groups.yaml
#- patches/webhook_in_projects.yaml
#- patches/webhook_in_pipelines.yaml
#- patches/webhook_in_fortifypipelineconfigurations.yaml
#- patches/webhook_in_twistlockpipelineconfigurations.yaml
#- patches/webhook_in_sonarqubepipelineconfigurations.yaml
......@@ -50,7 +48,6 @@ patchesStrategicMerge:
#- patches/cainjection_in_organizations.yaml
#- patches/cainjection_in_groups.yaml
#- patches/cainjection_in_projects.yaml
#- patches/cainjection_in_pipelines.yaml
#- patches/cainjection_in_fortifypipelineconfigurations.yaml
#- patches/cainjection_in_twistlockpipelineconfigurations.yaml
#- patches/cainjection_in_sonarqubepipelineconfigurations.yaml
......
# The following patch adds a directive for certmanager to inject CA into the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
cert-manager.io/inject-ca-from: $(CERTIFICATE_NAMESPACE)/$(CERTIFICATE_NAME)
name: pipelines.gitlab.valkyrie.dso.mil
# The following patch enables a conversion webhook for the CRD
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
name: pipelines.gitlab.valkyrie.dso.mil
spec:
conversion:
strategy: Webhook
webhook:
clientConfig:
service:
namespace: system
name: webhook-service
path: /convert
# permissions for end users to edit pipelines.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pipeline-editor-role
rules:
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines/status
verbs:
- get
# permissions for end users to view pipelines.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: pipeline-viewer-role
rules:
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines
verbs:
- get
- list
- watch
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines/status
verbs:
- get
......@@ -308,32 +308,6 @@ rules:
- get
- patch
- update
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines
verbs:
- create
- delete
- get
- list
- patch
- update
- watch
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines/finalizers
verbs:
- update
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
- pipelines/status
verbs:
- get
- patch
- update
- apiGroups:
- gitlab.valkyrie.dso.mil
resources:
......
/*
Copyright 2021.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package gitlab
import (
"context"
"github.com/go-logr/logr"
gogitlab "github.com/xanzy/go-gitlab"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/types"
ctrl "sigs.k8s.io/controller-runtime"
"sigs.k8s.io/controller-runtime/pkg/client"
"strconv"
apisGitlab "valkyrie.dso.mil/valkyrie-api/apis/gitlab"
"valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
gitlabClient "valkyrie.dso.mil/valkyrie-api/clients/gitlab"
)
const (
errorWhileLookingUpPipeline = "error while looking up pipeline."
errorUpdatingStatusOfPipeline = "Error updating status of pipeline."
)
// PipelineReconciler reconciles a Pipeline object
type PipelineReconciler struct {
client.Client
Log logr.Logger
Scheme *runtime.Scheme
gitlabClient gitlabClient.Client
gitlabClientConfiguration apisGitlab.ClientConfiguration
}
//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=pipelines,verbs=get;list;watch;create;update;patch;delete
//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=pipelines/status,verbs=get;update;patch
//+kubebuilder:rbac:groups=gitlab.valkyrie.dso.mil,resources=pipelines/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. This loop will
// create an maintain the CI/CD Pipeline settings for a Gitlab Project
func (r *PipelineReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) {
r.Log = r.Log.WithValues("pipeline", req.NamespacedName)
var err error
var pipeline *v1alpha1.Pipeline
var project *v1alpha1.Project
// Grab the pipeline from the K8s API
if pipeline, err = r.getPipeline(ctx, req); err != nil {
r.Log.Error(err, errorWhileLookingUpPipeline, "request", req)
return ctrl.Result{Requeue: client.IgnoreNotFound(err) != nil}, client.IgnoreNotFound(err)
}
// Grab the project from the K8s API for the credentials
if project, err = r.getProject(ctx, req, pipeline.Spec.ProjectName); err != nil {
r.Log.Error(err, errorWhileLookingUpProject)
_ = r.updateStatus(ctx, pipeline, errorWhileLookingUpProject)
return ctrl.Result{Requeue: true}, err
}
// Do a nil check here so we can use mock gitlabClients
if r.gitlabClient == nil {
if r.gitlabClientConfiguration == nil {
r.gitlabClientConfiguration = apisGitlab.ClientConfigurationImpl{}
}
// Setup Gitlab Client
if r.gitlabClient, err = r.gitlabClientConfiguration.SetupClient(r.Client, project.Spec.GitlabCredentialsName); err != nil {
r.Log.Error(err, errorUnableToSetupGitlabClient)
_ = r.updateStatus(ctx, pipeline, errorUnableToSetupGitlabClient)
return ctrl.Result{Requeue: true}, err
}
}
// Grab the Gitlab Project
//var gitlabProject *gogitlab.Project
if _, err = r.getGitlabProject(project); err != nil {
r.Log.Error(err, errorGettingProjectFromGitlab)
_ = r.updateStatus(ctx, pipeline, errorGettingProjectFromGitlab)
return ctrl.Result{Requeue: true}, err
}
// Setup General Pipelines
// Enable Public Pipelines
// Enable Auto-cancel redundant pipelines
// Enable skip outdated deployment jobs
// Set CI/CD Configuration file to products/{group}/{project-path}-ci.yml@platform-one/devops/pipeline-products
// Setup Artifacts
// Enable keep artifacts from most recent successful jobs
// TODO Setup Variables (Group Controller & Group Object needs updated here)
// KUSTOMIZE_PRODUCTION_PATH
// KUSTOMIZE_STAGING_PATH
// MAINIFEST_REPO_PATH
return ctrl.Result{}, nil
}
func (r *PipelineReconciler) getProject(ctx context.Context, request ctrl.Request, projectName string) (*v1alpha1.Project, error) {
objectKey := types.NamespacedName{
Namespace: request.Namespace,
Name: projectName,
}
project := v1alpha1.Project{}
err := r.Client.Get(ctx, objectKey, &project)
return &project, err
}
func (r *PipelineReconciler) getPipeline(ctx context.Context, request ctrl.Request) (*v1alpha1.Pipeline, error) {
pipeline := v1alpha1.Pipeline{}
err := r.Client.Get(ctx, request.NamespacedName, &pipeline)
return &pipeline, err
}
func (r *PipelineReconciler) updateStatus(ctx context.Context, pipeline *v1alpha1.Pipeline, status string) error {
pipeline.Status.State = status
if err := r.Status().Update(ctx, pipeline); err != nil {
r.Log.Error(err, errorUpdatingStatusOfPipeline, "pipeline", pipeline, "status", status)
return err
}
return nil
}
// SetupWithManager sets up the controller with the Manager.
func (r *PipelineReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.Pipeline{}).
Complete(r)
}
func (r *PipelineReconciler) getGitlabProject(project *v1alpha1.Project) (*gogitlab.Project, error) {
var id int
var err error
var statusCode int
var gitlabProject *gogitlab.Project
id, err = strconv.Atoi(project.Annotations[annotationKeyID])
if err != nil {
return nil, err
}
if gitlabProject, statusCode, err = r.gitlabClient.GetProject(id); err != nil {
r.Log.Error(err, errorGettingProjectFromGitlab, "statusCode", statusCode)
return nil, err
}
return gitlabProject, nil
}
package gitlab
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"
"sigs.k8s.io/controller-runtime/pkg/client"
"valkyrie.dso.mil/valkyrie-api/apis/gitlab/v1alpha1"
gitlabClient "valkyrie.dso.mil/valkyrie-api/clients/gitlab"
)
const GreenPipelineName = "greenPipeline"
func getGreenPipeline() v1alpha1.Pipeline {
return v1alpha1.Pipeline{
TypeMeta: metav1.TypeMeta{},
ObjectMeta: metav1.ObjectMeta{
Annotations: make(map[string]string),
},
Spec: v1alpha1.PipelineSpec{
ProjectName: GreenProjectName,
},
Status: v1alpha1.PipelineStatus{
State: "",
},
}
}
func getGreenGitlabProject() *gitlab.Project {
project := gitlab.Project{
ID: 1,
Description: "Green Project",
DefaultBranch: "",
Public: false,
Visibility: "",
SSHURLToRepo: "",
HTTPURLToRepo: "",
WebURL: "",
ReadmeURL: "",
TagList: nil,
Owner: nil,
Name: "Green Project",
NameWithNamespace: "",
Path: "/greenProject",
PathWithNamespace: "/greenGroup/greenProject",
IssuesEnabled: false,
OpenIssuesCount: 0,
MergeRequestsEnabled: false,
ApprovalsBeforeMerge: 0,
JobsEnabled: false,
WikiEnabled: false,
SnippetsEnabled: false,
ResolveOutdatedDiffDiscussions: false,
ContainerExpirationPolicy: nil,
ContainerRegistryEnabled: false,
CreatedAt: nil,
LastActivityAt: nil,
CreatorID: 0,
Namespace: nil,
ImportStatus: "",
ImportError: "",
Permissions: nil,
MarkedForDeletionAt: nil,
EmptyRepo: false,
Archived: false,
AvatarURL: "",
LicenseURL: "",
License: nil,
SharedRunnersEnabled: false,
ForksCount: 0,
StarCount: 0,
RunnersToken: "",
PublicBuilds: false,
AllowMergeOnSkippedPipeline: false,
OnlyAllowMergeIfPipelineSucceeds: false,
OnlyAllowMergeIfAllDiscussionsAreResolved: false,
RemoveSourceBranchAfterMerge: false,
LFSEnabled: false,
RequestAccessEnabled: false,
MergeMethod: "",
ForkedFromProject: nil,
Mirror: false,
MirrorUserID: 0,
MirrorTriggerBuilds: false,
OnlyMirrorProtectedBranches: false,
MirrorOverwritesDivergedBranches: false,
PackagesEnabled: false,
ServiceDeskEnabled: false,
ServiceDeskAddress: "",
IssuesAccessLevel: "",
RepositoryAccessLevel: "",
MergeRequestsAccessLevel: "",
ForkingAccessLevel: "",
WikiAccessLevel: "",
BuildsAccessLevel: "",
SnippetsAccessLevel: "",
PagesAccessLevel: "",
OperationsAccessLevel: "",
AutocloseReferencedIssues: false,
SuggestionCommitMessage: "",
CIForwardDeploymentEnabled: false,
SharedWithGroups: nil,
Statistics: nil,
Links: nil,
CIConfigPath: "",
CIDefaultGitDepth: 0,
CustomAttributes: nil,
ComplianceFrameworks: nil,
BuildCoverageRegex: "",
IssuesTemplate: "",
MergeRequestsTemplate: "",
}
return &project
}
func getRequestWithDefaultNamespacedTestPipeline() ctrl.Request {
return ctrl.Request{
NamespacedName: types.NamespacedName{
Namespace: GreenNamespace,
Name: GreenPipelineName,
},
}
}
func getPipelineControllerWithMocksInGreenTestState() (PipelineReconciler, *MockManager, *MockLogger, *MockStatusWriter) {
builder := v1alpha1.SchemeBuilder.Register(&v1alpha1.Pipeline{}, &v1alpha1.PipelineList{})
scheme, _ := builder.Build()
mockStatusWriter := MockStatusWriter{}
pipeline := getGreenPipeline()
project := getGreenProject()
loggerMock := MockLogger{
WithValuesKeysAndValues: nil,
WithValuesCalled: false,
WithNameValue: "",
WithNameCalled: false,
}
clientMock := MockClient{
statusWriter: &mockStatusWriter,
expectedObjects: make(map[client.ObjectKey]client.Object),
}
clientMock.expectedObjects[getRequestWithDefaultNamespacedTestPipeline().NamespacedName] = &pipeline
clientMock.expectedObjects[getRequestWithDefaultNamespacedTestProject().NamespacedName] = &project
mockManager := &MockManager{
Log: &loggerMock,
builder: builder,
}
gitlabProject := getGreenGitlabProject()
gitlabClient := MockGitlabClient{
expectedProjects: make(map[int]*gitlab.Project, 0),
}
gitlabClient.expectedProjects[gitlabProject.ID] = gitlabProject
sut := PipelineReconciler{
Client: &clientMock,
Log: &loggerMock,
Scheme: scheme,
}
sut.gitlabClient = &gitlabClient
return sut, mockManager, &loggerMock, &mockStatusWriter
}
var _ = Describe("SetupWithManager", func() {
var _ = Describe("SetupWithManager", func() {
sut, mgr, _, _ := getPipelineControllerWithMocksInGreenTestState()
err := sut.SetupWithManager(mgr)
It("should return no error", func() {
Expect(err).To(BeNil())
})
})
})
var _ = Describe("reconcile", func() {
Context("green state", func() {
ctx := context.TODO()
request := getRequestWithDefaultNamespacedTestPipeline()
sut, _, _, _ := getPipelineControllerWithMocksInGreenTestState()
result, err := sut.Reconcile(ctx, request)
It("should not return an error", func() {
Expect(err).To(BeNil())
})
It("should not requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: false}))
})
})
Context("pipeline isn't found in the K8s API", func() {
sut, _, log, _ := getPipelineControllerWithMocksInGreenTestState()
request := getRequestWithDefaultNamespacedTestPipeline()
request.NamespacedName.Name = "not going to find it"
result, err := sut.Reconcile(context.TODO(), request)
It("should return no error", func() {
Expect(err).To(BeNil())
})
It("should not requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: false}))
})
It("should log that there was an error looking for the project", func() {
Expect(log.loggedMessage).To(Equal(errorWhileLookingUpPipeline))
})
})
Context("project isn't found in the K8s API or returns an error", func() {
sut, _, log, status := getPipelineControllerWithMocksInGreenTestState()
request := getRequestWithDefaultNamespacedTestPipeline()
delete(sut.Client.(*MockClient).expectedObjects, getRequestWithDefaultNamespacedTestProject().NamespacedName)
result, err := sut.Reconcile(context.TODO(), request)
It("should return an error", func() {
Expect(err).ToNot(BeNil())
})
It("should log the error", func() {
Expect(log.loggedMessage).To(Equal(errorWhileLookingUpProject))
})
It("should requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: true}))
})
It("should update the pipeline status", func() {
Expect(status.updatedObject.(*v1alpha1.Pipeline).Status.State).To(Equal(errorWhileLookingUpProject))
})
})
Context("SetupClient fails", func() {
sut, _, log, status := getPipelineControllerWithMocksInGreenTestState()
request := getRequestWithDefaultNamespacedTestPipeline()
sut.gitlabClient = nil
sut.gitlabClientConfiguration = &MockClientConfiguration{
SetupClientFunction: func(client client.Client, credentialsName string) (gitlabClient.Client, error) {
return nil, &MockError{message: "SetupClientFunction fails."}
},
}
result, err := sut.Reconcile(context.TODO(), request)
It("should log the error", func() {
Expect(log.logLevelCalled).To(Equal("Error"))
Expect(log.loggedMessage).To(Equal(errorUnableToSetupGitlabClient))
})
It("should requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: true}))
})
It("should return an error", func() {
Expect(err).To(Not(BeNil()))
})
It("should update the pipeline status", func() {
Expect(status.updatedObject.(*v1alpha1.Pipeline).Status.State).To(Equal(errorUnableToSetupGitlabClient))
})
})
Context("getGitlabProject fails to get the ID annotation", func() {
sut, _, log, status := getPipelineControllerWithMocksInGreenTestState()
sut.Client.(*MockClient).expectedObjects[getRequestWithDefaultNamespacedTestProject().NamespacedName].(*v1alpha1.Project).Annotations[annotationKeyID] = "BAD"
request := getRequestWithDefaultNamespacedTestPipeline()
result, err := sut.Reconcile(context.TODO(), request)
It("should return an error", func() {
Expect(err).ToNot(BeNil())
})
It("should log the error", func() {
Expect(log.loggedMessage).To(Equal(errorGettingProjectFromGitlab))
})
It("should requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: true}))
})
It("should update the pipeline status", func() {
Expect(status.updatedObject.(*v1alpha1.Pipeline).Status.State).To(Equal(errorGettingProjectFromGitlab))
})
})
Context("getGitlabProject returns an error", func() {
sut, _, log, status := getPipelineControllerWithMocksInGreenTestState()
sut.gitlabClient.(*MockGitlabClient).getProjectFunction = func(groupID int) (*gitlab.Project, int, error) {
return nil, 500, &MockError{
message: "failure in getGitlabProject",
}
}
request := getRequestWithDefaultNamespacedTestPipeline()
result, err := sut.Reconcile(context.TODO(), request)
It("should return an error", func() {
Expect(err).ToNot(BeNil())
})
It("should log the error", func() {
Expect(log.loggedMessage).To(Equal(errorGettingProjectFromGitlab))
})
It("should requeue the object", func() {
Expect(result).To(Equal(ctrl.Result{Requeue: true}))
})
It("should update the pipeline status", func() {
Expect(status.updatedObject.(*v1alpha1.Pipeline).Status.State).To(Equal(errorGettingProjectFromGitlab))
})
})
})
var _ = Describe("updateStatus fails", func() {
sut, _, log, status := getPipelineControllerWithMocksInGreenTestState()
status.updateFunction = func(ctx context.Context, obj client.Object, opts ...client.UpdateOption) error {
return &MockError{
message: "update status fails.",
}
}
pipeline := getGreenPipeline()
err := sut.updateStatus(context.TODO(), &pipeline, errorGettingProjectFromGitlab)
It("should log the error", func() {
Expect(log.logLevelCalled).To(Equal("Error"))
Expect(log.loggedMessage).To(Equal(errorUpdatingStatusOfPipeline))
})
It("should return the error", func() {
Expect(err).ToNot(BeNil())
})
})
......@@ -67,6 +67,20 @@ const ManifestImageVariableName = "MANIFEST_IMAGE"
const annotationKeyID = "ID"
// Setup General Pipelines
// Enable Public Pipelines
// Enable Auto-cancel redundant pipelines
// Enable skip outdated deployment jobs
// Set CI/CD Configuration file to products/{group}/{project-path}-ci.yml@platform-one/devops/pipeline-products
// Setup Artifacts
// Enable keep artifacts from most recent successful jobs
// TODO Setup Variables (Group Controller & Group Object needs updated here)
// KUSTOMIZE_PRODUCTION_PATH
// KUSTOMIZE_STAGING_PATH
// MAINIFEST_REPO_PATH
// 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 = r.Log.WithValues("project", req.NamespacedName)
......@@ -155,7 +169,6 @@ func (r *ProjectReconciler) updateStatus(ctx context.Context, project *v1alpha1.
func (r *ProjectReconciler) SetupWithManager(mgr ctrl.Manager) error {
return ctrl.NewControllerManagedBy(mgr).
For(&v1alpha1.Project{}).
Owns(&v1alpha1.Pipeline{}).
Complete(r)
}
......
......@@ -142,11 +142,6 @@ func (d driverImpl) instantiateControllers(mgr manager.Manager) []controllers.Ma
Log: ctrl.Log.WithName("controllers").WithName("gitlab").WithName("Project"),
Scheme: mgr.GetScheme(),
},
&gitlabcontrollers.PipelineReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("gitlab").WithName("Pipeline"),
Scheme: mgr.GetScheme(),
},
&fortifycontrollers.CredentialReconciler{
Client: mgr.GetClient(),
Log: ctrl.Log.WithName("controllers").WithName("fortify").WithName("FortifyCredential"),
......
......@@ -32,44 +32,41 @@ var _ = Describe("instantiateControllers", func() {
It("Should create a Project Controller", func() {
Expect(controllers[3]).To(BeAssignableToTypeOf(&gitlab.ProjectReconciler{}))
})
It("Should create a Pipeline Controller", func() {
Expect(controllers[4]).To(BeAssignableToTypeOf(&gitlab.PipelineReconciler{}))
})
It("Should create a Fortify Credential Controller", func() {
Expect(controllers[5]).To(BeAssignableToTypeOf(&fortify.CredentialReconciler{}))
Expect(controllers[4]).To(BeAssignableToTypeOf(&fortify.CredentialReconciler{}))
})
It("Should create a Fortify Configuration Controller", func() {
Expect(controllers[6]).To(BeAssignableToTypeOf(&fortify.PipelineConfigurationReconciler{}))
Expect(controllers[5]).To(BeAssignableToTypeOf(&fortify.PipelineConfigurationReconciler{}))
})
It("Should create a Twistlock Configuration Controller", func() {
Expect(controllers[7]).To(BeAssignableToTypeOf(&twistlock.PipelineConfigurationReconciler{}))
Expect(controllers[6]).To(BeAssignableToTypeOf(&twistlock.PipelineConfigurationReconciler{}))
})
It("Should create a Twistlock credential Controller", func() {
Expect(controllers[8]).To(BeAssignableToTypeOf(&twistlock.CredentialReconciler{}))
Expect(controllers[7]).To(BeAssignableToTypeOf(&twistlock.CredentialReconciler{}))
})
It("Should create a SonarQube Configuration Controller", func() {
Expect(controllers[9]).To(BeAssignableToTypeOf(&gitlab.SonarqubePipelineConfigurationReconciler{}))
Expect(controllers[8]).To(BeAssignableToTypeOf(&gitlab.SonarqubePipelineConfigurationReconciler{}))
})
It("Should create an SD Elements Configuration Controller", func() {
Expect(controllers[10]).To(BeAssignableToTypeOf(&gitlab.SdElementsPipelineConfigurationReconciler{}))
Expect(controllers[9]).To(BeAssignableToTypeOf(&gitlab.SdElementsPipelineConfigurationReconciler{}))
})
It("Should create a Authorizing Official Controller", func() {
Expect(controllers[11]).To(BeAssignableToTypeOf(&customer.AuthorizingOfficialReconciler{}))
Expect(controllers[10]).To(BeAssignableToTypeOf(&customer.AuthorizingOfficialReconciler{}))
})
It("Should create a System Owner Controller", func() {
Expect(controllers[12]).To(BeAssignableToTypeOf(&customer.SystemOwnerReconciler{}))
Expect(controllers[11]).To(BeAssignableToTypeOf(&customer.SystemOwnerReconciler{}))
})
It("Should create a ChiefInformationSecurityOfficer Controller", func() {
Expect(controllers[13]).To(BeAssignableToTypeOf(&customer.ChiefInformationSecurityOfficerReconciler{}))
Expect(controllers[12]).To(BeAssignableToTypeOf(&customer.ChiefInformationSecurityOfficerReconciler{}))
})
It("Should create a GitlabCredentials Controller", func() {
Expect(controllers[14]).To(BeAssignableToTypeOf(&gitlab.CredentialsReconciler{}))
Expect(controllers[13]).To(BeAssignableToTypeOf(&gitlab.CredentialsReconciler{}))
})
It("Should create a DNSRepoCredential Controller", func() {
Expect(controllers[15]).To(BeAssignableToTypeOf(&gitlab.DNSRepoCredentialReconciler{}))
Expect(controllers[14]).To(BeAssignableToTypeOf(&gitlab.DNSRepoCredentialReconciler{}))
})
It("Should create a DNSRepoMergeRequest Controller", func() {
Expect(controllers[16]).To(BeAssignableToTypeOf(&gitlab.DNSRepoMergeRequestReconciler{}))
Expect(controllers[15]).To(BeAssignableToTypeOf(&gitlab.DNSRepoMergeRequestReconciler{}))
})
})
})
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment