Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: make drift check and apply with custom runner code #2

Merged
merged 42 commits into from
Dec 22, 2022
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
afbe55e
chore(wip): wip
AlanLonguet Nov 24, 2022
15f13a8
chore(evaluate): change function signature
AlanLonguet Nov 24, 2022
87c3d6d
feat: add compute hash func
spoukke Nov 24, 2022
5ceba86
chore(signature): again changing function signature
AlanLonguet Nov 24, 2022
30d2d16
feat: add evaluate for isTerraformRunning and isPlanArtifactUpToDDate
spoukke Nov 24, 2022
8645fe2
feat(conditions): terraformFailure TerraformApplyUpToDate
AlanLonguet Nov 24, 2022
b6852fc
feat: use const prefixes for cahce keys
spoukke Nov 24, 2022
026bdaf
chore(tests): add some units tests for conditions
AlanLonguet Dec 5, 2022
f19aaf4
build: generate deepcopy and manifests
spoukke Dec 5, 2022
99469c1
feat: fix timestamp conversion
spoukke Dec 5, 2022
8ceb75b
test: implement testing for all evaluate methods of terraform conditions
spoukke Dec 5, 2022
b4cea0f
chore: rename structs
spoukke Dec 5, 2022
ba4b83d
chore: uniformize every sub evaluate mehtod
spoukke Dec 5, 2022
4a993ae
test: start implementing terraform layer conditions tests
spoukke Dec 5, 2022
6a44b2b
test: implement terraform layer conditions testing
spoukke Dec 5, 2022
47ca78c
chore: remove unused struct
spoukke Dec 5, 2022
e873c28
feat: start working on job
spoukke Dec 8, 2022
89a4c2f
feat: fix init default pod spec
spoukke Dec 12, 2022
49be385
feat: fix init default pod spec
spoukke Dec 15, 2022
5a25c7b
chore(wip): runner
AlanLonguet Dec 15, 2022
c05749f
feat: finish cache logic for plan pod creation
spoukke Dec 15, 2022
420ed36
feat: add command for apply pod
spoukke Dec 15, 2022
811e165
feat: implement redis cache
spoukke Dec 16, 2022
8e71e38
improvement(runner): add runner code, init cobra, move to cache package
AlanLonguet Dec 19, 2022
29204d7
feat: remove applied bin cahce key
spoukke Dec 21, 2022
3faf6d9
feat(cobra): implement cobra launch
AlanLonguet Dec 21, 2022
3774fc5
chore(runner): modify pod creation to use burrito binary
AlanLonguet Dec 21, 2022
92634b5
chore(docker): and crd generation
AlanLonguet Dec 21, 2022
53415ab
feat: use config to setup cahce in layer controller
spoukke Dec 21, 2022
1275c76
feat: run exec on cotnrollers start
spoukke Dec 21, 2022
f0c96dc
feat: use custom image for runeer and generate random name
spoukke Dec 21, 2022
aa75fdb
fix: do not inpu error 2 times to logger
spoukke Dec 21, 2022
a78b505
fix(runner): pod generation
AlanLonguet Dec 21, 2022
4536cbc
fix(runner): pod generation remove command
AlanLonguet Dec 21, 2022
7ebd8a5
fix: change prefix in pod env vars
spoukke Dec 21, 2022
47af2fe
feat: catch set lock error
spoukke Dec 21, 2022
ead33c9
feat: use commen generate key function for cahce keys
spoukke Dec 21, 2022
155c17c
fix(all): add some logs on controller and runner, fix some cache dele…
AlanLonguet Dec 21, 2022
b3d51f4
feat(redis): implement delete func
AlanLonguet Dec 21, 2022
f48eee3
improvement(runner): no sé
AlanLonguet Dec 21, 2022
fd3b920
feat: make runner put last plan date in cache
spoukke Dec 22, 2022
2452f8b
fix: use unix timestamp as value for last plan date key in cache
spoukke Dec 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions api/v1alpha1/terraformlayer_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ limitations under the License.
package v1alpha1

