diff --git a/CHANGELOG.md b/CHANGELOG.md index 6df2a34947b..d150be80db7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ * Fix #4579: the implicit registration of resource and list types that happens when using the resource(class) methods has been removed. This makes the behavior of the client more predictable as that was an undocumented side-effect. If you expect to see instances of a custom type from an untyped api call - typically KubernetesClient.load, KubernetesClient.resourceList, KubernetesClient.resource(InputStream|String), then you must either create a META-INF/services/io.fabric8.kubernetes.api.model.KubernetesResource file (see above #3923), or make calls to KubernetesDeserializer.registerCustomKind - however since KubernetesDeserializer is an internal class that mechanism is not preferred. * Fix #4597: remove the deprecated support for `javax.validation.constraints.NotNull` in the `crd-generator`, to mark a property as `required` it needs to be annotated with `io.fabric8.generator.annotation.Required` * Fix #3973: removed support for Parameterizable - that was only needed as a workaround for non-string parameters. You should instead include those parameter values in the map passed to processLocally. +* Fix #3973: openShiftClient.templates().load and openShiftClient.load will no longer automatically process / create templates. Use the method openshiftClient.templates().from to get a template from any stream. ### 6.2.0 (2022-10-20) diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLock.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLock.java index 0395ea26d69..576b262b339 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLock.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLock.java @@ -15,13 +15,11 @@ */ package io.fabric8.kubernetes.client.extended.leaderelection.resourcelock; -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; -import com.fasterxml.jackson.databind.ObjectMapper; import io.fabric8.kubernetes.api.model.ConfigMap; import io.fabric8.kubernetes.api.model.ConfigMapBuilder; import io.fabric8.kubernetes.api.model.ObjectMeta; import io.fabric8.kubernetes.client.KubernetesClient; +import io.fabric8.kubernetes.client.KubernetesClientException; import io.fabric8.kubernetes.client.utils.Serialization; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,13 +34,11 @@ public class ConfigMapLock implements Lock { private final String configMapNamespace; private final String configMapName; private final String identity; - private final ObjectMapper objectMapper; public ConfigMapLock(String configMapNamespace, String configMapName, String identity) { this.configMapNamespace = Objects.requireNonNull(configMapNamespace, "configMapNamespace is required"); this.configMapName = Objects.requireNonNull(configMapName, "configMapName is required"); this.identity = Objects.requireNonNull(identity, "identity is required"); - objectMapper = Serialization.jsonMapper(); } /** @@ -58,9 +54,8 @@ public LeaderElectionRecord get(KubernetesClient client) { .map(annotations -> annotations.get(LEADER_ELECTION_RECORD_ANNOTATION_KEY)) .map(annotation -> { try { - return objectMapper.readValue(annotation, new TypeReference() { - }); - } catch (JsonProcessingException ex) { + return Serialization.unmarshal(annotation, LeaderElectionRecord.class); + } catch (KubernetesClientException ex) { LOGGER.error("Error deserializing LeaderElectionRecord from ConfigMap", ex); return null; } @@ -80,11 +75,11 @@ public void create( KubernetesClient client, LeaderElectionRecord leaderElectionRecord) throws LockException { try { - client.configMaps().inNamespace(configMapNamespace).withName(configMapName).create(new ConfigMapBuilder() + client.configMaps().inNamespace(configMapNamespace).resource(new ConfigMapBuilder() .editOrNewMetadata().withNamespace(configMapNamespace).withName(configMapName) - .addToAnnotations(LEADER_ELECTION_RECORD_ANNOTATION_KEY, objectMapper.writeValueAsString(leaderElectionRecord)) + .addToAnnotations(LEADER_ELECTION_RECORD_ANNOTATION_KEY, Serialization.asJson(leaderElectionRecord)) .endMetadata() - .build()); + .build()).create(); } catch (Exception e) { throw new LockException("Unable to create ConfigMapLock", e); } @@ -100,11 +95,11 @@ public void update( try { final ConfigMap toReplace = client.configMaps().inNamespace(configMapNamespace).withName(configMapName).get(); toReplace.getMetadata().getAnnotations() - .put(LEADER_ELECTION_RECORD_ANNOTATION_KEY, objectMapper.writeValueAsString(leaderElectionRecord)); + .put(LEADER_ELECTION_RECORD_ANNOTATION_KEY, Serialization.asJson(leaderElectionRecord)); // Use replace instead of edit to avoid concurrent modifications, resourceVersion is locked to original record version - client.configMaps().inNamespace(configMapNamespace).withName(configMapName) + client.configMaps().inNamespace(configMapNamespace).resource(toReplace) .lockResourceVersion((String) Objects.requireNonNull(leaderElectionRecord.getVersion())) - .replace(toReplace); + .replace(); } catch (Exception e) { throw new LockException("Unable to update ConfigMapLock", e); } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleMixedOperation.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleMixedOperation.java new file mode 100644 index 00000000000..cb2fae30645 --- /dev/null +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleMixedOperation.java @@ -0,0 +1,349 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package io.fabric8.kubernetes.client.extension; + +import io.fabric8.kubernetes.api.model.DeletionPropagation; +import io.fabric8.kubernetes.api.model.LabelSelector; +import io.fabric8.kubernetes.api.model.ListOptions; +import io.fabric8.kubernetes.api.model.ObjectReference; +import io.fabric8.kubernetes.api.model.StatusDetails; +import io.fabric8.kubernetes.client.Client; +import io.fabric8.kubernetes.client.GracePeriodConfigurable; +import io.fabric8.kubernetes.client.PropagationPolicyConfigurable; +import io.fabric8.kubernetes.client.Watch; +import io.fabric8.kubernetes.client.Watcher; +import io.fabric8.kubernetes.client.dsl.AnyNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Deletable; +import io.fabric8.kubernetes.client.dsl.DeletableWithOptions; +import io.fabric8.kubernetes.client.dsl.FilterNested; +import io.fabric8.kubernetes.client.dsl.FilterWatchListDeletable; +import io.fabric8.kubernetes.client.dsl.Informable; +import io.fabric8.kubernetes.client.dsl.ItemWritableOperation; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.Watchable; +import io.fabric8.kubernetes.client.informers.ResourceEventHandler; +import io.fabric8.kubernetes.client.informers.SharedIndexInformer; + +import java.io.File; +import java.io.InputStream; +import java.net.URL; +import java.util.List; +import java.util.Map; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.TimeUnit; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Stream; + +public class ExtensibleMixedOperation> implements MixedOperation { + + protected final MixedOperation operation; + protected final Client client; + + public ExtensibleMixedOperation(Client client, MixedOperation operation) { + this.client = client; + this.operation = operation; + } + + @Override + public R withName(String name) { + return operation.withName(name); + } + + @Override + public NonNamespaceOperation inNamespace(String name) { + return operation.inNamespace(name); + } + + @Override + public T replaceStatus(T item) { + return operation.replaceStatus(item); + } + + @Override + public AnyNamespaceOperation inAnyNamespace() { + return operation.inAnyNamespace(); + } + + @Override + public Watchable withResourceVersion(String resourceVersion) { + return operation.withResourceVersion(resourceVersion); + } + + @Override + public L list() { + return operation.list(); + } + + @Override + public L list(Integer limitVal, String continueVal) { + return operation.list(limitVal, continueVal); + } + + @Override + public List delete() { + return operation.delete(); + } + + @Override + public T waitUntilReady(long amount, TimeUnit timeUnit) { + return operation.waitUntilReady(amount, timeUnit); + } + + @Override + public PropagationPolicyConfigurable withGracePeriod(long gracePeriodSeconds) { + return operation.withGracePeriod(gracePeriodSeconds); + } + + @Override + public T waitUntilCondition(Predicate condition, long amount, TimeUnit timeUnit) { + return operation.waitUntilCondition(condition, amount, timeUnit); + } + + @Override + public T createOrReplace(T item) { + return operation.createOrReplace(item); + } + + @Override + public Watch watch(Watcher watcher) { + return operation.watch(watcher); + } + + @Override + public GracePeriodConfigurable withPropagationPolicy(DeletionPropagation propagationPolicy) { + return operation.withPropagationPolicy(propagationPolicy); + } + + @Override + public FilterNested> withNewFilter() { + return operation.withNewFilter(); + } + + @Override + public T replace(T item) { + return operation.replace(item); + } + + @Override + public FilterWatchListDeletable withLabels(Map labels) { + return operation.withLabels(labels); + } + + @Override + public ItemWritableOperation dryRun() { + return operation.dryRun(); + } + + @Override + public FilterWatchListDeletable withoutLabels(Map labels) { + return operation.withoutLabels(labels); + } + + @Override + public DeletableWithOptions withTimeout(long timeout, TimeUnit unit) { + return operation.withTimeout(timeout, unit); + } + + @Override + public Watch watch(ListOptions options, Watcher watcher) { + return operation.watch(options, watcher); + } + + @Override + public L list(ListOptions listOptions) { + return operation.list(listOptions); + } + + @Override + public Informable withIndexers(Map>> indexers) { + return operation.withIndexers(indexers); + } + + @Override + public Stream resources() { + return operation.resources(); + } + + @Override + public DeletableWithOptions withTimeoutInMillis(long timeoutInMillis) { + return operation.withTimeoutInMillis(timeoutInMillis); + } + + @Override + public T create(T item) { + return operation.create(item); + } + + @Override + public FilterWatchListDeletable withLabelIn(String key, String... values) { + return operation.withLabelIn(key, values); + } + + @Override + public List delete(T item) { + return operation.delete(item); + } + + @Override + public FilterWatchListDeletable withLabelNotIn(String key, String... values) { + return operation.withLabelNotIn(key, values); + } + + @Override + public FilterWatchListDeletable withLabel(String key, String value) { + return operation.withLabel(key, value); + } + + @Override + public Informable withLimit(Long limit) { + return operation.withLimit(limit); + } + + @Override + public ItemWritableOperation dryRun(boolean isDryRun) { + return operation.dryRun(isDryRun); + } + + @Override + public FilterWatchListDeletable withLabel(String key) { + return operation.withLabel(key); + } + + @Override + public T updateStatus(T item) { + return operation.updateStatus(item); + } + + @Override + public FilterWatchListDeletable withoutLabel(String key, String value) { + return operation.withoutLabel(key, value); + } + + @Override + public Watch watch(String resourceVersion, Watcher watcher) { + return operation.watch(resourceVersion, watcher); + } + + @Override + public FilterWatchListDeletable withoutLabel(String key) { + return operation.withoutLabel(key); + } + + @Override + public FilterWatchListDeletable withFields(Map fields) { + return operation.withFields(fields); + } + + @Override + public FilterWatchListDeletable withField(String key, String value) { + return operation.withField(key, value); + } + + @Override + public FilterWatchListDeletable withoutFields(Map fields) { + return operation.withoutFields(fields); + } + + @Override + public T patchStatus(T item) { + return operation.patchStatus(item); + } + + @Override + public boolean delete(T... items) { + return operation.delete(items); + } + + @Override + public SharedIndexInformer inform() { + return operation.inform(); + } + + @Override + public FilterWatchListDeletable withoutField(String key, String value) { + return operation.withoutField(key, value); + } + + @Override + public FilterWatchListDeletable withLabelSelector(LabelSelector selector) { + return operation.withLabelSelector(selector); + } + + @Override + public boolean delete(List items) { + return operation.delete(items); + } + + @Override + public FilterWatchListDeletable withLabelSelector(String selectorAsString) { + return operation.withLabelSelector(selectorAsString); + } + + @Override + public FilterWatchListDeletable withInvolvedObject(ObjectReference objectReference) { + return operation.withInvolvedObject(objectReference); + } + + @Override + public R load(InputStream is) { + return operation.load(is); + } + + @Override + public R load(URL url) { + return operation.load(url); + } + + @Override + public SharedIndexInformer inform(ResourceEventHandler handler) { + return operation.inform(handler); + } + + @Override + public R load(File file) { + return operation.load(file); + } + + @Override + public R load(String path) { + return operation.load(path); + } + + @Override + public R resource(T item) { + return operation.resource(item); + } + + @Override + public SharedIndexInformer inform(ResourceEventHandler handler, long resync) { + return operation.inform(handler, resync); + } + + @Override + public SharedIndexInformer runnableInformer(long resync) { + return operation.runnableInformer(resync); + } + + @Override + public CompletableFuture> informOnCondition(Predicate> condition) { + return operation.informOnCondition(condition); + } + +} diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java index 443a6f17d09..249fc812ca5 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResource.java @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.client.Client; +import io.fabric8.kubernetes.client.OperationInfo; import io.fabric8.kubernetes.client.dsl.Nameable; import io.fabric8.kubernetes.client.dsl.Resource; import io.fabric8.kubernetes.client.dsl.WritableOperation; @@ -94,4 +95,14 @@ default WritableOperation withTimeoutInMillis(long timeoutInMillis) { return withTimeout(timeoutInMillis, TimeUnit.MILLISECONDS); } + OperationInfo forOperationType(String type); + + enum Scope { + NAMESPACE, + TYPE, + RESOURCE + } + + X operation(Scope scope, String operation, String method, Object payload, Class responseType); + } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResourceAdapter.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResourceAdapter.java index 26d5a1a9f78..225fbc3e174 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResourceAdapter.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/extension/ExtensibleResourceAdapter.java @@ -18,6 +18,7 @@ import io.fabric8.kubernetes.api.model.DeletionPropagation; import io.fabric8.kubernetes.client.Client; +import io.fabric8.kubernetes.client.OperationInfo; import java.util.List; import java.util.Map; @@ -127,4 +128,14 @@ public ExtensibleResource withTimeoutInMillis(long timeoutInMillis) { return withTimeout(timeoutInMillis, TimeUnit.MILLISECONDS); } + @Override + public OperationInfo forOperationType(String type) { + return this.resource.forOperationType(type); + } + + @Override + public X operation(Scope scope, String operation, String method, Object payload, Class responseType) { + return this.resource.operation(scope, operation, method, payload, responseType); + } + } diff --git a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/IOHelpers.java b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/IOHelpers.java index a700165c9d7..e51978245ad 100644 --- a/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/IOHelpers.java +++ b/kubernetes-client-api/src/main/java/io/fabric8/kubernetes/client/utils/IOHelpers.java @@ -75,7 +75,11 @@ public static boolean isJSONValid(String json) { } public static String convertYamlToJson(String yaml) throws IOException { - return Serialization.asJson(Serialization.unmarshal(yaml)); + ObjectMapper yamlReader = Serialization.yamlMapper(); + Object obj = yamlReader.readValue(yaml, Object.class); + + ObjectMapper jsonWriter = Serialization.jsonMapper(); + return jsonWriter.writeValueAsString(obj); } public static String convertToJson(String jsonOrYaml) throws IOException { diff --git a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLockTest.java b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLockTest.java index a6f2bb8bc47..31848cbcde6 100644 --- a/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLockTest.java +++ b/kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/extended/leaderelection/resourcelock/ConfigMapLockTest.java @@ -21,13 +21,11 @@ import io.fabric8.kubernetes.api.model.ObjectMetaBuilder; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.dsl.MixedOperation; -import io.fabric8.kubernetes.client.dsl.ReplaceDeletable; import io.fabric8.kubernetes.client.dsl.Resource; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; -import org.mockito.Answers; import org.mockito.ArgumentMatchers; import org.mockito.Mockito; @@ -42,7 +40,6 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.RETURNS_DEEP_STUBS; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; @@ -128,15 +125,13 @@ void createWithValidLeaderElectionRecordShouldSendPostRequest() throws Exception // When lock.create(kc, record); // Then - verify(configMaps.withName("name"), times(1)).create(any(ConfigMap.class)); + verify(configMaps.resource(any(ConfigMap.class)), times(1)).create(); } @Test void updateWithValidLeaderElectionRecordShouldSendPutRequest() throws Exception { // Given final Resource configMapResource = configMaps.withName("name"); - final ReplaceDeletable replaceable = mock(ReplaceDeletable.class, Answers.RETURNS_DEEP_STUBS); - when(configMapResource.lockResourceVersion(any())).thenReturn(replaceable); final ConfigMap configMapInTheCluster = new ConfigMap(); configMapInTheCluster.setMetadata(new ObjectMetaBuilder().withAnnotations(new HashMap<>()).build()); when(configMapResource.get()).thenReturn(configMapInTheCluster); @@ -144,10 +139,11 @@ void updateWithValidLeaderElectionRecordShouldSendPutRequest() throws Exception "1337", Duration.ofSeconds(1), ZonedDateTime.now(), ZonedDateTime.now(), 0); record.setVersion("313373"); final ConfigMapLock lock = new ConfigMapLock("namespace", "name", "1337"); + // When lock.update(kc, record); // Then - verify(replaceable, times(1)).replace(eq(configMapInTheCluster)); + verify(configMaps.resource(any()).lockResourceVersion("313373")).replace(); } @Test diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java index 27788157121..b4e99c23f58 100755 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/BaseOperation.java @@ -715,27 +715,37 @@ protected T handlePatch(PatchContext context, T current, T updated, boolean stat } protected Scale handleScale(Scale scaleParam) { - try { - return handleScale(getCompleteResourceUrl().toString(), scaleParam); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw KubernetesClientException.launderThrowable(forOperationType("scale"), ie); - } catch (IOException e) { - throw KubernetesClientException.launderThrowable(forOperationType("scale"), e); - } - + return operation(Scope.RESOURCE, "scale", "PUT", scaleParam, Scale.class); } protected Status handleDeploymentRollback(DeploymentRollback deploymentRollback) { + return operation(Scope.RESOURCE, "rollback", "POST", deploymentRollback, Status.class); + } + + @Override + public X operation(Scope scope, String operation, String method, Object payload, Class responseType) { try { - return handleDeploymentRollback(getCompleteResourceUrl().toString(), deploymentRollback); - } catch (InterruptedException ie) { - Thread.currentThread().interrupt(); - throw KubernetesClientException.launderThrowable(forOperationType("rollback"), ie); + URL baseUrl = null; + switch (scope) { + case NAMESPACE: + baseUrl = getNamespacedUrl(namespace, null); + break; + case TYPE: + baseUrl = getNamespacedUrl(); + break; + case RESOURCE: + baseUrl = getCompleteResourceUrl(); + break; + } + HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder() + .uri(baseUrl + "/" + operation); + if (payload != null) { + requestBuilder.method(method, JSON, JSON_MAPPER.writeValueAsString(payload)); + } + return handleResponse(requestBuilder, responseType); } catch (IOException e) { - throw KubernetesClientException.launderThrowable(forOperationType("rollback"), e); + throw KubernetesClientException.launderThrowable(forOperationType(operation), e); } - } protected T handleGet(URL resourceUrl) throws InterruptedException, IOException { diff --git a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java index 71964f3acf4..dcc6a0fcef4 100644 --- a/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java +++ b/kubernetes-client/src/main/java/io/fabric8/kubernetes/client/dsl/internal/OperationSupport.java @@ -25,8 +25,6 @@ import io.fabric8.kubernetes.api.model.Preconditions; import io.fabric8.kubernetes.api.model.Status; import io.fabric8.kubernetes.api.model.StatusBuilder; -import io.fabric8.kubernetes.api.model.autoscaling.v1.Scale; -import io.fabric8.kubernetes.api.model.extensions.DeploymentRollback; import io.fabric8.kubernetes.client.Client; import io.fabric8.kubernetes.client.Config; import io.fabric8.kubernetes.client.KubernetesClientException; @@ -172,7 +170,9 @@ protected void addNamespacedUrlPathParts(List parts, String namespace, S parts.add("namespaces"); parts.add(namespace); } - parts.add(type); + if (type != null) { + parts.add(type); + } } public URL getNamespacedUrl() throws MalformedURLException { @@ -433,39 +433,6 @@ protected T handlePatch(PatchContext patchContext, T current, String patchFo return handleResponse(requestBuilder, type); } - /** - * Replace Scale of specified Kubernetes Resource - * - * @param resourceUrl Kubernetes resource URL - * @param scale Scale object which we want to inject - * @return updated Scale object - * @throws InterruptedException in case thread is interrupted - * @throws IOException in some other I/O problem - */ - protected Scale handleScale(String resourceUrl, Scale scale) throws InterruptedException, IOException { - HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().uri(resourceUrl + "/scale"); - if (scale != null) { - requestBuilder.put(JSON, JSON_MAPPER.writeValueAsString(scale)); - } - return handleResponse(requestBuilder, Scale.class); - } - - /** - * Create rollback of a Deployment - * - * @param resourceUrl resource url - * @param deploymentRollback DeploymentRollback resource - * @return Status - * @throws InterruptedException in case thread is interrupted - * @throws IOException in some other I/O problem - */ - protected Status handleDeploymentRollback(String resourceUrl, DeploymentRollback deploymentRollback) - throws InterruptedException, IOException { - HttpRequest.Builder requestBuilder = httpClient.newHttpRequestBuilder().uri(resourceUrl + "/rollback").post(JSON, - JSON_MAPPER.writeValueAsString(deploymentRollback)); - return handleResponse(requestBuilder, Status.class); - } - /** * Send an http get. * @@ -474,7 +441,6 @@ protected Status handleDeploymentRollback(String resourceUrl, DeploymentRollback * @param template argument provided * * @return returns a deserialized object as api server response of provided type. - * @throws InterruptedException Interrupted Exception * @throws IOException IOException */ protected T handleGet(URL resourceUrl, Class type) throws IOException { diff --git a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java index a3b2e7c4afc..63df1237701 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/kubernetes/client/mock/LeaderElectionTest.java @@ -64,6 +64,7 @@ public void singleLeaderConfigMapLockUpdateTest() throws Exception { server.expect().get().withPath("/api/v1/namespaces/namespace/configmaps/name") .andReturn(200, new ConfigMapBuilder() .withNewMetadata() + .withName("name") .withResourceVersion("1") .withAnnotations(Collections.singletonMap( "control-plane.alpha.kubernetes.io/leader", diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java index a0006cdac01..c4c788c806c 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/LoadAsTemplateTest.java @@ -55,7 +55,7 @@ void tearDown() { @Test void shouldLoadPodAsTemplate() { - KubernetesList list = client.templates().load(getClass().getResourceAsStream("/test-pod-create-from-load.yml")) + KubernetesList list = client.templates().from(getClass().getResourceAsStream("/test-pod-create-from-load.yml")) .processLocally(); assertNotNull(list); assertNotNull(list.getItems()); diff --git a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java index 2bc3582bc22..fb45bf33370 100644 --- a/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java +++ b/kubernetes-tests/src/test/java/io/fabric8/openshift/client/server/mock/OpenShiftLoadTest.java @@ -16,31 +16,35 @@ package io.fabric8.openshift.client.server.mock; import io.fabric8.kubernetes.api.model.HasMetadata; +import io.fabric8.kubernetes.client.server.mock.EnableKubernetesMockClient; +import io.fabric8.kubernetes.client.server.mock.KubernetesMockServer; import io.fabric8.openshift.client.OpenShiftClient; import org.junit.jupiter.api.Test; +import java.util.Collections; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; -@EnableOpenShiftMockClient +@EnableKubernetesMockClient class OpenShiftLoadTest { - OpenShiftMockServer server; + KubernetesMockServer server; OpenShiftClient client; @Test void testResourceGetFromLoadWhenSingleDocumentsWithStartingDelimiter() { // when - List result = client.load(getClass().getResourceAsStream("/test-template.yml")).get(); + List result = client.templates().from(getClass().getResourceAsStream("/test-template.yml")) + .processLocally(Collections.emptyMap()).getItems(); // then assertNotNull(result); assertEquals(5, result.size()); HasMetadata deploymentResource = result.get(2); - assertEquals("image.openshift.io/v1", deploymentResource.getApiVersion()); + assertEquals("v1", deploymentResource.getApiVersion()); assertEquals("ImageStream", deploymentResource.getKind()); assertEquals("eap-app", deploymentResource.getMetadata().getName()); } @@ -49,7 +53,8 @@ void testResourceGetFromLoadWhenSingleDocumentsWithStartingDelimiter() { void testResourceGetFromLoadWhenSingleDocumentsWithoutDelimiter() { // when - List result = client.load(getClass().getResourceAsStream("/template-with-params.yml")).get(); + List result = client.templates().from(getClass().getResourceAsStream("/template-with-params.yml")).get() + .getObjects(); // then assertNotNull(result); diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java index 5cf4a82185a..8972922f22b 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/NamespacedOpenShiftClientAdapter.java @@ -18,7 +18,6 @@ import io.fabric8.kubernetes.api.model.ComponentStatus; import io.fabric8.kubernetes.api.model.ComponentStatusList; -import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.NamespacedKubernetesClientAdapter; import io.fabric8.kubernetes.client.RequestConfig; import io.fabric8.kubernetes.client.VersionInfo; @@ -99,10 +98,8 @@ import io.fabric8.openshift.api.model.SubjectAccessReview; import io.fabric8.openshift.api.model.SubjectAccessReviewResponse; import io.fabric8.openshift.api.model.SubjectRulesReview; -import io.fabric8.openshift.api.model.Template; import io.fabric8.openshift.api.model.TemplateInstance; import io.fabric8.openshift.api.model.TemplateInstanceList; -import io.fabric8.openshift.api.model.TemplateList; import io.fabric8.openshift.api.model.User; import io.fabric8.openshift.api.model.UserIdentityMapping; import io.fabric8.openshift.api.model.UserList; @@ -140,7 +137,7 @@ import io.fabric8.openshift.client.dsl.OpenShiftWhereaboutsAPIGroupDSL; import io.fabric8.openshift.client.dsl.ProjectOperation; import io.fabric8.openshift.client.dsl.ProjectRequestOperation; -import io.fabric8.openshift.client.dsl.TemplateResource; +import io.fabric8.openshift.client.dsl.TemplateOperation; import java.net.URL; @@ -347,7 +344,7 @@ public MixedOperation> routes() { } @Override - public MixedOperation> templates() { + public TemplateOperation templates() { return getClient().templates(); } diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java index d8ff1c277f1..13b8e1484ed 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/OpenShiftClient.java @@ -16,13 +16,102 @@ package io.fabric8.openshift.client; -import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.RequestConfig; import io.fabric8.kubernetes.client.VersionInfo; -import io.fabric8.kubernetes.client.dsl.*; +import io.fabric8.kubernetes.client.dsl.AppsAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.AutoscalingAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.BatchAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.ExtensionsAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.FunctionCallable; +import io.fabric8.kubernetes.client.dsl.Gettable; +import io.fabric8.kubernetes.client.dsl.InOutCreateable; +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.kubernetes.client.dsl.Nameable; +import io.fabric8.kubernetes.client.dsl.Namespaceable; +import io.fabric8.kubernetes.client.dsl.NamespacedInOutCreateable; +import io.fabric8.kubernetes.client.dsl.NetworkAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.NonNamespaceOperation; +import io.fabric8.kubernetes.client.dsl.RbacAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.kubernetes.client.dsl.SchedulingAPIGroupDSL; +import io.fabric8.kubernetes.client.dsl.StorageAPIGroupDSL; import io.fabric8.kubernetes.client.extension.SupportTestingClient; -import io.fabric8.openshift.api.model.*; +import io.fabric8.openshift.api.model.BrokerTemplateInstance; +import io.fabric8.openshift.api.model.BrokerTemplateInstanceList; +import io.fabric8.openshift.api.model.Build; +import io.fabric8.openshift.api.model.BuildConfig; +import io.fabric8.openshift.api.model.BuildConfigList; +import io.fabric8.openshift.api.model.BuildList; +import io.fabric8.openshift.api.model.ClusterNetwork; +import io.fabric8.openshift.api.model.ClusterNetworkList; +import io.fabric8.openshift.api.model.ClusterRole; +import io.fabric8.openshift.api.model.ClusterRoleBinding; +import io.fabric8.openshift.api.model.ClusterRoleBindingList; +import io.fabric8.openshift.api.model.ClusterRoleList; +import io.fabric8.openshift.api.model.DeploymentConfig; +import io.fabric8.openshift.api.model.DeploymentConfigList; +import io.fabric8.openshift.api.model.EgressNetworkPolicy; +import io.fabric8.openshift.api.model.EgressNetworkPolicyList; +import io.fabric8.openshift.api.model.Group; +import io.fabric8.openshift.api.model.GroupList; +import io.fabric8.openshift.api.model.HelmChartRepository; +import io.fabric8.openshift.api.model.HelmChartRepositoryList; +import io.fabric8.openshift.api.model.HostSubnet; +import io.fabric8.openshift.api.model.HostSubnetList; +import io.fabric8.openshift.api.model.Identity; +import io.fabric8.openshift.api.model.IdentityList; +import io.fabric8.openshift.api.model.Image; +import io.fabric8.openshift.api.model.ImageList; +import io.fabric8.openshift.api.model.ImageStream; +import io.fabric8.openshift.api.model.ImageStreamImage; +import io.fabric8.openshift.api.model.ImageStreamImport; +import io.fabric8.openshift.api.model.ImageStreamList; +import io.fabric8.openshift.api.model.ImageStreamMapping; +import io.fabric8.openshift.api.model.ImageStreamTag; +import io.fabric8.openshift.api.model.ImageStreamTagList; +import io.fabric8.openshift.api.model.ImageTag; +import io.fabric8.openshift.api.model.ImageTagList; +import io.fabric8.openshift.api.model.LocalResourceAccessReview; +import io.fabric8.openshift.api.model.LocalSubjectAccessReview; +import io.fabric8.openshift.api.model.NetNamespace; +import io.fabric8.openshift.api.model.NetNamespaceList; +import io.fabric8.openshift.api.model.OAuthAccessToken; +import io.fabric8.openshift.api.model.OAuthAccessTokenList; +import io.fabric8.openshift.api.model.OAuthAuthorizeToken; +import io.fabric8.openshift.api.model.OAuthAuthorizeTokenList; +import io.fabric8.openshift.api.model.OAuthClient; +import io.fabric8.openshift.api.model.OAuthClientAuthorization; +import io.fabric8.openshift.api.model.OAuthClientAuthorizationList; +import io.fabric8.openshift.api.model.OAuthClientList; +import io.fabric8.openshift.api.model.PodSecurityPolicyReview; +import io.fabric8.openshift.api.model.PodSecurityPolicySelfSubjectReview; +import io.fabric8.openshift.api.model.PodSecurityPolicySubjectReview; +import io.fabric8.openshift.api.model.RangeAllocation; +import io.fabric8.openshift.api.model.RangeAllocationList; +import io.fabric8.openshift.api.model.ResourceAccessReview; +import io.fabric8.openshift.api.model.ResourceAccessReviewResponse; +import io.fabric8.openshift.api.model.Role; +import io.fabric8.openshift.api.model.RoleBinding; +import io.fabric8.openshift.api.model.RoleBindingList; +import io.fabric8.openshift.api.model.RoleBindingRestriction; +import io.fabric8.openshift.api.model.RoleBindingRestrictionList; +import io.fabric8.openshift.api.model.RoleList; +import io.fabric8.openshift.api.model.Route; +import io.fabric8.openshift.api.model.RouteList; +import io.fabric8.openshift.api.model.SecurityContextConstraints; +import io.fabric8.openshift.api.model.SecurityContextConstraintsList; +import io.fabric8.openshift.api.model.SelfSubjectRulesReview; +import io.fabric8.openshift.api.model.SubjectAccessReview; +import io.fabric8.openshift.api.model.SubjectAccessReviewResponse; +import io.fabric8.openshift.api.model.SubjectRulesReview; +import io.fabric8.openshift.api.model.TemplateInstance; +import io.fabric8.openshift.api.model.TemplateInstanceList; +import io.fabric8.openshift.api.model.User; +import io.fabric8.openshift.api.model.UserIdentityMapping; +import io.fabric8.openshift.api.model.UserList; +import io.fabric8.openshift.api.model.UserOAuthAccessToken; +import io.fabric8.openshift.api.model.UserOAuthAccessTokenList; import io.fabric8.openshift.api.model.miscellaneous.apiserver.v1.APIRequestCount; import io.fabric8.openshift.api.model.miscellaneous.apiserver.v1.APIRequestCountList; import io.fabric8.openshift.api.model.miscellaneous.cloudcredential.v1.CredentialsRequest; @@ -35,7 +124,26 @@ import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.EgressRouterList; import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.OperatorPKI; import io.fabric8.openshift.api.model.miscellaneous.network.operator.v1.OperatorPKIList; -import io.fabric8.openshift.client.dsl.*; +import io.fabric8.openshift.client.dsl.BuildConfigResource; +import io.fabric8.openshift.client.dsl.BuildResource; +import io.fabric8.openshift.client.dsl.DeployableScalableResource; +import io.fabric8.openshift.client.dsl.MachineConfigurationAPIGroupDSL; +import io.fabric8.openshift.client.dsl.NameableCreateOrDeleteable; +import io.fabric8.openshift.client.dsl.OpenShiftClusterAutoscalingAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftConfigAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftConsoleAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftHiveAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftMachineAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftMonitoringAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftOperatorAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftOperatorHubAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftQuotaAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftStorageVersionMigratorApiGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftTunedAPIGroupDSL; +import io.fabric8.openshift.client.dsl.OpenShiftWhereaboutsAPIGroupDSL; +import io.fabric8.openshift.client.dsl.ProjectOperation; +import io.fabric8.openshift.client.dsl.ProjectRequestOperation; +import io.fabric8.openshift.client.dsl.TemplateOperation; import java.net.URL; @@ -446,9 +554,9 @@ public interface OpenShiftClient extends KubernetesClient, SupportTestingClient /** * API entrypoint for accessing Template(template.openshift.io/v1) * - * @return {@link ParameterMixedOperation} object for Template operations + * @return {@link TemplateOperation} object for Template operations */ - MixedOperation> templates(); + TemplateOperation templates(); /** * API entrypoint for TemplateInstance(template.openshift.io/v1) diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateOperation.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateOperation.java new file mode 100644 index 00000000000..9764c33f61a --- /dev/null +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateOperation.java @@ -0,0 +1,35 @@ +/** + * Copyright (C) 2015 Red Hat, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package io.fabric8.openshift.client.dsl; + +import io.fabric8.kubernetes.client.dsl.MixedOperation; +import io.fabric8.openshift.api.model.Template; +import io.fabric8.openshift.api.model.TemplateList; + +import java.io.InputStream; + +public interface TemplateOperation extends MixedOperation { + + /** + * Create a template from the given stream. If it is already a template, that will be returned unchanged. + * Any other HasMetadata will be returned as items in a Template with a randomly generated name. + * + * @param is + * @return the Template + */ + TemplateResource from(InputStream is); + +} diff --git a/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java index 7620a103cc4..2595562b8df 100644 --- a/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java +++ b/openshift-client-api/src/main/java/io/fabric8/openshift/client/dsl/TemplateResource.java @@ -15,85 +15,87 @@ */ package io.fabric8.openshift.client.dsl; +import io.fabric8.kubernetes.api.model.KubernetesList; import io.fabric8.kubernetes.client.dsl.Resource; +import io.fabric8.openshift.api.model.Template; import io.fabric8.openshift.client.ParameterValue; import java.io.File; import java.io.InputStream; import java.util.Map; -public interface TemplateResource extends Resource { +public interface TemplateResource extends Resource