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

[Breaking change] Upgrade quarkus from 1.2.1.Final to 1.9.0.Final #46

Merged
merged 8 commits into from
Dec 10, 2020
3 changes: 0 additions & 3 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,7 @@ pipeline {
if (isFullRelease(TAG)) {
docker.withRegistry('https://index.docker.io/v1/', '8a04e3ab-c6db-44af-8198-1beb391c98d2') {
def image = docker.build("instana/instana-agent-operator:$VERSION", BUILD_ARGS)

image.push()
image.push('latest')
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wiggzz After discussion with Henning/Miel/Et al., we decided to no longer push the latest tag and to make the dependency between the operator image and the operator yaml more explicit, i.e. if a customer wants a more recent version of the operator, they have to update their operator yaml.

}
} else {
echo "Skipping pushing tag because this is a pre-release or branch."
Expand All @@ -46,7 +44,6 @@ pipeline {
// annoyingly no way to reuse the existing image with docker jenkins plugin.
// probably should just pull all of this into a shell script
def image = docker.build("scan.connect.redhat.com/ospid-6da7e6aa-00e1-4355-9c15-21d63fb091b6/instana-agent-operator:$VERSION", BUILD_ARGS)

image.push()
}
}
Expand Down
4 changes: 2 additions & 2 deletions docs/build.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Building the Instana Agent Operator from Source
The following command will build the `instana/instana-agent-operator` Docker image locally:

```bash
./mvnw package
./mvnw -C -B clean package
docker build -f src/main/docker/Dockerfile.jvm -t instana/instana-agent-operator .
```

Expand All @@ -13,6 +13,6 @@ To build the Docker image with GraalVM native image, use the following command:
> Note: The native image does not work yet because of [https://github.com/quarkusio/quarkus/issues/3077](https://github.com/quarkusio/quarkus/issues/3077)

```bash
./mvnw package -Pnative -Dnative-image.docker-build=true
./mvnw -C -B clean package -Pnative -Dnative-image.docker-build=true
docker build -f src/main/docker/Dockerfile.native -t instana/instana-agent-operator .
```
61 changes: 20 additions & 41 deletions docs/testing-with-kind.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,57 +10,31 @@ Kind (**K**ubernetes **in** **D**ocker) will set up a local cluster where all no
Set up a local Kubernetes Cluster with Kind
-------------------------------------------

Create `kind-config.yaml` with the following content (replace `/home` with `/Users` on macOS):

```yaml
kind: Cluster
apiVersion: kind.sigs.k8s.io/v1alpha3
nodes:
- role: control-plane
extraMounts:
- containerPath: /hosthome
hostPath: /home
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /home
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /home
```

Install [kind](https://kind.sigs.k8s.io/) (a single executable that can be downloaded from the [Github release page](https://github.com/kubernetes-sigs/kind/releases)) and run the following commands to create the cluster:

```sh
kind --config kind-config.yaml create cluster
export KUBECONFIG="$(kind get kubeconfig-path --name="kind")"
kubectl get nodes
./e2e-testing/with-kind/create-cluster.sh
```

You should see a cluster with one control-pane and two worker nodes up and running.

Prepare the Docker Images
-------------------------

In the `instana-agent-operator` project, build the `instana/instana-agent-operator` Docker image and push it to the local Kind cluster:
This script will also do the following:
- Build the `instana/instana-agent-operator` Docker image locally and load it into the local Kind cluster
- Pull the latest `instana/agent` Docker image locally and load it into the local Kind cluster

```sh
mvn package docker:build
kind load docker-image instana/instana-agent-operator
```
Install the Operator
--------------------

Pull the `instana/agent` Docker image and push it to the local Kind cluster:
Follow the steps described in [Install Operator Manually](https://www.instana.com/docs/setup_and_manage/host_agent/on/kubernetes/#install-operator-manually).

If your changes include the `instana-agent-operator.yaml`, you'll need to generate a new version of that file:
```sh
docker pull instana/agent
kind load docker-image instana/agent
./olm/create-artifacts.sh dev olm
```
Otherwise, you can download `instana-agent-operator.yaml` file from the latest [GitHub release](https://github.com/instana/instana-agent-operator/releases)

Install the Operator
--------------------

Follow the steps described in [Install Operator Manually](https://docs.instana.io/setup_and_manage/host_agent/on/kubernetes/#install-operator-manually)
Then in either case, change the `imagePullPolicy` for the `Deployment` from `Always` to `IfNotPresent`.
This will ensure that it uses the locally built `instana/instana-agent-operator` image instead of pulling from the remote registry.

Expected result
---------------
Expand All @@ -69,12 +43,17 @@ Expected result
kubectl -n instana-agent get pods
```

should show two instances of the `instana-agent-operator` (see the number of `replicas` configured in `instana-agent-operator-deploy.yaml`), and two instances of `instana-agent` (one on each node in the cluster).
This should show one instance of the `instana-agent-operator` (see the number of `replicas` configured in `olm/operator-resources/instana-agent-operator.yaml`), and two instances of `instana-agent` (one on each worker node in the cluster).

Delete a node
-------------

Delete one of the worker nodes that is running the `instana-agent` leader pod. The operator should reassign leadership to another agent pod.
You should see the reassignment if you tail the logs for the operator pod.

Clean up
--------

```sh
kind delete cluster
unset KUBECONFIG
./e2e-testing/with-kind/delete-cluster.sh
```
23 changes: 23 additions & 0 deletions e2e-testing/with-kind/create-cluster.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#!/bin/bash

set -e

VERSION=${1:-dev}
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"
BASE_DIR="$SCRIPT_DIR/../../"
OS_NAME=$(uname | tr '[:upper:]' '[:lower:]')
KIND_CONFIG_FILE="$SCRIPT_DIR/kind-config-$OS_NAME.yaml"

printf "%s\n" "Creating cluster with kind-config-$OS_NAME.yaml"
kind --config $KIND_CONFIG_FILE create cluster

kubectl get nodes

printf "%s\n" "Build and load Operator image into kind cluster"
./mvnw -C -B clean package
docker build -f $BASE_DIR/src/main/docker/Dockerfile.jvm -t instana/instana-agent-operator:$VERSION $BASE_DIR
kind load docker-image instana/instana-agent-operator

printf "%s\n" "Load Agent image into kind cluster"
docker pull instana/agent
kind load docker-image instana/agent
5 changes: 5 additions & 0 deletions e2e-testing/with-kind/delete-cluster.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/bash

set -e

kind delete cluster
15 changes: 15 additions & 0 deletions e2e-testing/with-kind/kind-config-darwin.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- containerPath: /hosthome
hostPath: /Users
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /Users
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /Users
15 changes: 15 additions & 0 deletions e2e-testing/with-kind/kind-config-linux.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
extraMounts:
- containerPath: /hosthome
hostPath: /home
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /home
- role: worker
extraMounts:
- containerPath: /hosthome
hostPath: /home
7 changes: 4 additions & 3 deletions olm/operator-resources/instana-agent-operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -67,9 +67,9 @@ rules:
- 'events'
verbs:
- 'create'
# -------------------------------------------------------------------------
# For the custom resource, the operator needs list, watch, get, update.
# -------------------------------------------------------------------------
# -----------------------------------------------------------------------------
# For the custom resource, the operator needs list, watch, get, update, create.
# -----------------------------------------------------------------------------
- apiGroups:
- 'instana.io'
resources:
Expand All @@ -79,6 +79,7 @@ rules:
- 'update'
- 'list'
- 'watch'
- 'create'
dlbock marked this conversation as resolved.
Show resolved Hide resolved
# -------------------------------------------------------------------------
# Below are the permissions are for the agent.
# The operator needs these permissions to create the agent's cluster role.
Expand Down
12 changes: 9 additions & 3 deletions olm/operator-resources/operator-artifacts.jsonnet
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,15 @@ local operatorResourcesWithVersion = std.map(addVersionToMetadataLabels, operato

local addVersionToDeploymentSpec(deployment) = deployment + {
spec+: {
template+: { metadata+: { labels+:
super.labels + { "app.kubernetes.io/version": version }
}}
template+: {
metadata+: {
labels+: super.labels + { "app.kubernetes.io/version": version }
},
spec+:
super.spec + {
containers: std.mapWithIndex(function(i, c) if i == 0 then c + {image: c.image + ":" + version} else c, super.containers)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the full version 0.3.9? This is good for now - but ideally in the future we should probably create major version tags, (so, in this case 0) and then use the major version tag here as opposed to the full version. But honestly we probably need a proper update strategy other than just "wait for the operator to crash and re-pull"... so, this is good.

Copy link
Contributor Author

@dlbock dlbock Dec 9, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is the full version, so it'll look like this: image: instana/instana-agent-operator:0.3.9

}
}
}
};
local isDeployment(res) = res.kind == "Deployment";
Expand Down
2 changes: 1 addition & 1 deletion pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
<properties>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<surefire-plugin.version>2.22.0</surefire-plugin.version>
<quarkus.version>1.2.1.Final</quarkus.version>
<quarkus.version>1.9.0.Final</quarkus.version>
<bouncycastle.version>1.62</bouncycastle.version>
<maven.compiler.source>1.8</maven.compiler.source>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
Expand Down
5 changes: 3 additions & 2 deletions src/main/java/com/instana/operator/AgentDeployer.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
import io.fabric8.kubernetes.api.model.VolumeBuilder;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.VolumeMountBuilder;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition;
import io.fabric8.kubernetes.api.model.apps.DaemonSet;
import io.fabric8.kubernetes.api.model.apps.DaemonSetList;
import io.fabric8.kubernetes.api.model.apps.DoneableDaemonSet;
Expand Down Expand Up @@ -70,6 +70,7 @@
import static com.instana.operator.util.StringUtils.isBlank;
import static io.fabric8.kubernetes.client.Watcher.Action.ADDED;
import static io.fabric8.kubernetes.client.Watcher.Action.DELETED;
import static java.net.HttpURLConnection.HTTP_CONFLICT;

@ApplicationScoped
public class AgentDeployer {
Expand Down Expand Up @@ -204,7 +205,7 @@ void createResource(int nRetries, MixedOperation<T, L, D, R> op, Factory<T, L, D
customResourceState.update(created);
} catch (KubernetesClientException e) {
// For status codes, see https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#http-status-codes
if (e.getCode() == 409 && nRetries > 1) {
if (e.getCode() == HTTP_CONFLICT && nRetries > 1) {
// Another resource of the same name exists in the same namespace.
// Maybe it's currently being removed, try again in a few seconds.
executor.schedule(() -> createResource(nRetries - 1, op, factory), 10, TimeUnit.SECONDS);
Expand Down
32 changes: 22 additions & 10 deletions src/main/java/com/instana/operator/CustomResourceState.java
Original file line number Diff line number Diff line change
@@ -1,23 +1,28 @@
package com.instana.operator;

import static com.instana.operator.client.KubernetesClientProducer.CRD_NAME;
import static com.instana.operator.util.ResourceUtils.name;
import static java.net.HttpURLConnection.HTTP_FORBIDDEN;

import java.util.Optional;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.instana.operator.customresource.DoneableInstanaAgent;
import com.instana.operator.customresource.InstanaAgent;
import com.instana.operator.customresource.InstanaAgentList;
import com.instana.operator.customresource.InstanaAgentStatus;
import com.instana.operator.customresource.ResourceInfo;

import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Pod;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import java.util.Optional;

import static com.instana.operator.client.KubernetesClientProducer.CRD_NAME;
import static com.instana.operator.util.ResourceUtils.name;

@ApplicationScoped
public class CustomResourceState {
Expand Down Expand Up @@ -127,7 +132,14 @@ private void update() {
try {
client.inNamespace(customResource.getMetadata().getNamespace()).createOrReplace(customResource);
} catch (Exception e) {
LOGGER.warn("Failed to update " + CRD_NAME + " " + name(customResource) + ": " + e.getMessage());
StringBuilder errorMessage = new StringBuilder();
errorMessage.append("Failed to update Custom Resource").append(CRD_NAME).append(name(customResource));
if (e instanceof KubernetesClientException) {
if (((KubernetesClientException)e).getCode() == HTTP_FORBIDDEN) {
errorMessage.append(". Please ensure the operator has the updated cluster role permissions.");
}
}
LOGGER.warn(errorMessage.toString() + ": " + e.getMessage());
// No need to System.exit() if we cannot update the status. Ignore this and carry on.
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/main/java/com/instana/operator/CustomResourceWatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,12 @@
import com.instana.operator.customresource.DoneableInstanaAgent;
import com.instana.operator.customresource.InstanaAgent;
import com.instana.operator.customresource.InstanaAgentList;
import com.instana.operator.env.NamespaceProducer;
import com.instana.operator.events.CustomResourceAdded;
import com.instana.operator.events.CustomResourceDeleted;
import com.instana.operator.events.CustomResourceModified;
import com.instana.operator.events.CustomResourceOtherInstanceAdded;
import com.instana.operator.events.OperatorLeaderElected;
import io.fabric8.kubernetes.client.Watch;
import io.fabric8.kubernetes.client.Watcher;
import io.fabric8.kubernetes.client.dsl.FilterWatchListMultiDeletable;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
import io.fabric8.kubernetes.client.dsl.Resource;
Expand Down Expand Up @@ -61,7 +59,7 @@ public class CustomResourceWatcher {
private final AtomicReference<InstanaAgent> current = new AtomicReference<>();

public void onElectedLeader(@ObservesAsync OperatorLeaderElected _ev) {
List<FilterWatchListMultiDeletable<InstanaAgent, InstanaAgentList, Boolean, Watch, Watcher<InstanaAgent>>> ops = new ArrayList<>();
List<FilterWatchListMultiDeletable<InstanaAgent, InstanaAgentList, Boolean, Watch>> ops = new ArrayList<>();
if (targetNamespaces.isEmpty()) {
LOGGER.info("Watching for " + KubernetesClientProducer.CRD_NAME + " resources in any namespace.");
ops.add(client.inAnyNamespace());
Expand All @@ -72,7 +70,7 @@ public void onElectedLeader(@ObservesAsync OperatorLeaderElected _ev) {
}
}
Cache<InstanaAgent, InstanaAgentList> cache = cacheService.newCache(InstanaAgent.class, InstanaAgentList.class);
for (FilterWatchListMultiDeletable<InstanaAgent, InstanaAgentList, Boolean, Watch, Watcher<InstanaAgent>> op : ops) {
for (FilterWatchListMultiDeletable<InstanaAgent, InstanaAgentList, Boolean, Watch> op : ops) {
cache.listThenWatch(op).subscribe(event -> handleCacheEvent(cache.get(event.getUid())));
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/instana/operator/cache/Cache.java
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public Optional<T> get(String uid) {
return map.get(uid);
}

public Observable<CacheEvent> listThenWatch(FilterWatchListDeletable<T, L, Boolean, Watch, Watcher<T>> op) {
public Observable<CacheEvent> listThenWatch(FilterWatchListDeletable<T, L, Boolean, Watch> op) {
return listThenWatch(new ListerWatcher<>(op));
}

Expand Down
4 changes: 2 additions & 2 deletions src/main/java/com/instana/operator/cache/ListerWatcher.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
*/
public class ListerWatcher<T extends HasMetadata, L extends KubernetesResourceList<T>> {

private final FilterWatchListDeletable<T, L, Boolean, Watch, Watcher<T>> op;
private final FilterWatchListDeletable<T, L, Boolean, Watch> op;

ListerWatcher(FilterWatchListDeletable<T, L, Boolean, Watch, Watcher<T>> op) {
ListerWatcher(FilterWatchListDeletable<T, L, Boolean, Watch> op) {
this.op = op;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import com.instana.operator.customresource.DoneableInstanaAgent;
import com.instana.operator.customresource.InstanaAgent;
import com.instana.operator.customresource.InstanaAgentList;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinition;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.dsl.MixedOperation;
Expand Down Expand Up @@ -34,7 +34,6 @@
import javax.net.ssl.X509TrustManager;
import java.net.Proxy;
import java.util.Arrays;
import java.util.Optional;
import java.util.concurrent.TimeUnit;

import static com.instana.operator.env.Environment.OPERATOR_NAMESPACE;
Expand Down
2 changes: 1 addition & 1 deletion src/test/java/com/instana/operator/AgentDeployerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinitionBuilder;
import io.fabric8.kubernetes.api.model.apiextensions.v1beta1.CustomResourceDefinitionBuilder;
import io.fabric8.kubernetes.api.model.apps.DaemonSet;
import io.fabric8.kubernetes.client.DefaultKubernetesClient;
import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer;
Expand Down