Skip to content

Commit

Permalink
Merge pull request #1472 from rohanKanojia/pr/custom-resources-improv…
Browse files Browse the repository at this point in the history
…ements
  • Loading branch information
fusesource-ci authored Apr 8, 2019
2 parents f3c0c1d + 75c7493 commit 25944e5
Show file tree
Hide file tree
Showing 20 changed files with 753 additions and 5 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,10 @@


New Feature
* First Draft of Custom Resource Improvements (#1472)

#### 4.2.0

#### 4.1-SNAPSHOT

Bugs

Expand Down
1 change: 1 addition & 0 deletions kubernetes-client/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>

</dependencies>

</project>
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
import io.fabric8.kubernetes.api.model.ServiceAccountList;
import io.fabric8.kubernetes.api.model.DoneableServiceAccount;
import io.fabric8.kubernetes.client.dsl.*;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.internal.*;
import io.fabric8.kubernetes.client.utils.Serialization;
import okhttp3.OkHttpClient;
Expand Down Expand Up @@ -244,6 +245,11 @@ public <T extends HasMetadata, L extends KubernetesResourceList, D extends Donea
.withDoneableType(doneClass));
}

@Override
public RawCustomResourceOperationsImpl customResource(CustomResourceDefinitionContext customResourceDefinition) {
return new RawCustomResourceOperationsImpl(httpClient, getConfiguration(), customResourceDefinition);
}

