Skip to content

Commit

Permalink
feat: add support for Argo Rollouts resource (#166)
Browse files Browse the repository at this point in the history
  • Loading branch information
dnguy078 authored Aug 21, 2023
1 parent 1637e1c commit 67dd4c0
Show file tree
Hide file tree
Showing 18 changed files with 372 additions and 78 deletions.
4 changes: 1 addition & 3 deletions API.md
Original file line number Diff line number Diff line change
Expand Up @@ -1096,9 +1096,7 @@ that should be applied. The primary use case is in the PodAccessTemplate, where
controller (Deployment, DaemonSet, StatefulSet) can be used as the reference for the PodSpec
that is launched for the user. However, the operator may want to make modifications to the
PodSpec at launch time (eg, change the entrypoint command or arguments).</p>
<p>TODO: Add podAnnotations
TODO: Add podLabels
TODO: Add affinity</p>
<p>TODO: Add affinity</p>
</div>
<table>
<thead>
Expand Down
1 change: 1 addition & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ vet: ## Run go vet against code.

.PHONY: test
test: manifests generate envtest ## Run tests.
go mod download
KUBEBUILDER_ASSETS="$(shell $(ENVTEST) use $(ENVTEST_K8S_VERSION) --bin-dir $(LOCALBIN) -p path)" go test -v $(shell go list ./... | grep -v 'e2e') -coverprofile cover.out -covermode=atomic -race

##@ Build
Expand Down
4 changes: 4 additions & 0 deletions config/crd/bases/crds.wizardofoz.co_execaccesstemplates.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,13 +86,17 @@ spec:
description: "Defines the \"APIVersion\" of the resource being
referred to. Eg, \"apps/v1\". \n TODO: Figure out how to regex
validate that it has a \"/\" in it"
enum:
- apps/v1
- argoproj.io/v1alpha1
type: string
kind:
description: Defines the "Kind" of resource being referred to.
enum:
- Deployment
- DaemonSet
- StatefulSet
- Rollout
type: string
name:
description: Defines the "metadata.Name" of the target resource.
Expand Down
140 changes: 88 additions & 52 deletions config/crd/bases/crds.wizardofoz.co_podaccesstemplates.yaml

Large diffs are not rendered by default.

8 changes: 8 additions & 0 deletions config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,14 @@ rules:
- get
- list
- watch
- apiGroups:
- argoproj.io
resources:
- rollouts
verbs:
- get
- list
- watch
- apiGroups:
- crds.wizardofoz.co
resources:
Expand Down
31 changes: 31 additions & 0 deletions examples/rollout.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
spec:
replicas: 5
strategy:
canary:
steps:
- setWeight: 20
- pause: {duration: 1}
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollouts-demo
template:
metadata:
labels:
app: rollouts-demo
spec:
containers:
- name: rollouts-demo
image: nginx:latest
ports:
- name: http
containerPort: 80
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ module github.com/diranged/oz
go 1.20

require (
github.com/argoproj/argo-rollouts v1.5.1
github.com/fatih/color v1.15.0
github.com/go-logr/logr v1.2.4
github.com/ivanpirog/coloredcobra v1.0.1
Expand Down Expand Up @@ -34,14 +35,14 @@ require (
github.com/gogo/protobuf v1.3.2 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/btree v1.1.2 // indirect
github.com/google/gnostic-models v0.6.8 // indirect
github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/pprof v0.0.0-20210720184732-4bb14d4b1be1 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/imdario/mergo v0.3.16 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
Expand Down
10 changes: 6 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/argoproj/argo-rollouts v1.5.1 h1:P1C6oIWn6fwtPvB3u04NQlUGIv8cq/aJvUkbwciuWYo=
github.com/argoproj/argo-rollouts v1.5.1/go.mod h1:OaOf+oZawsss6fy+9WEDy4IaSbwuRteBj1X2QiVfqdA=
github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA=
github.com/benbjohnson/clock v1.3.0 h1:ip6w0uFQkncKQ979AypyG0ER7mqUSBdKLOgAle/AT8A=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
Expand Down Expand Up @@ -64,8 +66,8 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v1.0.1 h1:gK4Kx5IaGY9CD5sPJ36FHiBJ6ZXl0kilRiiCj+jdYp4=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/btree v1.1.2 h1:xf4v41cLI2Z6FxbKm+8Bu+m8ifhj15JuZ9sa0jZCMUU=
github.com/google/btree v1.1.2/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/gnostic-models v0.6.8 h1:yo/ABAfM5IMRsS1VnXjTBvUb61tFIHozhlYvRgGre9I=
github.com/google/gnostic-models v0.6.8/go.mod h1:5n7qKqH0f5wFt+aWF8CW6pZLLNOfYuF5OpfBSENuI8U=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
Expand All @@ -86,8 +88,8 @@ github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaU
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 h1:pdN6V1QBWetyv/0+wjACpqVH+eVULgEjkurDLq3goeM=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.16 h1:wwQJbIsHYGMUyLSPrEq1CT16AhnhNJQ51+4fdHUnCl4=
github.com/imdario/mergo v0.3.16/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
Expand Down
5 changes: 3 additions & 2 deletions internal/api/v1alpha1/cross_version_object_reference.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,12 @@ type CrossVersionObjectReference struct {
// TODO: Figure out how to regex validate that it has a "/" in it
//
// +kubebuilder:validation:Required
// +kubebuilder:validation:Enum=apps/v1;argoproj.io/v1alpha1
APIVersion string `json:"apiVersion"`

// Defines the "Kind" of resource being referred to.
// +kubebuilder:validation:Required
// +kubebuilder:validation:Enum=Deployment;DaemonSet;StatefulSet
// +kubebuilder:validation:Enum=Deployment;DaemonSet;StatefulSet;Rollout
Kind ControllerKind `json:"kind"`

// Defines the "metadata.Name" of the target resource.
Expand Down Expand Up @@ -68,7 +69,7 @@ func (r *CrossVersionObjectReference) GetGroupVersionKind() schema.GroupVersionK
}
}

// GetObject returns a generic unstrucutred resource that points to the desired API object. Because
// GetObject returns a generic unstructured resource that points to the desired API object. Because
// this is unstructured (for now), you can really only use this to get metadata back from the API
// about the resource.
//
Expand Down
2 changes: 0 additions & 2 deletions internal/api/v1alpha1/pod_spec_mutation_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ const (
// that is launched for the user. However, the operator may want to make modifications to the
// PodSpec at launch time (eg, change the entrypoint command or arguments).
//
// TODO: Add podAnnotations
// TODO: Add podLabels
// TODO: Add affinity
type PodTemplateSpecMutationConfig struct {
// DefaultContainerName allows the operator to define which container is considered the default
Expand Down
146 changes: 140 additions & 6 deletions internal/builders/podaccessbuilder/create_access_resources_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"

rolloutsv1alpha1 "github.com/argoproj/argo-rollouts/pkg/apis/rollouts/v1alpha1"
appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
Expand All @@ -22,12 +23,14 @@ import (
var _ = Describe("RequestReconciler", Ordered, func() {
Context("CreateAccessResources()", func() {
var (
ctx = context.Background()
ns *corev1.Namespace
deployment *appsv1.Deployment
request *v1alpha1.PodAccessRequest
template *v1alpha1.PodAccessTemplate
builder = PodAccessBuilder{}
ctx = context.Background()
ns *corev1.Namespace
deployment *appsv1.Deployment
request *v1alpha1.PodAccessRequest
rolloutRequest *v1alpha1.PodAccessRequest
template *v1alpha1.PodAccessTemplate
rolloutTemplate *v1alpha1.PodAccessTemplate
builder = PodAccessBuilder{}
)

BeforeAll(func() {
Expand Down Expand Up @@ -72,6 +75,39 @@ var _ = Describe("RequestReconciler", Ordered, func() {
err = k8sClient.Create(ctx, deployment)
Expect(err).To(Not(HaveOccurred()))

By("Creating a Rollout to reference for the test")
rollout := &rolloutsv1alpha1.Rollout{
ObjectMeta: metav1.ObjectMeta{
Name: "rollout-test",
Namespace: ns.Name,
},
Spec: rolloutsv1alpha1.RolloutSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"testLabel": "testValue",
},
},
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"testLabel": "testValue",
},
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Name: "test",
Image: "nginx:latest",
},
},
},
},
},
}

err = k8sClient.Create(ctx, rollout)
Expect(err).To(Not(HaveOccurred()))

By("Should have an PodAccessTemplate to test against")
cpuReq, _ := resource.ParseQuantity("1")
template = &v1alpha1.PodAccessTemplate{
Expand Down Expand Up @@ -108,6 +144,40 @@ var _ = Describe("RequestReconciler", Ordered, func() {
err = k8sClient.Create(ctx, template)
Expect(err).ToNot(HaveOccurred())

rolloutTemplate = &v1alpha1.PodAccessTemplate{
ObjectMeta: metav1.ObjectMeta{
Name: utils.RandomString(8),
Namespace: ns.GetName(),
},
Spec: v1alpha1.PodAccessTemplateSpec{
AccessConfig: v1alpha1.AccessConfig{
AllowedGroups: []string{"testGroupA"},
DefaultDuration: "1h",
MaxDuration: "2h",
},
ControllerTargetRef: &v1alpha1.CrossVersionObjectReference{
APIVersion: "argoproj.io/v1alpha1",
Kind: "Rollout",
Name: "rollout-test",
},
ControllerTargetMutationConfig: &v1alpha1.PodTemplateSpecMutationConfig{
DefaultContainerName: "test",
Command: &[]string{"/bin/sleep"},
Args: &[]string{"100"},
Env: []corev1.EnvVar{
{Name: "FOO", Value: "BAR"},
},
Resources: corev1.ResourceRequirements{
Requests: map[corev1.ResourceName]resource.Quantity{
"cpu": cpuReq,
},
},
},
},
}
err = k8sClient.Create(ctx, rolloutTemplate)
Expect(err).ToNot(HaveOccurred())

By("Should have an PodAccessRequest built to test against")
request = &v1alpha1.PodAccessRequest{
ObjectMeta: metav1.ObjectMeta{
Expand All @@ -120,6 +190,19 @@ var _ = Describe("RequestReconciler", Ordered, func() {
}
err = k8sClient.Create(ctx, request)
Expect(err).ToNot(HaveOccurred())

// verify podaccess request with Rollout
rolloutRequest = &v1alpha1.PodAccessRequest{
ObjectMeta: metav1.ObjectMeta{
Name: "createaccessresource-rollout-test",
Namespace: ns.GetName(),
},
Spec: v1alpha1.PodAccessRequestSpec{
TemplateName: rolloutTemplate.GetName(),
},
}
err = k8sClient.Create(ctx, rolloutRequest)
Expect(err).ToNot(HaveOccurred())
})

AfterAll(func() {
Expand Down Expand Up @@ -178,5 +261,56 @@ var _ = Describe("RequestReconciler", Ordered, func() {
Expect(foundRoleBinding.RoleRef.Name).To(Equal(foundRole.GetName()))
Expect(foundRoleBinding.Subjects[0].Name).To(Equal("testGroupA"))
})

It("CreateAccessResources() should succeed with Rollout", func() {
rolloutRequest.Status.PodName = ""

// Execute
ret, err := builder.CreateAccessResources(ctx, k8sClient, rolloutRequest, rolloutTemplate)

// VERIFY: No error returned
Expect(err).ToNot(HaveOccurred())

// VERIFY: Proper status string returned
Expect(ret).To(MatchRegexp(fmt.Sprintf(
"Success. Pod %s-.*, Role %s-.*, RoleBinding %s.* created",
rolloutRequest.GetName(),
rolloutRequest.GetName(),
rolloutRequest.GetName(),
)))

// VERIFY: Pod Created as expected
foundPod := &corev1.Pod{}
err = k8sClient.Get(ctx, types.NamespacedName{
Name: bldutil.GenerateResourceName(rolloutRequest),
Namespace: ns.GetName(),
}, foundPod)
Expect(err).ToNot(HaveOccurred())
Expect(foundPod.GetOwnerReferences()).ToNot(BeNil())
Expect(foundPod.Spec.Containers[0].Command[0]).To(Equal("/bin/sleep"))
Expect(foundPod.Spec.Containers[0].Args[0]).To(Equal("100"))

// VERIFY: Role Created as expected
foundRole := &rbacv1.Role{}
err = k8sClient.Get(ctx, types.NamespacedName{
Name: bldutil.GenerateResourceName(rolloutRequest),
Namespace: ns.GetName(),
}, foundRole)
Expect(err).ToNot(HaveOccurred())
Expect(foundRole.GetOwnerReferences()).ToNot(BeNil())
Expect(foundRole.Rules[0].ResourceNames[0]).To(Equal(foundPod.GetName()))
Expect(foundRole.Rules[1].ResourceNames[0]).To(Equal(foundPod.GetName()))

// VERIFY: RoleBinding Created as expected
foundRoleBinding := &rbacv1.RoleBinding{}
err = k8sClient.Get(ctx, types.NamespacedName{
Name: bldutil.GenerateResourceName(rolloutRequest),
Namespace: ns.GetName(),
}, foundRoleBinding)
Expect(err).ToNot(HaveOccurred())
Expect(foundRoleBinding.GetOwnerReferences()).ToNot(BeNil())
Expect(foundRoleBinding.RoleRef.Name).To(Equal(foundRole.GetName()))
Expect(foundRoleBinding.Subjects[0].Name).To(Equal("testGroupA"))
})
})
})
Loading

0 comments on commit 67dd4c0

Please sign in to comment.