diff --git a/pom.xml b/pom.xml index 8004551194a873d468c686a0e3117cd09319cf2c..c588a8bbe364b63f11c72f8f3eebd217b4be5025 100644 --- a/pom.xml +++ b/pom.xml @@ -191,6 +191,11 @@ <artifactId>slf4j-api</artifactId> </dependency> + <dependency> + <groupId>io.fabric8</groupId> + <artifactId>kubernetes-httpclient-okhttp</artifactId> + <version>${fabric8.version}</version> + </dependency> <!-- Testing --> @@ -238,12 +243,6 @@ <version>${fabric8.version}</version> <scope>test</scope> </dependency> - <dependency> - <groupId>io.fabric8</groupId> - <artifactId>kubernetes-httpclient-okhttp</artifactId> - <version>${fabric8.version}</version> - <scope>test</scope> - </dependency> diff --git a/src/main/java/org/etsi/osl/cridge/KubernetesClientResource.java b/src/main/java/org/etsi/osl/cridge/KubernetesClientResource.java index 5380cc6b92169569ffb5a32b8eb3c03e2a45dd87..3547b839c0ad5ca29ed216fe1d0358196bbfcd5f 100644 --- a/src/main/java/org/etsi/osl/cridge/KubernetesClientResource.java +++ b/src/main/java/org/etsi/osl/cridge/KubernetesClientResource.java @@ -341,7 +341,7 @@ public class KubernetesClientResource { } - private KubernetesSecret KubernetesSecret2OpensliceResource(Secret secret) { + KubernetesSecret KubernetesSecret2OpensliceResource(Secret secret) { String baseCRD = String.format( "%s@%s@%s@%s", @@ -404,19 +404,9 @@ public class KubernetesClientResource { logger.debug("============ Deploy crspec =============" ); - logger.debug("Check if this CRIDGE instance is related to this kubernets cluster context" ); - if ( (headers.get("currentContextCluster") ==null) || - (headers.get("clusterMasterURL") ==null) || - ( ! headers.get("currentContextCluster").equals( kubernetesContextDefinition.getCurrentContextCluster() )) || - ( ! headers.get("clusterMasterURL").equals( kubernetesContextDefinition.getMasterURL() ))) { - - logger.debug("Will return SEE OTHER header.currentContextCluster={}, this.context= {} header.clusterMasterURLclusterMasterURL={}, this.context= {}", - headers.get("currentContextCluster"), - kubernetesContextDefinition.getCurrentContextCluster(), - headers.get("clusterMasterURL"), - kubernetesContextDefinition.getMasterURL() ); + logger.debug("Check if this CRIDGE instance is related to this kubernets cluster context"); + if (!checkCRIDGEClusterContext(headers)) { return "SEE OTHER"; - } logger.debug("Deploy the following CR:" ); @@ -605,7 +595,7 @@ public class KubernetesClientResource { - try (final KubernetesClient k8s = new KubernetesClientBuilder().build()) { + try { GenericKubernetesResource gkr = Serialization.unmarshal( crspec ); headers.forEach(((hname, hval) ->{ @@ -617,7 +607,7 @@ public class KubernetesClientResource { } })); gkr.getMetadata().setName( (String) headers.get("org.etsi.osl.prefixName")) ; - Resource<GenericKubernetesResource> dummyObject = k8s.resource( gkr ); + Resource<GenericKubernetesResource> dummyObject = kubernetesClient.resource( gkr ); logger.debug("Object to delete:{}", dummyObject ); List<StatusDetails> result = dummyObject.delete(); @@ -632,7 +622,7 @@ public class KubernetesClientResource { e.printStackTrace(); } - return "DONE"; + return "OK"; } @@ -648,7 +638,7 @@ public class KubernetesClientResource { logger.debug("Patch the following CR:"); logger.debug("{}", crspec); - try (final KubernetesClient k8s = new KubernetesClientBuilder().build()) { + try { GenericKubernetesResource gkr = Serialization.unmarshal( crspec ); headers.forEach(((hname, hval) ->{ @@ -669,7 +659,7 @@ public class KubernetesClientResource { logger.debug("{}", gkr.toString() ); - Resource<GenericKubernetesResource> dummyObject = k8s.resource( gkr ); + Resource<GenericKubernetesResource> dummyObject = kubernetesClient.resource( gkr ); dummyObject.patch(); }catch (Exception e) { e.printStackTrace(); diff --git a/src/test/java/org/etsi/osl/cridge/CridgeIntegrationTest.java b/src/test/java/org/etsi/osl/cridge/CridgeIntegrationTest.java index 1e334e54b085eaf16a2baa416a0a58d6d2e21463..b6f38b5cf037eded27ebf953b2263b043fe1625e 100644 --- a/src/test/java/org/etsi/osl/cridge/CridgeIntegrationTest.java +++ b/src/test/java/org/etsi/osl/cridge/CridgeIntegrationTest.java @@ -11,6 +11,7 @@ import java.io.InputStream; import java.net.HttpURLConnection; import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; @@ -19,6 +20,9 @@ import org.apache.camel.RoutesBuilder; import org.apache.camel.builder.RouteBuilder; import org.apache.camel.model.dataformat.JsonLibrary; import org.apache.commons.io.IOUtils; +import org.etsi.osl.domain.model.kubernetes.KubernetesCRDV1; +import org.etsi.osl.domain.model.kubernetes.KubernetesCRV1; +import org.etsi.osl.domain.model.kubernetes.KubernetesSecret; import org.etsi.osl.tmf.ri639.model.ResourceCreate; import org.junit.Rule; import org.junit.jupiter.api.Assertions; @@ -38,6 +42,7 @@ import org.springframework.test.context.event.RecordApplicationEvents; import org.springframework.test.context.event.annotation.BeforeTestClass; import org.springframework.test.context.junit4.SpringRunner; import io.fabric8.kubernetes.api.model.Condition; +import io.fabric8.kubernetes.api.model.GenericKubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResource; import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.api.model.ListMeta; @@ -45,13 +50,13 @@ import io.fabric8.kubernetes.api.model.ListMetaBuilder; import io.fabric8.kubernetes.api.model.NamedContext; import io.fabric8.kubernetes.api.model.NamedContextBuilder; import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; +import io.fabric8.kubernetes.api.model.Secret; +import io.fabric8.kubernetes.api.model.SecretBuilder; import io.fabric8.kubernetes.api.model.WatchEvent; import io.fabric8.kubernetes.api.model.WatchEventBuilder; import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinition; import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionList; import io.fabric8.kubernetes.api.model.apiextensions.v1.CustomResourceDefinitionListBuilder; -import io.fabric8.kubernetes.api.model.resource.v1alpha2.ResourceHandle; -import io.fabric8.kubernetes.api.model.resource.v1alpha2.ResourceHandleBuilder; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.ConfigBuilder; import io.fabric8.kubernetes.client.KubernetesClient; @@ -61,6 +66,7 @@ import io.fabric8.kubernetes.client.Watcher; import io.fabric8.kubernetes.client.WatcherException; import io.fabric8.kubernetes.client.dsl.MixedOperation; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.base.ResourceDefinitionContext; import io.fabric8.kubernetes.client.extension.ExtensionAdapter.ClientFactory; import io.fabric8.kubernetes.client.http.HttpClient.Factory; import io.fabric8.kubernetes.client.impl.ResourceHandler; @@ -68,7 +74,6 @@ import io.fabric8.kubernetes.client.informers.ResourceEventHandler; import io.fabric8.kubernetes.client.informers.SharedIndexInformer; import io.fabric8.kubernetes.client.informers.SharedInformerFactory; import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; -import io.fabric8.kubernetes.client.server.mock.KubernetesClientBuilderCustomizer; import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; import io.fabric8.kubernetes.client.server.mock.KubernetesServer; import io.fabric8.kubernetes.client.utils.Serialization; @@ -136,12 +141,12 @@ public class CridgeIntegrationTest { NamedContext nctx = new NamedContextBuilder().withNewContext().withCluster("testCluster") .and().withName("tstContext").build(); - KubernetesClientBuilderCustomizer zzz = new KubernetesClientBuilderCustomizer(); + // KubernetesClientBuilderCustomizer zzz = new KubernetesClientBuilderCustomizer(); Config config = Config.autoConfigure(null); config.setNamespace("testNamespace"); KubernetesClientBuilder xxx = new KubernetesClientBuilder().withConfig(config); - zzz.accept(xxx); - kubernetesClient = server.createClient(zzz); + // zzz.accept(xxx); + kubernetesClient = server.createClient(); kubernetesClient.getConfiguration().setCurrentContext(nctx); @@ -175,7 +180,7 @@ public class CridgeIntegrationTest { } } - + @Test public void testCRDRegister() throws Exception { @@ -201,11 +206,11 @@ public class CridgeIntegrationTest { // .customResourceDefinitions() // .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yaml"))) // .item(); - - //prepare CR_SPEC request + + // prepare CR_SPEC request CustomResourceDefinition crdMyCalc = v1CRDFromCustomResourceType(MyCalculator.class).build(); - + Map<String, Object> map = new HashMap<>(); @@ -227,12 +232,12 @@ public class CridgeIntegrationTest { String _CR_SPEC = Serialization.asYaml(getMyCalculator("test-resource")); - //First check for an invalid context cluster + // First check for an invalid context cluster String response = kubernetesClientResource.deployCR(map, _CR_SPEC); assertEquals("SEE OTHER", response); - - //Now try for the correct context cluster + + // Now try for the correct context cluster map.put("currentContextCluster", kubernetesClientResource.getKubernetesContextDefinition().getCurrentContextCluster()); map.put("clusterMasterURL", @@ -258,19 +263,19 @@ public class CridgeIntegrationTest { server.expect().post().withPath("/api/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators") .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); - + server.expect().post() .withPath( "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators") .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); - //register the resource handler + // register the resource handler KubernetesClient client = routesPreparation.kubernetesClient; client.getKubernetesSerialization().registerKubernetesResource("examples.osl.etsi.org/v1alpha1", "MyCalculator", MyCalculator.class); - - //make the deployment test! + + // make the deployment test! response = kubernetesClientResource.deployCR(map, _CR_SPEC); assertEquals("OK", response); @@ -284,7 +289,7 @@ public class CridgeIntegrationTest { // Given KubernetesClient client = routesPreparation.kubernetesClient; - + server.expect().withPath( "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators?allowWatchBookmarks=true&watch=true") .andUpgradeToWebSocket().open().waitFor(10L) @@ -348,4 +353,258 @@ public class CridgeIntegrationTest { } + @Test + public void testKubernetesCRD2OpensliceCRD() throws FileNotFoundException { + + logger.info("===============TEST testCRDRegister ============================="); + // CustomResourceDefinition crdMyCalc = v1CRDFromCustomResourceType(MyCalculator.class).build(); + CustomResourceDefinition cronTabCrd = + routesPreparation.kubernetesClient.apiextensions().v1().customResourceDefinitions() + .load( + new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yaml"))) + .item(); + + List<KubernetesCRDV1> value = kubernetesClientResource.KubernetesCRD2OpensliceCRD(cronTabCrd); + + assertEquals(1, value.size()); + assertEquals("CronTab", value.get(0).getKind()); + assertEquals("v1", value.get(0).getVersion()); + assertEquals("stable.example.com", value.get(0).getApiGroup()); + + + } + + @Test + public void testKubernetesCRDOpensliceCR() throws FileNotFoundException { + + + logger.info("===============TEST testCRRegister ============================="); + + ResourceDefinitionContext resourceDefinitionContext = new ResourceDefinitionContext.Builder() + .withGroup("stable.example.com").withVersion("v1").withPlural("crontabs").build(); + + GenericKubernetesResource cronTabCr = + routesPreparation.kubernetesClient.genericKubernetesResources(resourceDefinitionContext) + .load(new FileInputStream("src/test/resources/crontab-cr.yaml")).item(); + + + KubernetesCRV1 value = kubernetesClientResource.KubernetesCR2OpensliceCR(cronTabCr); + + assertEquals("CronTab", value.getKind()); + + + } + + @Test + public void testKubernetesSecret2OpensliceResource() throws FileNotFoundException { + + + logger.info( + "===============TEST KubernetesSecret2OpensliceResource ============================="); + + + Secret secret1 = new SecretBuilder().withNewMetadata().withName("secret1").endMetadata() + .addToData("username", "guccifer").addToData("password", "shadowgovernment").build(); + + + server.expect().post().withPath("/api/v1/namespaces/default/secrets") + .andReturn(HttpURLConnection.HTTP_OK, secret1).once(); + + Secret secretCreated = routesPreparation.kubernetesClient.secrets().inNamespace("default") + .resource(secret1).create(); + + + KubernetesSecret value = + kubernetesClientResource.KubernetesSecret2OpensliceResource(secretCreated); + + assertEquals("Secret", value.getKind()); + assertEquals("v1", value.getVersion()); + + + } + + + @Test + public void testCRDelete() throws Exception { + logger.info("===============TEST testCRDEPLOY ============================="); + + + // CustomResourceDefinition cronTabCrd = routesPreparation.kubernetesClient.apiextensions().v1() + // .customResourceDefinitions() + // .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yaml"))) + // .item(); + + + // prepare CR_SPEC request + CustomResourceDefinition crdMyCalc = v1CRDFromCustomResourceType(MyCalculator.class).build(); + + + + Map<String, Object> map = new HashMap<>(); + map.put("currentContextCluster", "testCluster"); + map.put("clusterMasterURL", server.getHostName()); + map.put("org.etsi.osl.serviceId", "sid-xxx-xxx-xxx"); + map.put("org.etsi.osl.resourceId", "rid-xxx-xxx-xxx"); + map.put("org.etsi.osl.prefixName", "crrid12345"); + map.put("org.etsi.osl.serviceOrderId", "orderid-xxx-xxx-xxx"); + map.put("org.etsi.osl.namespace", "orderid-xxx-xxx-xxx"); + map.put("org.etsi.osl.statusCheckFieldName", "_CR_CHECK_FIELD"); + map.put("org.etsi.osl.statusCheckValueStandby", "_CR_CHECKVAL_STANDBY"); + map.put("org.etsi.osl.statusCheckValueAlarm", "_CR_CHECKVAL_ALARM"); + map.put("org.etsi.osl.statusCheckValueAvailable", "_CR_CHECKVAL_AVAILABLE"); + map.put("org.etsi.osl.statusCheckValueReserved", "_CR_CHECKVAL_RESERVED"); + map.put("org.etsi.osl.statusCheckValueUnknown", "_CR_CHECKVAL_UNKNOWN"); + map.put("org.etsi.osl.statusCheckValueSuspended", "_CR_CHECKVAL_SUSPENDED"); + + + String _CR_SPEC = Serialization.asYaml(getMyCalculator("test-resource")); + + // First check for an invalid context cluster + String response = kubernetesClientResource.deployCR(map, _CR_SPEC); + assertEquals("SEE OTHER", response); + + + // Now try for the correct context cluster + map.put("currentContextCluster", + kubernetesClientResource.getKubernetesContextDefinition().getCurrentContextCluster()); + map.put("clusterMasterURL", + kubernetesClientResource.getKubernetesContextDefinition().getMasterURL()); + + + // server api expectations + server.expect().get() + .withPath("/api/v1/namespaces/orderid-xxx-xxx-xxx/secrets?resourceVersion=0") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get().withPath( + "/api/v1/namespaces/orderid-xxx-xxx-xxx/secrets?allowWatchBookmarks=true&timeoutSeconds=600&watch=true") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get() + .withPath("/apis/stable.example.com/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get().withPath( + "/apis/stable.example.com/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators/amycalculator") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().post().withPath("/api/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); + + server.expect().post() + .withPath( + "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); + + // register the resource handler + KubernetesClient client = routesPreparation.kubernetesClient; + + client.getKubernetesSerialization().registerKubernetesResource("examples.osl.etsi.org/v1alpha1", + "MyCalculator", MyCalculator.class); + + // make the deployment test! + response = kubernetesClientResource.deleteCR(map, _CR_SPEC); + + assertEquals("OK", response); + + } + + + + @Test + public void testCPatch() throws Exception { + logger.info("===============TEST testCRDEPLOY ============================="); + + + // CustomResourceDefinition cronTabCrd = routesPreparation.kubernetesClient.apiextensions().v1() + // .customResourceDefinitions() + // .load(new BufferedInputStream(new FileInputStream("src/test/resources/crontab-crd.yaml"))) + // .item(); + + + // prepare CR_SPEC request + CustomResourceDefinition crdMyCalc = v1CRDFromCustomResourceType(MyCalculator.class).build(); + + + + Map<String, Object> map = new HashMap<>(); + map.put("currentContextCluster", "testCluster"); + map.put("clusterMasterURL", server.getHostName()); + map.put("org.etsi.osl.serviceId", "sid-xxx-xxx-xxx"); + map.put("org.etsi.osl.resourceId", "rid-xxx-xxx-xxx"); + map.put("org.etsi.osl.prefixName", "crrid12345"); + map.put("org.etsi.osl.serviceOrderId", "orderid-xxx-xxx-xxx"); + map.put("org.etsi.osl.namespace", "orderid-xxx-xxx-xxx"); + map.put("org.etsi.osl.statusCheckFieldName", "_CR_CHECK_FIELD"); + map.put("org.etsi.osl.statusCheckValueStandby", "_CR_CHECKVAL_STANDBY"); + map.put("org.etsi.osl.statusCheckValueAlarm", "_CR_CHECKVAL_ALARM"); + map.put("org.etsi.osl.statusCheckValueAvailable", "_CR_CHECKVAL_AVAILABLE"); + map.put("org.etsi.osl.statusCheckValueReserved", "_CR_CHECKVAL_RESERVED"); + map.put("org.etsi.osl.statusCheckValueUnknown", "_CR_CHECKVAL_UNKNOWN"); + map.put("org.etsi.osl.statusCheckValueSuspended", "_CR_CHECKVAL_SUSPENDED"); + + + String _CR_SPEC = Serialization.asYaml(getMyCalculator("test-resource")); + + // First check for an invalid context cluster + String response = kubernetesClientResource.deployCR(map, _CR_SPEC); + assertEquals("SEE OTHER", response); + + + // Now try for the correct context cluster + map.put("currentContextCluster", + kubernetesClientResource.getKubernetesContextDefinition().getCurrentContextCluster()); + map.put("clusterMasterURL", + kubernetesClientResource.getKubernetesContextDefinition().getMasterURL()); + + + // server api expectations + server.expect().get() + .withPath("/api/v1/namespaces/orderid-xxx-xxx-xxx/secrets?resourceVersion=0") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get().withPath( + "/api/v1/namespaces/orderid-xxx-xxx-xxx/secrets?allowWatchBookmarks=true&timeoutSeconds=600&watch=true") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get() + .withPath("/apis/stable.example.com/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().get().withPath( + "/apis/stable.example.com/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators/amycalculator") + .andReturn(HttpURLConnection.HTTP_OK, crdMyCalc).once(); + + server.expect().post().withPath("/api/v1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); + + server.expect().post() + .withPath( + "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators") + .andReturn(HttpURLConnection.HTTP_CREATED, crdMyCalc).once(); + + // register the resource handler + KubernetesClient client = routesPreparation.kubernetesClient; + + client.getKubernetesSerialization().registerKubernetesResource("examples.osl.etsi.org/v1alpha1", + "MyCalculator", MyCalculator.class); + + server.expect().get() + .withPath( + "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators/crrid12345") + .andReturn(HttpURLConnection.HTTP_OK, null).once(); + server.expect().patch() + .withPath( + "/apis/examples.osl.etsi.org/v1alpha1/namespaces/orderid-xxx-xxx-xxx/mycalculators/crrid12345") + .andReturn(HttpURLConnection.HTTP_OK, null).once(); + + + // make the deployment test! + response = kubernetesClientResource.patchCR(map, _CR_SPEC); + + assertEquals("OK", response); + + } + + } diff --git a/src/test/resources/asecret.yaml b/src/test/resources/asecret.yaml new file mode 100644 index 0000000000000000000000000000000000000000..5c7900ad974799bb39329de9cfa39008a79ab4aa --- /dev/null +++ b/src/test/resources/asecret.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Secret +metadata: + name: dotfile-secret +data: + .secret-file: dmFsdWUtMg0KDQo= +--- +apiVersion: v1 +kind: Pod +metadata: + name: secret-dotfiles-pod +spec: + volumes: + - name: secret-volume + secret: + secretName: dotfile-secret + containers: + - name: dotfile-test-container + image: registry.k8s.io/busybox + command: + - ls + - "-l" + - "/etc/secret-volume" + volumeMounts: + - name: secret-volume + readOnly: true + mountPath: "/etc/secret-volume" \ No newline at end of file