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

DOTNET-5289 Add support for argo rollouts #150

Merged
merged 6 commits into from
Oct 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion .github/workflows/pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ jobs:
with:
status: ${{ job.status }}
message: |-
Version <https://github.com/Contrast-Security-Inc/agent-operator/releases/tag/v${{ env.BUILD_VERSION }}|v${{ env.BUILD_VERSION }}> of the agent-operator was released!
Version <https://github.com/Contrast-Security-OSS/agent-operator/releases/tag/v${{ env.BUILD_VERSION }}|v${{ env.BUILD_VERSION }}> of the agent-operator was released!
fallback: |-
[GitHub] Version v${{ env.BUILD_VERSION }} of the agent-operator was released!
env:
Expand Down
41 changes: 41 additions & 0 deletions docs/testing-argo-rollouts.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Testing Argo Rollouts

Follow [argo rollouts installation](https://argo-rollouts.readthedocs.io/en/stable/installation/) instructions to install the controller and kubectl plugin

## Actually Testing

Deploy `install-prod.yaml` from [releases](https://github.com/Contrast-Security-OSS/agent-operator/releases).

```bash
# Install the production manifests.
kubectl apply -f install-prod.yaml

# Wait for the cluster to converge.
watch kubectl -n contrast-agent-operator get pods

# Check the logs for any problems.
kubectl -n contrast-agent-operator logs deployment/contrast-agent-operator -f
```

Then we can deploy argo rollout examples

```bash
# Install the Argo Rollout only examples (e.g. Rollout).
kubectl apply -k ./manifests/examples/argo-rollouts

# Promote the rollout to finish the agent injection
kubectl argo rollouts promote dotnet-core-app

# Inspect rollout in another terminal
kubectl argo rollouts get rollout dotnet-core-app --watch
```

We can also force a change on the container to trigger a rollout

```bash
# Optional: Force a change to the container to trigger a rollout
kubectl argo rollouts set image dotnet-core-app dotnet-core-app=contrast/sample-app-aspnetcore:main

# Promote the rollout to finish
kubectl argo rollouts promote dotnet-core-app
```
2 changes: 1 addition & 1 deletion docs/testing-openshift.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Setup:

## Actually Testing

Deploy `install-prod.yaml` from [releases](https://github.com/Contrast-Security-Inc/agent-operator/releases).
Deploy `install-prod.yaml` from [releases](https://github.com/Contrast-Security-OSS/agent-operator/releases).

```bash
# Install the production manifests.
Expand Down
33 changes: 33 additions & 0 deletions manifests/examples/argo-rollouts/base/dotnet-core.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: dotnet-core-app
namespace: default
labels:
app: dotnet-core-app
spec:
replicas: 2
strategy:
canary:
steps:
- setWeight: 20
- pause: {}
- setWeight: 40
- pause: {duration: 10}
revisionHistoryLimit: 1
selector:
matchLabels:
app: dotnet-core-app
template:
metadata:
labels:
app: dotnet-core-app
annotations:
test: test
spec:
containers:
- image: contrast/sample-app-aspnetcore:latest
name: dotnet-core-app
ports:
- containerPort: 80
name: http
52 changes: 52 additions & 0 deletions manifests/examples/argo-rollouts/base/minimal-setup.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
apiVersion: agents.contrastsecurity.com/v1beta1
kind: AgentInjector
metadata:
name: example-injector-dotnet-core
spec:
enabled: true
version: latest
type: dotnet-core
selector:
images:
- "*"
labels:
- name: app
value: dotnet-core-app
connection:
name: example-agent-connection
configuration:
name: example-agent-configuration
---
apiVersion: agents.contrastsecurity.com/v1beta1
kind: AgentConnection
metadata:
name: example-agent-connection
spec:
url: http://localhost
apiKey:
secretName: example-agent-connection-secret
secretKey: apiKey
serviceKey:
secretName: example-agent-connection-secret
secretKey: serviceKey
userName:
secretName: example-agent-connection-secret
secretKey: userName
---
apiVersion: v1
kind: Secret
metadata:
name: example-agent-connection-secret
type: Opaque
stringData:
apiKey: apiKey
serviceKey: serviceKey
userName: userName
---
apiVersion: agents.contrastsecurity.com/v1beta1
kind: AgentConfiguration
metadata:
name: example-agent-configuration
spec:
yaml: |
enabled: true
4 changes: 4 additions & 0 deletions manifests/examples/argo-rollouts/kustomization.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
namespace: default
resources:
- base/dotnet-core.yaml
- base/minimal-setup.yaml
1 change: 1 addition & 0 deletions manifests/generate-manifests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ dotnet run --no-build --project $project -- generator rbac -o $output\rbac\
# "$($output)operator\kustomization.yaml"
"$($output)crd\deploymentconfigs_apps_openshift_io.yaml"
"$($output)crd\dynakubes_dynatrace_com.yaml"
"$($output)crd\rollouts_argoproj_io.yaml"
"$($output)crd\kustomization.yaml"
) | ForEach-Object {
Write-Host "Cleaning up bad object $_"
Expand Down
60 changes: 31 additions & 29 deletions manifests/install/all/operator/base/rbac/cluster-role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -6,35 +6,14 @@ metadata:
app.kubernetes.io/name: operator
app.kubernetes.io/part-of: contrast-agent-operator
rules:
- apiGroups:
- ""
- agents.contrastsecurity.com
- coordination.k8s.io
resources:
- secrets
- agentconnections
- agentconfigurations
- leases
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- create
- get
- list
- watch
- patch
- update
- delete
- apiGroups:
- apps
- argoproj.io
- ""
- apps.openshift.io
resources:
- daemonsets
- rollouts
- deployments
- statefulsets
- pods
Expand All @@ -46,21 +25,44 @@ rules:
- patch
- apiGroups:
- agents.contrastsecurity.com
- dynatrace.com
resources:
- agentinjectors
- clusteragentconfigurations
- dynakubes
- clusteragentconnections
verbs:
- get
- list
- watch
- apiGroups:
- agents.contrastsecurity.com
- ""
- coordination.k8s.io
resources:
- agentconnections
- secrets
- agentconfigurations
- leases
verbs:
- '*'
- apiGroups:
- agents.contrastsecurity.com
- dynatrace.com
resources:
- clusteragentconnections
- dynakubes
- clusteragentconfigurations
- agentinjectors
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- create
- get
- list
- watch
- patch
- update
- delete
- apiGroups:
- ""
resources:
Expand Down Expand Up @@ -121,4 +123,4 @@ rules:
verbs:
- get
- patch
- update
- update
19 changes: 19 additions & 0 deletions src/Contrast.K8s.AgentOperator/Controllers/RolloutController.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using Contrast.K8s.AgentOperator.Core.Kube;
using Contrast.K8s.AgentOperator.Core.State;
using Contrast.K8s.AgentOperator.Entities.Argo;
using JetBrains.Annotations;
using KubeOps.Operator.Rbac;

namespace Contrast.K8s.AgentOperator.Controllers
{
[EntityRbac(typeof(V1Alpha1Rollout), Verbs = VerbConstants.ReadAndPatch), UsedImplicitly]
public class RolloutController : GenericController<V1Alpha1Rollout>
{
public RolloutController(IEventStream eventStream) : base(eventStream)
{
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
using Contrast.K8s.AgentOperator.Core.State;
using Contrast.K8s.AgentOperator.Core.State.Resources;
using Contrast.K8s.AgentOperator.Core.State.Resources.Interfaces;
using Contrast.K8s.AgentOperator.Entities.Argo;
using Contrast.K8s.AgentOperator.Entities.OpenShift;
using JetBrains.Annotations;
using k8s.Models;
Expand Down Expand Up @@ -85,6 +86,7 @@ private ValueTask PatchToDesiredState(DesiredState desiredState, ResourceIdentit
DaemonSetResource => PatchToDesiredStateDaemonSet(desiredState, identity),
StatefulSetResource => PatchToDesiredStateStatefulSet(desiredState, identity),
DeploymentResource => PatchToDesiredStateDeployment(desiredState, identity),
RolloutResource => PatchToDesiredStateRollout(desiredState, identity),
DeploymentConfigResource => PatchToDesiredStateDeploymentConfig(desiredState, identity),
_ => throw new ArgumentOutOfRangeException()
};
Expand All @@ -108,6 +110,12 @@ private async ValueTask PatchToDesiredStateDeployment(DesiredState desiredState,
await _patcher.Patch<V1Deployment>(identity.Name, identity.Namespace, o => { PatchAnnotations(desiredState, o.Spec.Template); });
}

private async ValueTask PatchToDesiredStateRollout(DesiredState desiredState, NamespacedResourceIdentity identity)
{
await _state.MarkAsDirty(identity);
await _patcher.Patch<V1Alpha1Rollout>(identity.Name, identity.Namespace, o => { PatchAnnotations(desiredState, o.Spec.Template); });
}

private async ValueTask PatchToDesiredStateDeploymentConfig(DesiredState desiredState, NamespacedResourceIdentity identity)
{
await _state.MarkAsDirty(identity);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using System.Threading;
using System.Threading.Tasks;
using Contrast.K8s.AgentOperator.Core.Kube;
using Contrast.K8s.AgentOperator.Core.State.Resources;
using Contrast.K8s.AgentOperator.Entities.Argo;
using JetBrains.Annotations;
using k8s.Models;
using MediatR;

namespace Contrast.K8s.AgentOperator.Core.State.Appliers
{
[UsedImplicitly]
public class RolloutApplier : BaseApplier<V1Alpha1Rollout, RolloutResource>
{
public RolloutApplier(IStateContainer stateContainer, IMediator mediator) : base(stateContainer, mediator)
{
}

public override ValueTask<RolloutResource> CreateFrom(V1Alpha1Rollout entity, CancellationToken cancellationToken = default)
{
var resource = new RolloutResource(
entity.Uid(),
entity.Metadata.GetLabels(),
entity.Spec.Template.GetPod(),
entity.Spec.Selector.ToPodSelector()
);

return ValueTask.FromResult(resource);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using System.Collections.Generic;
using Contrast.K8s.AgentOperator.Core.State.Resources.Interfaces;
using Contrast.K8s.AgentOperator.Core.State.Resources.Primitives;

namespace Contrast.K8s.AgentOperator.Core.State.Resources
{
public record RolloutResource(string Uid,
IReadOnlyCollection<MetadataLabel> Labels,
PodTemplate PodTemplate,
PodSelector Selector)
: IResourceWithPodTemplate;
}
19 changes: 19 additions & 0 deletions src/Contrast.K8s.AgentOperator/Entities/Argo/V1Alpha1Rollout.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// Contrast Security, Inc licenses this file to you under the Apache 2.0 License.
// See the LICENSE file in the project root for more information.

using JetBrains.Annotations;
using k8s.Models;
using KubeOps.Operator.Entities;

namespace Contrast.K8s.AgentOperator.Entities.Argo
{
[KubernetesEntity(Group = "argoproj.io", ApiVersion = "v1alpha1", Kind = "Rollout", PluralName = "rollouts"), UsedImplicitly]
public class V1Alpha1Rollout : CustomKubernetesEntity<V1Alpha1Rollout.RolloutSpec>
{
//Drop-in replacement for Deployment (with additional fields for the rollout info)
public class RolloutSpec : V1DeploymentSpec
{
}
}

}