@Override
public <T extends HasMetadata, L extends KubernetesResourceList, D extends Doneable<T>> MixedOperation<T, L, D, Resource<T, D>> customResource(CustomResourceDefinition crd, Class<T> resourceType, Class<L> listClass, Class<D> doneClass) {
return customResources(crd, resourceType, listClass, doneClass);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinition;
import io.fabric8.kubernetes.api.model.apiextensions.CustomResourceDefinitionList;
import io.fabric8.kubernetes.api.model.apiextensions.DoneableCustomResourceDefinition;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl;

import java.io.InputStream;
import java.util.Collection;
Expand All @@ -87,6 +89,8 @@ public interface KubernetesClient extends Client {

VersionInfo getVersion();

RawCustomResourceOperationsImpl customResource(CustomResourceDefinitionContext customResourceDefinition);

AppsAPIGroupDSL apps();

AutoscalingAPIGroupDSL autoscaling();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
/**
* 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.dsl.base;

public class CustomResourceDefinitionContext {
private String name;
private String group;
private String scope;
private String plural;
private String version;

public String getName() { return name; }

public String getGroup() {
return group;
}

public String getScope() {
return scope;
}

public String getPlural() {
return plural;
}

public String getVersion() {
return version;
}

public static class Builder {
private CustomResourceDefinitionContext customResourceDefinitionContext;

public Builder() {
this.customResourceDefinitionContext = new CustomResourceDefinitionContext();
}

public Builder withName(String name) {
this.customResourceDefinitionContext.name = name;
return this;
}

public Builder withGroup(String group) {
this.customResourceDefinitionContext.group = group;
return this;
}

public Builder withScope(String scope) {
this.customResourceDefinitionContext.scope = scope;
return this;
}

public Builder withPlural(String plural) {
this.customResourceDefinitionContext.plural = plural;
return this;
}

public Builder withVersion(String version) {
this.customResourceDefinitionContext.version = version;
return this;
}

public CustomResourceDefinitionContext build() {
return this.customResourceDefinitionContext;
}
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,6 @@
import io.fabric8.kubernetes.client.dsl.base.HasMetadataOperation;
import io.fabric8.kubernetes.client.dsl.base.OperationContext;
import okhttp3.OkHttpClient;
import io.fabric8.kubernetes.client.dsl.MixedOperation;

import java.util.Map;
import java.util.TreeMap;

/**
*/
Expand All @@ -46,6 +42,7 @@ public CustomResourceDefinitionOperationsImpl(OperationContext context) {
this.listType = CustomResourceDefinitionList.class;
this.doneableType = DoneableCustomResourceDefinition.class;
}

@Override
public CustomResourceDefinitionOperationsImpl newInstance(OperationContext context) {
return new CustomResourceDefinitionOperationsImpl(context);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
/**
* 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.dsl.internal;

import com.fasterxml.jackson.databind.ObjectMapper;
import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.base.OperationSupport;
import io.fabric8.kubernetes.client.utils.IOHelpers;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class RawCustomResourceOperationsImpl extends OperationSupport {
private OkHttpClient client;
private Config config;
private CustomResourceDefinitionContext customResourceDefinition;

private enum HttpCallMethod { GET, POST, PUT, DELETE };

public RawCustomResourceOperationsImpl(OkHttpClient client, Config config, CustomResourceDefinitionContext customResourceDefinition) {
this.client = client;
this.config = config;
this.customResourceDefinition = customResourceDefinition;
}

public Map<String, Object> create(String objectAsString) throws IOException {
return validateAndSubmitRequest(null, null, objectAsString, HttpCallMethod.POST);
}

public Map<String, Object> create(String namespace, String objectAsString) throws KubernetesClientException, IOException {
return validateAndSubmitRequest(namespace, null, objectAsString, HttpCallMethod.POST);
}

public Map<String, Object> create(InputStream objectAsStream) throws KubernetesClientException, IOException {
return validateAndSubmitRequest(null, null, IOHelpers.readFully(objectAsStream), HttpCallMethod.POST);
}

public Map<String, Object> create(String namespace, InputStream objectAsStream) throws KubernetesClientException, IOException {
return validateAndSubmitRequest(namespace, null, IOHelpers.readFully(objectAsStream), HttpCallMethod.POST);
}

public Map<String, Object> edit(String name, String objectAsString) throws IOException {
return validateAndSubmitRequest(null, name, objectAsString, HttpCallMethod.PUT);
}

public Map<String, Object> edit(String namespace, String name, String objectAsString) throws IOException {
return validateAndSubmitRequest(namespace, name, objectAsString, HttpCallMethod.PUT);
}

public Map<String, Object> edit(String namespace, String name, InputStream objectAsStream) throws IOException, KubernetesClientException {
return validateAndSubmitRequest(namespace, name, IOHelpers.readFully(objectAsStream), HttpCallMethod.PUT);
}

public Map<String, Object> get(String name) {
return makeCall(fetchUrl(null, null) + name, null, HttpCallMethod.GET);
}

public Map<String, Object> get(String namespace, String name) {
return makeCall(fetchUrl(namespace, null) + name, null, HttpCallMethod.GET);
}

public Map<String, Object> list() {
return makeCall(fetchUrl(null, null), null, HttpCallMethod.GET);
}

public Map<String, Object> list(String namespace) {
return makeCall(fetchUrl(namespace, null), null, HttpCallMethod.GET);
}

public Map<String, Object> list(String namespace, Map<String, String> labels) {
return makeCall(fetchUrl(namespace, labels), null, HttpCallMethod.GET);
}

public Map<String, Object> delete(String namespace) {
return makeCall(fetchUrl(namespace, null), null, HttpCallMethod.DELETE);
}

public Map<String, Object> delete(String namespace, String name) {
return makeCall(fetchUrl(namespace, null) + name, null, HttpCallMethod.DELETE);
}

private String fetchUrl(String namespace, Map<String, String> labels) {
StringBuilder urlBuilder = new StringBuilder(config.getMasterUrl());
urlBuilder.append("apis/")
.append(customResourceDefinition.getGroup())
.append("/")
.append(customResourceDefinition.getVersion())
.append("/");

if(customResourceDefinition.getScope().equals("Namespaced") && namespace != null) {
urlBuilder.append("namespaces/").append(namespace).append("/");
}
urlBuilder.append(customResourceDefinition.getPlural()).append("/");
if(labels != null) {
urlBuilder.append("?labelSelector").append("=").append(getLabelsQueryParam(labels));
}
return urlBuilder.toString();
}

private String getLabelsQueryParam(Map<String, String> labels) {
StringBuilder labelQueryBuilder = new StringBuilder();
for(Map.Entry<String, String> entry : labels.entrySet()) {
if(labelQueryBuilder.length() > 0) {
labelQueryBuilder.append(",");
}
labelQueryBuilder.append(entry.getKey()).append("=").append(entry.getValue());
}
return labelQueryBuilder.toString();
}

private Map<String, Object> makeCall(String url, String body, HttpCallMethod callMethod) throws RuntimeException {
try {
Response response;
if(body == null) {
response = client.newCall(getRequest(url, callMethod)).execute();
}
else {
response = client.newCall(getRequest(url, body, callMethod)).execute();
}
if(response.code() != HttpURLConnection.HTTP_NOT_FOUND &&
response.code() != HttpURLConnection.HTTP_SERVER_ERROR &&
response.code() != HttpURLConnection.HTTP_BAD_REQUEST) {
return new ObjectMapper().readValue(response.body().string(), HashMap.class);
} else {
response.close();
throw new IllegalStateException(response.message());
}
} catch(Exception e) {
throw KubernetesClientException.launderThrowable(e);
}
}

private Map<String, Object> validateAndSubmitRequest(String namespace, String name, String objectAsString, HttpCallMethod httpCallMethod) throws IOException {
if (IOHelpers.isJSONValid(objectAsString)) {
return makeCall(fetchUrl(namespace, null) + (name != null ? name : ""), objectAsString, httpCallMethod);
} else {
return makeCall(fetchUrl(namespace, null) + (name != null ? name : ""), IOHelpers.convertYamlToJson(objectAsString), httpCallMethod);
}
}

private Request getRequest(String url, HttpCallMethod httpCallMethod) {
Request.Builder requestBuilder = new Request.Builder();
switch(httpCallMethod) {
case GET:
requestBuilder.get().url(url);
break;
case DELETE:
requestBuilder.delete().url(url);
break;
}

return requestBuilder.build();
}

private Request getRequest(String url, String body, HttpCallMethod httpCallMethod) {
Request.Builder requestBuilder = new Request.Builder();
RequestBody requestBody = RequestBody.create(MediaType.parse("application/json"), body);
switch(httpCallMethod) {
case POST:
return requestBuilder.post(requestBody).url(url).build();
case PUT:
return requestBuilder.put(requestBody).url(url).build();
}
return requestBuilder.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@
import io.fabric8.kubernetes.client.dsl.ServiceResource;
import io.fabric8.kubernetes.client.dsl.SettingsAPIGroupDSL;
import io.fabric8.kubernetes.client.dsl.StorageAPIGroupDSL;
import io.fabric8.kubernetes.client.dsl.base.CustomResourceDefinitionContext;
import io.fabric8.kubernetes.client.dsl.internal.RawCustomResourceOperationsImpl;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.ConfigurationPolicy;
Expand Down Expand Up @@ -383,6 +385,11 @@ public <T extends HasMetadata, L extends KubernetesResourceList, D extends Donea
return customResources(crd, resourceType, listClass, doneClass);
}

@Override
public RawCustomResourceOperationsImpl customResource(CustomResourceDefinitionContext customResourceDefinition) {
return delegate.customResource(customResourceDefinition);
}

@Override
public String getApiVersion() {
return delegate.getApiVersion();
Expand Down
Loading

0 comments on commit 25944e5

Please sign in to comment.