Skip to content

Commit 9d3fb48

Browse files
zreigzmaciaszczykmmichaeljguarino
authored
feat: Add infrastructure stack run poller (#170)
* infrastructure stack poller * infrastructure stack poller * change names * register stack Reconciler * bump go cient * handle job * reconcile Job * create job * merge job spec * remove job check * add label selector * add label selector * update job reconciler * use new client to simplify job generation * default job spec * do not update run status * add run job generation * update variable name * add stack run job controller * check job status * move job logic * make defaultJobContainer private * update logs * update default job * fetch job pods * use pointer * update log * change error handling * add label selector * default image and version * add label selector * fix client * refactor * refactor * fetch job pod status * update exit codes * start adding tests for stack run job controller * fix tests * add more tests * fix job creation * add container envs * rebase * add job controller * fix unit tests * fix unmarshal job spec * sync step status * update step statuses * update mocks * ignore stack run * add default container annotation * initialize agent tests * add tests for stack agent * fix approval logic * add nil checks * add more tests * add tests to cover job creation * add missing mapping for sa * fix annotations mapping * cover job spec mapping * cover raw job spec mapping * add pipeline gate controller tests * fix make test * simplify test suite * cleanup other suites * simplify test suite * fix kustomize files * add image names * add image versions * change image * bump console client * fix linter --------- Co-authored-by: Marcin Maciaszczyk <[email protected]> Co-authored-by: michaeljguarino <[email protected]>
1 parent d765f7b commit 9d3fb48

25 files changed

+1780
-105
lines changed

cmd/agent.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ import (
44
"os"
55
"time"
66

7+
"github.com/pluralsh/deployment-operator/internal/utils"
8+
"github.com/pluralsh/deployment-operator/pkg/controller/stacks"
9+
710
"github.com/pluralsh/deployment-operator/pkg/controller"
811
"github.com/pluralsh/deployment-operator/pkg/controller/namespaces"
912
"github.com/pluralsh/deployment-operator/pkg/controller/pipelinegates"
@@ -69,6 +72,18 @@ func runAgent(opt *options, config *rest.Config, ctx context.Context, k8sClient
6972
Queue: ns.NamespaceQueue,
7073
})
7174

75+
namespace, err := utils.GetOperatorNamespace()
76+
if err != nil {
77+
setupLog.Error(err, "unable to get operator namespace")
78+
os.Exit(1)
79+
}
80+
81+
s := stacks.NewStackReconciler(mgr.GetClient(), k8sClient, r, namespace, opt.consoleUrl, opt.deployToken)
82+
mgr.AddController(&controller.Controller{
83+
Name: "Stack Controller",
84+
Do: s,
85+
Queue: s.StackQueue,
86+
})
7287
if err := mgr.Start(); err != nil {
7388
setupLog.Error(err, "unable to start controller manager")
7489
os.Exit(1)

cmd/main.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,14 @@ func main() {
104104
}).SetupWithManager(mgr); err != nil {
105105
setupLog.Error(err, "unable to create controller", "controller", "HealthConvert")
106106
}
107+
if err = (&controller.StackRunJobReconciler{
108+
Client: mgr.GetClient(),
109+
Scheme: mgr.GetScheme(),
110+
ConsoleClient: ctrlMgr.GetClient(),
111+
}).SetupWithManager(mgr); err != nil {
112+
setupLog.Error(err, "unable to create controller", "controller", "StackRun")
113+
}
114+
107115
//+kubebuilder:scaffold:builder
108116

109117
if err = (&controller.PipelineGateReconciler{

config/crd/kustomization.yaml

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,5 @@ resources:
55
- bases/deployments.plural.sh_luascripts.yaml
66
#+kubebuilder:scaffold:crdkustomizeresource
77

8-
patches:
9-
# [WEBHOOK] To enable webhook, uncomment all the sections with [WEBHOOK] prefix.
10-
# patches here are for enabling the conversion webhook for each CRD
11-
#- path: patches/webhook_in_luascripts.yaml
12-
#+kubebuilder:scaffold:crdkustomizewebhookpatch
13-
14-
# [CERTMANAGER] To enable cert-manager, uncomment all the sections with [CERTMANAGER] prefix.
15-
# patches here are for enabling the CA injection for each CRD
16-
#- path: patches/cainjection_in_luascripts.yaml
17-
#+kubebuilder:scaffold:crdkustomizecainjectionpatch
18-
19-
# [WEBHOOK] To enable webhook, uncomment the following section
20-
# the following config is for teaching kustomize how to do kustomization for CRDs.
21-
22-
#configurations:
23-
#- kustomizeconfig.yaml
8+
apiVersion: kustomize.config.k8s.io/v1beta1
9+
kind: Kustomization

go.mod

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,14 @@ require (
1919
github.com/open-policy-agent/gatekeeper/v3 v3.15.1
2020
github.com/orcaman/concurrent-map/v2 v2.0.1
2121
github.com/pkg/errors v0.9.1
22-
github.com/pluralsh/console-client-go v0.5.6
22+
github.com/pluralsh/console-client-go v0.5.8
2323
github.com/pluralsh/controller-reconcile-helper v0.0.4
2424
github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34
2525
github.com/pluralsh/polly v0.1.10
2626
github.com/samber/lo v1.39.0
2727
github.com/spf13/pflag v1.0.5
2828
github.com/stretchr/testify v1.9.0
29+
github.com/vektah/gqlparser/v2 v2.5.11
2930
github.com/vektra/mockery/v2 v2.39.0
3031
github.com/vmware-tanzu/velero v1.13.0
3132
github.com/yuin/gopher-lua v1.1.1
@@ -192,7 +193,6 @@ require (
192193
github.com/stretchr/objx v0.5.2 // indirect
193194
github.com/subosito/gotenv v1.4.2 // indirect
194195
github.com/ugorji/go/codec v1.1.7 // indirect
195-
github.com/vektah/gqlparser/v2 v2.5.11 // indirect
196196
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
197197
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
198198
github.com/xeipuuv/gojsonschema v1.2.0 // indirect

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -526,8 +526,8 @@ github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
526526
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
527527
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
528528
github.com/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg=
529-
github.com/pluralsh/console-client-go v0.5.6 h1:8CUQco0vJehtKabVVNHAkFE4V9UI9MaMKvYNgQRrJdo=
530-
github.com/pluralsh/console-client-go v0.5.6/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo=
529+
github.com/pluralsh/console-client-go v0.5.8 h1:Qm7vS+gCbmWqy5i4saLPc5/SUZaW6RCzxWF+uxyPA+Y=
530+
github.com/pluralsh/console-client-go v0.5.8/go.mod h1:eyCiLA44YbXiYyJh8303jk5JdPkt9McgCo5kBjk4lKo=
531531
github.com/pluralsh/controller-reconcile-helper v0.0.4 h1:1o+7qYSyoeqKFjx+WgQTxDz4Q2VMpzprJIIKShxqG0E=
532532
github.com/pluralsh/controller-reconcile-helper v0.0.4/go.mod h1:AfY0gtteD6veBjmB6jiRx/aR4yevEf6K0M13/pGan/s=
533533
github.com/pluralsh/gophoenix v0.1.3-0.20231201014135-dff1b4309e34 h1:ab2PN+6if/Aq3/sJM0AVdy1SYuMAnq4g20VaKhTm/Bw=

internal/controller/backup_controller.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,12 +43,12 @@ func (r *BackupReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctr
4343
// Read resource from Kubernetes cluster.
4444
backup := &velerov1.Backup{}
4545
if err := r.Get(ctx, req.NamespacedName, backup); err != nil {
46-
logger.Error(err, "Unable to fetch backup")
46+
logger.Error(err, "unable to fetch backup")
4747
return ctrl.Result{}, k8sClient.IgnoreNotFound(err)
4848
}
4949

5050
// Upsert backup data to the Console.
51-
logger.Info("Cluster backup saved", "name", backup.Name, "namespace", backup.Namespace)
51+
logger.Info("cluster backup saved", "name", backup.Name, "namespace", backup.Namespace)
5252
_, err := r.ConsoleClient.SaveClusterBackup(console.BackupAttributes{
5353
Name: backup.Name,
5454
Namespace: backup.Namespace,
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package controller
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/go-logr/logr"
8+
. "github.com/onsi/ginkgo/v2"
9+
. "github.com/onsi/gomega"
10+
console "github.com/pluralsh/console-client-go"
11+
"github.com/pluralsh/deployment-operator/api/v1alpha1"
12+
"github.com/pluralsh/deployment-operator/pkg/client"
13+
"github.com/pluralsh/deployment-operator/pkg/test/common"
14+
"github.com/pluralsh/deployment-operator/pkg/test/mocks"
15+
"github.com/samber/lo"
16+
"github.com/stretchr/testify/mock"
17+
batchv1 "k8s.io/api/batch/v1"
18+
corev1 "k8s.io/api/core/v1"
19+
"k8s.io/apimachinery/pkg/api/errors"
20+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
21+
"k8s.io/apimachinery/pkg/types"
22+
"sigs.k8s.io/controller-runtime/pkg/reconcile"
23+
)
24+
25+
var _ = Describe("PipelineGate Controller", Ordered, func() {
26+
Context("When reconciling a resource", func() {
27+
const (
28+
gateName = "gate-test"
29+
namespace = "default"
30+
id = "123"
31+
raw = `{"backoffLimit":4,"template":{"metadata":{"namespace":"default","creationTimestamp":null},"spec":{"containers":[{"name":"pi","image":"perl:5.34.0","command":["perl","-Mbignum=bpi","-wle","print bpi(2000)"],"resources":{}}],"restartPolicy":"Never"}}}`
32+
)
33+
34+
gateCache := client.NewCache[console.PipelineGateFragment](time.Second, func(id string) (*console.PipelineGateFragment, error) {
35+
return &console.PipelineGateFragment{
36+
ID: id,
37+
Name: "test",
38+
Spec: &console.GateSpecFragment{
39+
Job: &console.JobSpecFragment{
40+
Namespace: namespace,
41+
Raw: lo.ToPtr(raw),
42+
},
43+
},
44+
Status: nil,
45+
}, nil
46+
})
47+
48+
ctx := context.Background()
49+
gateNamespacedName := types.NamespacedName{Name: gateName, Namespace: namespace}
50+
pipelineGate := &v1alpha1.PipelineGate{}
51+
52+
BeforeAll(func() {
53+
By("Creating pipeline gate")
54+
err := kClient.Get(ctx, gateNamespacedName, pipelineGate)
55+
if err != nil && errors.IsNotFound(err) {
56+
resource := &v1alpha1.PipelineGate{
57+
ObjectMeta: metav1.ObjectMeta{
58+
Name: gateName,
59+
Namespace: namespace,
60+
},
61+
Spec: v1alpha1.PipelineGateSpec{
62+
ID: id,
63+
Name: "test",
64+
Type: v1alpha1.GateType(console.GateTypeJob),
65+
GateSpec: &v1alpha1.GateSpec{
66+
JobSpec: &batchv1.JobSpec{
67+
Template: corev1.PodTemplateSpec{
68+
ObjectMeta: metav1.ObjectMeta{},
69+
Spec: corev1.PodSpec{
70+
Containers: []corev1.Container{
71+
{
72+
Name: "image1",
73+
},
74+
},
75+
},
76+
},
77+
},
78+
},
79+
},
80+
}
81+
Expect(kClient.Create(ctx, resource)).To(Succeed())
82+
}
83+
84+
})
85+
86+
It("should set state pending", func() {
87+
fakeConsoleClient := mocks.NewClientMock(mocks.TestingT)
88+
fakeConsoleClient.On("UpdateGate", mock.Anything, mock.Anything).Return(nil)
89+
reconciler := &PipelineGateReconciler{
90+
Client: kClient,
91+
ConsoleClient: fakeConsoleClient,
92+
GateCache: gateCache,
93+
Scheme: kClient.Scheme(),
94+
Log: logr.Logger{},
95+
}
96+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: gateNamespacedName})
97+
Expect(err).NotTo(HaveOccurred())
98+
99+
existingGate := &v1alpha1.PipelineGate{}
100+
Expect(kClient.Get(ctx, gateNamespacedName, existingGate)).NotTo(HaveOccurred())
101+
Expect(*existingGate.Status.State).Should(Equal(v1alpha1.GateState(console.GateStatePending)))
102+
103+
})
104+
105+
It("should reconcile Pending Gate", func() {
106+
fakeConsoleClient := mocks.NewClientMock(mocks.TestingT)
107+
fakeConsoleClient.On("UpdateGate", mock.Anything, mock.Anything).Return(nil)
108+
reconciler := &PipelineGateReconciler{
109+
Client: kClient,
110+
ConsoleClient: fakeConsoleClient,
111+
GateCache: gateCache,
112+
Scheme: kClient.Scheme(),
113+
Log: logr.Logger{},
114+
}
115+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: gateNamespacedName})
116+
Expect(err).NotTo(HaveOccurred())
117+
118+
existingGate := &v1alpha1.PipelineGate{}
119+
Expect(kClient.Get(ctx, gateNamespacedName, existingGate)).NotTo(HaveOccurred())
120+
Expect(*existingGate.Status.State).Should(Equal(v1alpha1.GateState(console.GateStateRunning)))
121+
existingJob := &batchv1.Job{}
122+
Expect(kClient.Get(ctx, gateNamespacedName, existingJob)).NotTo(HaveOccurred())
123+
})
124+
125+
It("should open Gate", func() {
126+
fakeConsoleClient := mocks.NewClientMock(mocks.TestingT)
127+
fakeConsoleClient.On("UpdateGate", mock.Anything, mock.Anything).Return(nil)
128+
reconciler := &PipelineGateReconciler{
129+
Client: kClient,
130+
ConsoleClient: fakeConsoleClient,
131+
GateCache: gateCache,
132+
Scheme: kClient.Scheme(),
133+
Log: logr.Logger{},
134+
}
135+
136+
existingJob := &batchv1.Job{}
137+
Expect(kClient.Get(ctx, gateNamespacedName, existingJob)).NotTo(HaveOccurred())
138+
139+
Expect(common.MaybePatch(kClient, existingJob,
140+
func(p *batchv1.Job) {
141+
p.Status.Conditions = []batchv1.JobCondition{
142+
{
143+
Type: batchv1.JobComplete,
144+
Status: corev1.ConditionTrue,
145+
},
146+
}
147+
})).To(Succeed())
148+
149+
_, err := reconciler.Reconcile(ctx, reconcile.Request{NamespacedName: gateNamespacedName})
150+
Expect(err).NotTo(HaveOccurred())
151+
152+
existingGate := &v1alpha1.PipelineGate{}
153+
Expect(kClient.Get(ctx, gateNamespacedName, existingGate)).NotTo(HaveOccurred())
154+
Expect(*existingGate.Status.State).Should(Equal(v1alpha1.GateState(console.GateStateOpen)))
155+
156+
Expect(kClient.Delete(ctx, existingGate)).To(Succeed())
157+
Expect(kClient.Delete(ctx, existingJob)).To(Succeed())
158+
})
159+
})
160+
})

0 commit comments

Comments
 (0)