Skip to content

Commit

Permalink
Added DEVELOPMENT.md and improved tests
Browse files Browse the repository at this point in the history
  • Loading branch information
rameshmalla committed Dec 10, 2023
1 parent c204fbd commit e5b1afd
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 14 deletions.
2 changes: 2 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# Contributor Covenant Code of Conduct

_**In the grand play of code, let’s make kindness our main function. After all, a little humor and a sprinkle of 'please' and 'thank you' never hurt anyone's development stack!**_

## Our Pledge

In the interest of fostering an open and welcoming environment, we as
Expand Down
47 changes: 47 additions & 0 deletions DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# Developers guide

The operator is a Spring Boot project. To build the project, you need the following prerequisites:
- A local installation of JDK17
- Gradle `./gradlew clean build` to execute the tests and build the operator.

To test and deploy the operator in your local environment, you need the following setup:
- [Docker](https://www.docker.com/) to build the operator image with your local changes.
- [minikube](https://minikube.sigs.k8s.io/docs/start/) to deploy the operator and test your changes.

## How I test my changes

Once I have made some changes to the code, I follow the below workflow:

- Run unit and integration tests.
- Build operator
```
~ ./gradlew clean build
```
- Build the operator docker image with the new changes.
```
~ minikube image build -t configs-operator:test_5 .
```
Note that I used minikube client to build the docker image. Quote from [minikube](https://minikube.sigs.k8s.io/docs/handbook/pushing/#1-pushing-directly-to-the-in-cluster-docker-daemon-docker-env)
> When using a container or VM driver (all drivers except none), you can reuse the Docker daemon inside minikube cluster. This means you don’t have to build on your host machine and push the image into a docker registry. You can just build inside the same docker daemon as minikube which speeds up local experiments.
- Update [./install/cluster/Config-Operator.yaml](https://github.com/rameshmalla/k8s-custom-configmap/blob/main/install/cluster/Config-Operator.yaml#L31) with your new test image `configs-operator:test_5`.
- Apply the CRD and operator manifest in the `./install` folder.
```shell
~ kubectl apply -f ./install/cluster/configmapcustomresources.rcube.com-v1.yml
customresourcedefinition.apiextensions.k8s.io/configmapcustomresources.rcube.com created

~ kubectl apply -f ./install/cluster/Config-Operator.yaml
namespace/configs-operator created
serviceaccount/configs-operator created
deployment.apps/configs-operator created
clusterrole.rbac.authorization.k8s.io/configs-operator-role created
clusterrolebinding.rbac.authorization.k8s.io/configs-operator-admin created
```
- Apply application [./install/testing/app-deployment.yaml](https://github.com/rameshmalla/k8s-custom-configmap/blob/main/install/testing/app-deployment.yaml) manifest.
```shell
~ kubectl apply -f ./install/testing/app-deployment.yaml
namespace/local created
configmapcustomresource.rcube.com/application-toggles-config created
deployment.apps/nginx-deployment created
```

- Test my changes against the deployed application and the operator.
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,8 @@ data:
## Example
Apply this [example](./install/testing/app-deployment.yaml) to play with the custom config-map resource.

## Developers guide
Refer to this [page](DEVELOPMENT.md).
## Getting help
If you have questions, concerns, bug reports, etc., please file an issue in this repository's [Issue Tracker](https://github.com/rameshmalla/k8s-custom-configmap/issues).

Expand Down
1 change: 0 additions & 1 deletion install/cluster/Config-Operator.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ spec:
containers:
- name: operator
image: malla/configs-operator:main
imagePullPolicy: IfNotPresent
resources:
requests:
memory: 512Mi
Expand Down
Original file line number Diff line number Diff line change
@@ -1,28 +1,35 @@
package com.rcube.configmap.conifgvalidator;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

import com.rcube.configmap.TestDataUtil;
import com.rcube.configmap.operator.ConfigMapCustomResource;
import com.rcube.configmap.operator.CustomConfigMapSpec;
import io.fabric8.kubernetes.api.model.ConfigMap;
import io.fabric8.kubernetes.api.model.ConfigMapVolumeSource;
import io.fabric8.kubernetes.api.model.HasMetadata;
import io.fabric8.kubernetes.api.model.Namespace;
import io.fabric8.kubernetes.api.model.NamespaceBuilder;
import io.fabric8.kubernetes.api.model.ObjectMeta;
import io.fabric8.kubernetes.api.model.ObjectMetaBuilder;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition;
import io.fabric8.kubernetes.api.model.apps.Deployment;
import io.fabric8.kubernetes.client.KubernetesClient;
import io.javaoperatorsdk.operator.springboot.starter.test.EnableMockOperator;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.tuple.Pair;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.InputStream;
import java.net.URISyntaxException;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;

@SpringBootTest
@EnableMockOperator(
crdPaths = "install/cluster/configmapcustomresources.rcube.com-v1.yml"
Expand All @@ -32,7 +39,7 @@ public class ConfigValidatorTest {
@Autowired
private KubernetesClient client;

private static Pair<String,String> TEST_DATA = TestDataUtil.validSchemaData();
private static final Pair<String, String> TEST_DATA = TestDataUtil.validSchemaData();

@Test
public void contextLoads() {
Expand All @@ -46,18 +53,15 @@ public void contextLoads() {
}

@Test
public void test() {
public void testShouldCreateConfigMapFromCustomResource() {
String testNS = "test-ns";
client.namespaces().resource(namespace(testNS)).create();
assertNotNull(client.namespaces().withName(testNS).get());
// create a CR
client.resources(ConfigMapCustomResource.class).inNamespace(testNS)
.resource(getValidConfigSpec())
.create();
final ConfigMapCustomResource resource = client.resources(ConfigMapCustomResource.class)
.inNamespace(testNS)
.withName("test-resource")
.get();
final ConfigMapCustomResource resource = getResource(testNS,"test-resource", ConfigMapCustomResource.class);

assertNotNull(resource);
assertEquals(TEST_DATA.getRight(), resource.getSpec().getConfig().getData().get("test.json"));
Expand All @@ -73,6 +77,34 @@ public void test() {
.withName("test-resource").get()));
}

@Test
public void testShouldCreateVersionedConfigMapFromCustomResource() throws URISyntaxException {
final String nameSpace = "local";
final String deploymentName = "nginx-deployment";
client.load(fetchResource("app-deployment.yaml"))
.create();
await()
.atMost(5, TimeUnit.SECONDS)
.untilAsserted(
() ->
{
final Deployment resource = getResource(nameSpace, deploymentName, Deployment.class);
assertNotNull(resource);
resource.getSpec()
.getTemplate()
.getSpec()
.getVolumes()
.stream()
.map(Volume::getConfigMap)
.filter(Objects::nonNull)
.map(ConfigMapVolumeSource::getName)
.forEach(requestedConfigMaps -> {
System.out.println(requestedConfigMaps);
assertNotNull(getResource(nameSpace, requestedConfigMaps, ConfigMap.class));
});
});
}

private ConfigMapCustomResource getValidConfigSpec() {
final ObjectMeta objectMeta = new ObjectMeta();
objectMeta.setName("test-resource");
Expand All @@ -85,11 +117,23 @@ private ConfigMapCustomResource getValidConfigSpec() {
return resource;
}

private <T extends HasMetadata> T getResource(final String nameSpace,
final String name,
final Class<T> resourceType) {
return client.resources(resourceType)
.inNamespace(nameSpace)
.withName(name).get();
}

private Namespace namespace(String ns) {
return new NamespaceBuilder()
.withMetadata(
new ObjectMetaBuilder().withName(ns).build())
.build();
}

private InputStream fetchResource(String fileName) {
return ConfigValidatorTest.class.getClassLoader().getResourceAsStream(fileName);
}

}
64 changes: 64 additions & 0 deletions src/test/resources/app-deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
apiVersion: v1
kind: Namespace
metadata:
name: local
---
apiVersion: "rcube.com/v1"
kind: ConfigMapCustomResource
metadata:
namespace: local
name: application-toggles-config
labels:
application: nginx-deployment
spec:
config:
data:
application-toggles-config.json: |
{
"startNewFlow": true
}
schema:
application-toggles-config.json: |
{
"type": "object",
"properties": {
"startNewFlow": {
"type": "boolean"
}
},
"required": [
"startNewFlow"
]
}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
namespace: local
labels:
app: nginx
config-map-version: "master-10"
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
volumeMounts:
- name: application-toggles-config
mountPath: /etc/config
ports:
- containerPort: 80
volumes:
- name: application-toggles-config
configMap:
name: "application-toggles-config-master-10"

0 comments on commit e5b1afd

Please sign in to comment.