Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
Copyright 2020 The Kubernetes Authors.
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.kubernetes.client.examples;

import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1ConfigMap;
import io.kubernetes.client.openapi.models.V1Pod;
import io.kubernetes.client.util.Config;
import io.kubernetes.client.util.Yaml;
import java.io.File;
import java.io.IOException;

/**
* A simple example of how to use Yaml.createResource() to create Kubernetes resources from YAML
* without specifying the type upfront. This is equivalent to `kubectl create -f <yaml-file>`.
*
* <p>Easiest way to run this: mvn exec:java
* -Dexec.mainClass="io.kubernetes.client.examples.YamlCreateResourceExample"
*
* <p>From inside $REPO_DIR/examples
*/
public class YamlCreateResourceExample {
public static void main(String[] args) throws IOException, ApiException {
// Initialize the API client
ApiClient client = Config.defaultClient();
Configuration.setDefaultApiClient(client);

// Example 1: Create a ConfigMap from YAML string
// This method automatically determines the resource type (ConfigMap)
// and uses the appropriate API to create it
String configMapYaml =
"apiVersion: v1\n"
+ "kind: ConfigMap\n"
+ "metadata:\n"
+ " name: example-config\n"
+ " namespace: default\n"
+ "data:\n"
+ " database.url: jdbc:postgresql://localhost/mydb\n"
+ " database.user: admin\n";

System.out.println("Creating ConfigMap from YAML string...");
Object configMapResult = Yaml.createResource(client, configMapYaml);
System.out.println("Created: " + configMapResult);

// Example 2: Create a Pod from YAML string
// Again, no need to specify V1Pod.class - the method determines it automatically
String podYaml =
"apiVersion: v1\n"
+ "kind: Pod\n"
+ "metadata:\n"
+ " name: example-pod\n"
+ " namespace: default\n"
+ "spec:\n"
+ " containers:\n"
+ " - name: nginx\n"
+ " image: nginx:1.14.2\n"
+ " ports:\n"
+ " - containerPort: 80\n";

System.out.println("\nCreating Pod from YAML string...");
Object podResult = Yaml.createResource(client, podYaml);
System.out.println("Created: " + podResult);

// Example 3: Create a resource from a YAML file
// This works with any Kubernetes resource type
File yamlFile = new File("example-resource.yaml");
if (yamlFile.exists()) {
System.out.println("\nCreating resource from YAML file...");
Object fileResult = Yaml.createResource(client, yamlFile);
System.out.println("Created: " + fileResult);
}

// Example 4: Type casting if you need to access specific fields
// The returned object is the strongly-typed Kubernetes object
V1ConfigMap configMap = (V1ConfigMap) configMapResult;
System.out.println("\nConfigMap name: " + configMap.getMetadata().getName());
System.out.println("ConfigMap data: " + configMap.getData());

V1Pod pod = (V1Pod) podResult;
System.out.println("\nPod name: " + pod.getMetadata().getName());
System.out.println("Pod phase: " + pod.getStatus().getPhase());

// Clean up - delete the created resources
CoreV1Api api = new CoreV1Api();
System.out.println("\nCleaning up...");
api.deleteNamespacedConfigMap("example-config", "default").execute();
System.out.println("Deleted ConfigMap");

api.deleteNamespacedPod("example-pod", "default").execute();
System.out.println("Deleted Pod");
}
}
165 changes: 165 additions & 0 deletions util/src/main/java/io/kubernetes/client/util/Yaml.java
Original file line number Diff line number Diff line change
Expand Up @@ -566,4 +566,169 @@ private static Object modelMapper(Map<String, Object> data) throws IOException {
public static void addModelMap(String apiGroupVersion, String kind, Class<?> clazz) {
ModelMapper.addModelMap(apiGroupVersion, kind, clazz);
}

/**
* Create a Kubernetes resource from a YAML string. This method automatically determines the
* resource type from the YAML content (apiVersion and kind) and uses the appropriate API to
* create the resource.
*
* <p>This is equivalent to `kubectl create -f <yaml-content>`.
*
* <p>Example usage:
* <pre>{@code
* ApiClient client = Config.defaultClient();
* String yaml = "apiVersion: v1\n" +
* "kind: ConfigMap\n" +
* "metadata:\n" +
* " name: my-config\n" +
* " namespace: default\n";
* Object created = Yaml.createResource(client, yaml);
* }</pre>
*
* @param client The API client to use for creating the resource
* @param content The YAML content as a string
* @return The created resource object
* @throws IOException If an error occurs while reading or parsing the YAML
* @throws io.kubernetes.client.openapi.ApiException If an error occurs while creating the resource in the cluster
*/
public static Object createResource(io.kubernetes.client.openapi.ApiClient client, String content)
throws IOException, io.kubernetes.client.openapi.ApiException {
return createResource(client, new StringReader(content));
}

/**
* Create a Kubernetes resource from a YAML file. This method automatically determines the
* resource type from the YAML content (apiVersion and kind) and uses the appropriate API to
* create the resource.
*
* <p>This is equivalent to `kubectl create -f <yaml-file>`.
*
* @param client The API client to use for creating the resource
* @param f The YAML file to load
* @return The created resource object
* @throws IOException If an error occurs while reading or parsing the YAML
* @throws io.kubernetes.client.openapi.ApiException If an error occurs while creating the resource in the cluster
*/
public static Object createResource(io.kubernetes.client.openapi.ApiClient client, File f)
throws IOException, io.kubernetes.client.openapi.ApiException {
return createResource(client, new FileReader(f));
}

/**
* Create a Kubernetes resource from a YAML stream. This method automatically determines the
* resource type from the YAML content (apiVersion and kind) and uses the appropriate API to
* create the resource.
*
* <p>This is equivalent to `kubectl create -f <yaml-stream>`.
*
* @param client The API client to use for creating the resource
* @param reader The stream to load
* @return The created resource object
* @throws IOException If an error occurs while reading or parsing the YAML
* @throws io.kubernetes.client.openapi.ApiException If an error occurs while creating the resource in the cluster
*/
public static Object createResource(io.kubernetes.client.openapi.ApiClient client, Reader reader)
throws IOException, io.kubernetes.client.openapi.ApiException {
// Read the entire content into a string first so we can parse it twice
StringBuilder sb = new StringBuilder();
char[] buffer = new char[8192];
int read;
while ((read = reader.read(buffer)) != -1) {
sb.append(buffer, 0, read);
}
String yamlContent = sb.toString();

// Load the YAML as a map to extract apiVersion and kind
// Note: The getSnakeYaml() method already configures LoaderOptions with appropriate
// security settings to prevent YAML bombs and other attacks
Map<String, Object> data = getSnakeYaml(null).load(new StringReader(yamlContent));

String kind = (String) data.get("kind");
if (kind == null) {
throw new IOException("Missing kind in YAML!");
}
String apiVersion = (String) data.get("apiVersion");
if (apiVersion == null) {
throw new IOException("Missing apiVersion in YAML!");
}

// Use ModelMapper to get the appropriate class for this resource type
Class<?> clazz = ModelMapper.getApiTypeClass(apiVersion, kind);
if (clazz == null) {
throw new IOException(
"Unknown apiVersion/kind: " + apiVersion + "/" + kind + ". Is it registered?");
}

// Load the YAML into the strongly typed object using the same content
Object resource = loadAs(new StringReader(yamlContent), clazz);

// Ensure the resource is a KubernetesObject
if (!(resource instanceof io.kubernetes.client.common.KubernetesObject)) {
throw new IOException(
"Resource is not a KubernetesObject: " + resource.getClass().getName());
}

io.kubernetes.client.common.KubernetesObject k8sObject =
(io.kubernetes.client.common.KubernetesObject) resource;

// Parse apiVersion to extract group and version
io.kubernetes.client.apimachinery.GroupVersionKind gvk =
ModelMapper.groupVersionKindFromApiVersionAndKind(apiVersion, kind);

// Get the resource metadata to determine the plural name
io.kubernetes.client.apimachinery.GroupVersionResource gvr =
ModelMapper.getGroupVersionResourceByClass(clazz);

if (gvr == null) {
// If no GVR mapping exists, we need to perform discovery
io.kubernetes.client.Discovery discovery = new io.kubernetes.client.Discovery(client);
ModelMapper.refresh(discovery);
gvr = ModelMapper.getGroupVersionResourceByClass(clazz);

if (gvr == null) {
throw new IOException(
"Unable to determine resource plural name for " + apiVersion + "/" + kind);
}
}

// Create a GenericKubernetesApi for this resource type
io.kubernetes.client.util.generic.GenericKubernetesApi<
io.kubernetes.client.common.KubernetesObject,
io.kubernetes.client.common.KubernetesListObject>
api =
new io.kubernetes.client.util.generic.GenericKubernetesApi<>(
(Class<io.kubernetes.client.common.KubernetesObject>) clazz,
io.kubernetes.client.common.KubernetesListObject.class,
gvk.getGroup(),
gvk.getVersion(),
gvr.getResource(),
client);

// Create the resource
io.kubernetes.client.util.generic.KubernetesApiResponse<
io.kubernetes.client.common.KubernetesObject>
response;

Boolean isNamespaced = ModelMapper.isNamespaced(clazz);
if (isNamespaced != null && isNamespaced) {
// For namespaced resources
String namespace = k8sObject.getMetadata().getNamespace();
if (namespace == null || namespace.isEmpty()) {
// Default to "default" namespace, matching kubectl behavior
namespace = "default";
}
response = api.create(namespace, k8sObject, new io.kubernetes.client.util.generic.options.CreateOptions());
} else {
// For cluster-scoped resources
response = api.create(k8sObject, new io.kubernetes.client.util.generic.options.CreateOptions());
}

if (!response.isSuccess()) {
throw new io.kubernetes.client.openapi.ApiException(
response.getHttpStatusCode(),
"Failed to create resource: " + response.getStatus());
}

return response.getObject();
}
}
Loading
Loading