import (
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

Expand All @@ -28,14 +29,30 @@ type TerraformLayerSpec struct {
// INSERT ADDITIONAL SPEC FIELDS - desired state of cluster
// Important: Run "make" to regenerate code after modifying this file

// Foo is an example field of TerraformLayer. Edit terraformlayer_types.go to remove/update
Foo string `json:"foo,omitempty"`
Path string `json:"path,omitempty"`
Branch string `json:"branch,omitempty"`
TerraformVersion string `json:"terraformVersion,omitempty"`
Repository TerraformLayerRepository `json:"repository,omitempty"`
RemediationStrategy TerraformLayerRemediationStrategy `json:"remediationStrategy,omitempty"`
PlanOnPullRequest bool `json:"planOnPullRequest,omitempty"`
RunnerPodTemplate corev1.PodTemplateSpec `json:"template,omitempty"`
}

type TerraformLayerRemediationStrategy struct {
PlanOnDrift bool `json:"planOnDrift,omitempty"`
ApplyOnDrift bool `json:"applyOnDrift,omitempty"`
ApplyOnPush bool `json:"applyOnPush,omitempty"`
}

type TerraformLayerRepository struct {
Kind string `json:"kind,omitempty"`
Name string `json:"name,omitempty"`
Namespace string `json:"namespace,omitempty"`
}

// TerraformLayerStatus defines the observed state of TerraformLayer
type TerraformLayerStatus struct {
// INSERT ADDITIONAL STATUS FIELD - define observed state of cluster
// Important: Run "make" to regenerate code after modifying this file
Conditions []metav1.Condition `json:"conditions,omitempty" patchStrategy:"merge" patchMergeKey:"type" protobuf:"bytes,1,rep,name=conditions"`
}

//+kubebuilder:object:root=true
Expand Down
36 changes: 36 additions & 0 deletions controllers/cache.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package controllers

import "errors"

type Cache interface {
Get(key string) ([]byte, error)
Set(key string, value []byte, ttl int) error
Delete(key string) error
}

type MemoryCache struct {
data map[string][]byte
}

func newMemoryCache() *MemoryCache {
return &MemoryCache{
data: map[string][]byte{},
}
}

func (m *MemoryCache) Get(key string) ([]byte, error) {
if _, ok := m.data[key]; !ok {
return nil, errors.New("key not found")
}
return m.data[key], nil
}

func (m *MemoryCache) Set(key string, value []byte, ttl int) error {
m.data[key] = value
return nil
}

func (m *MemoryCache) Delete(key string) error {
delete(m.data, key)
return nil
}
143 changes: 143 additions & 0 deletions controllers/conditions_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
/*
Copyright 2022.

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 controllers

import (
"strconv"
"testing"
"time"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"

logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
//+kubebuilder:scaffold:imports
)

// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.

func TestConditions(t *testing.T) {
RegisterFailHandler(Fail)

RunSpecs(t, "Conditions Suite")
}

var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
})

var _ = AfterSuite(func() {
})

var _ = Describe("TerraformLayer", func() {
var t *configv1alpha1.TerraformLayer
var cache Cache

BeforeEach(func() {
t = &configv1alpha1.TerraformLayer{
Spec: configv1alpha1.TerraformLayerSpec{
Path: "/test",
Branch: "main",
Repository: configv1alpha1.TerraformLayerRepository{
Name: "test-repository",
Namespace: "default",
},
},
}
cache = newMemoryCache()
})

Describe("TerraformRunningCondition", func() {
var condition TerraformRunningCondition
BeforeEach(func() {
condition = TerraformRunningCondition{}
})
Context("with lock in cache", func() {
It("should return true", func() {
cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0)
Expect(condition.Evaluate(cache, t)).To(Equal(true))
})
})
Context("with lock not in cache", func() {
It("should return false", func() {
Expect(condition.Evaluate(cache, t)).To(Equal(false))
})
})
})
Describe("TerraformPlanArtifactCondition", func() {
var condition TerraformPlanArtifactCondition
BeforeEach(func() {
condition = TerraformPlanArtifactCondition{}
})
Context("with no last timestamp in cache", func() {
It("should return false", func() {
Expect(condition.Evaluate(cache, t)).To(Equal(false))
})
})
Context("with last timestamp in cache < 20min", func() {
It("should return true", func() {
cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch),
[]byte(strconv.Itoa(int((time.Now().Add(-5 * time.Minute)).Unix()))), 0)
Expect(condition.Evaluate(cache, t)).To(Equal(true))
})
})
Context("with last timestamp in cache > 20min", func() {
It("should return false", func() {
cache.Set(PrefixLastPlanDate+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path, t.Spec.Branch),
[]byte(strconv.Itoa(int(time.Now().Add(-25*time.Minute).Unix()))), 0)
Expect(condition.Evaluate(cache, t)).To(Equal(false))
})
})
})
// Describe("TerraformPlanArtifactCondition", func() {
// var runningCondition TerraformRunningCondition
// BeforeEach(func() {
// runningCondition = TerraformRunningCondition{}
// })
// Context("with lock in cache", func() {
// It("should return true", func() {
// cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0)
// Expect(runningCondition.Evaluate(cache, t)).To(Equal(true))
// })
// })
// Context("with lock not in cache", func() {
// It("should return false", func() {
// Expect(runningCondition.Evaluate(cache, t)).To(Equal(false))
// })
// })
// })
// Describe("TerraformPlanArtifactCondition", func() {
// var runningCondition TerraformRunningCondition
// BeforeEach(func() {
// runningCondition = TerraformRunningCondition{}
// })
// Context("with lock in cache", func() {
// It("should return true", func() {
// cache.Set(PrefixLock+computeHash(t.Spec.Repository.Name, t.Spec.Repository.Namespace, t.Spec.Path), []byte{1}, 0)
// Expect(runningCondition.Evaluate(cache, t)).To(Equal(true))
// })
// })
// Context("with lock not in cache", func() {
// It("should return false", func() {
// Expect(runningCondition.Evaluate(cache, t)).To(Equal(false))
// })
// })
// })
})
118 changes: 59 additions & 59 deletions controllers/suite_test.go
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
/*
Copyright 2022.
// /*
// Copyright 2022.

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
// 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
// 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.
*/
// 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 controllers

import (
"path/filepath"
"testing"
// import (
// "path/filepath"
// "testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
// . "github.com/onsi/ginkgo/v2"
// . "github.com/onsi/gomega"

"k8s.io/client-go/kubernetes/scheme"
"k8s.io/client-go/rest"
"sigs.k8s.io/controller-runtime/pkg/client"
"sigs.k8s.io/controller-runtime/pkg/envtest"
logf "sigs.k8s.io/controller-runtime/pkg/log"
"sigs.k8s.io/controller-runtime/pkg/log/zap"
// "k8s.io/client-go/kubernetes/scheme"
// "k8s.io/client-go/rest"
// "sigs.k8s.io/controller-runtime/pkg/client"
// "sigs.k8s.io/controller-runtime/pkg/envtest"
// logf "sigs.k8s.io/controller-runtime/pkg/log"
// "sigs.k8s.io/controller-runtime/pkg/log/zap"

configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
//+kubebuilder:scaffold:imports
)
// configv1alpha1 "github.com/padok-team/burrito/api/v1alpha1"
// //+kubebuilder:scaffold:imports
// )

// These tests use Ginkgo (BDD-style Go testing framework). Refer to
// http://onsi.github.io/ginkgo/ to learn more about Ginkgo.
// // These tests use Ginkgo (BDD-style Go testing framework). Refer to
// // http://onsi.github.io/ginkgo/ to learn more about Ginkgo.

var cfg *rest.Config
var k8sClient client.Client
var testEnv *envtest.Environment
// var cfg *rest.Config
// var k8sClient client.Client
// var testEnv *envtest.Environment

func TestAPIs(t *testing.T) {
RegisterFailHandler(Fail)
// func TestAPIs(t *testing.T) {
// RegisterFailHandler(Fail)

RunSpecs(t, "Controller Suite")
}
// RunSpecs(t, "Controller Suite")
// }

var _ = BeforeSuite(func() {
logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))
// var _ = BeforeSuite(func() {
// logf.SetLogger(zap.New(zap.WriteTo(GinkgoWriter), zap.UseDevMode(true)))

By("bootstrapping test environment")
testEnv = &envtest.Environment{
CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
ErrorIfCRDPathMissing: true,
}
// By("bootstrapping test environment")
// testEnv = &envtest.Environment{
// CRDDirectoryPaths: []string{filepath.Join("..", "config", "crd", "bases")},
// ErrorIfCRDPathMissing: true,
// }

var err error
// cfg is defined in this file globally.
cfg, err = testEnv.Start()
Expect(err).NotTo(HaveOccurred())
Expect(cfg).NotTo(BeNil())
// var err error
// // cfg is defined in this file globally.
// cfg, err = testEnv.Start()
// Expect(err).NotTo(HaveOccurred())
// Expect(cfg).NotTo(BeNil())

err = configv1alpha1.AddToScheme(scheme.Scheme)
Expect(err).NotTo(HaveOccurred())
// err = configv1alpha1.AddToScheme(scheme.Scheme)
// Expect(err).NotTo(HaveOccurred())

//+kubebuilder:scaffold:scheme
// //+kubebuilder:scaffold:scheme

k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())
// k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
// Expect(err).NotTo(HaveOccurred())
// Expect(k8sClient).NotTo(BeNil())

})
// })

var _ = AfterSuite(func() {
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})
// var _ = AfterSuite(func() {
// By("tearing down the test environment")
// err := testEnv.Stop()
// Expect(err).NotTo(HaveOccurred())
// })
Loading