zking2000 / NotePad

1 stars 0 forks source link

java-kubectl #99

Open zking2000 opened 4 weeks ago

zking2000 commented 4 weeks ago
package com.example;

import java.io.FileReader;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;

import io.kubernetes.client.common.KubernetesListObject;
import io.kubernetes.client.common.KubernetesObject;
import io.kubernetes.client.openapi.ApiClient;
import io.kubernetes.client.openapi.ApiException;
import io.kubernetes.client.openapi.Configuration;
import io.kubernetes.client.openapi.apis.AppsV1Api;
import io.kubernetes.client.openapi.apis.AutoscalingV2Api;
import io.kubernetes.client.openapi.apis.CoreV1Api;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.openapi.models.V2HorizontalPodAutoscaler;
import io.kubernetes.client.util.ClientBuilder;
import io.kubernetes.client.util.KubeConfig;
import io.kubernetes.client.util.Yaml;
import io.kubernetes.client.util.generic.GenericKubernetesApi;

public class KubectlJava {
    private final ApiClient client;
    private final CoreV1Api coreV1Api;
    private final AppsV1Api appsV1Api;
    private final AutoscalingV2Api autoscalingV2Api;

    public KubectlJava(String kubeConfigPath) throws IOException {
        client = ClientBuilder
                .kubeconfig(KubeConfig.loadKubeConfig(new FileReader(kubeConfigPath)))
                .build();
        Configuration.setDefaultApiClient(client);

        coreV1Api = new CoreV1Api(client);
        appsV1Api = new AppsV1Api(client);
        autoscalingV2Api = new AutoscalingV2Api(client);
    }

    public void apply(String yamlPath) throws IOException {
        System.out.println("开始读取YAML文件: " + yamlPath);
        String content = new String(Files.readAllBytes(Paths.get(yamlPath)));
        System.out.println("YAML文件内容:");
        System.out.println(content);

        List<Object> objects = Yaml.loadAll(content);
        System.out.println("解析到 " + objects.size() + " 个资源对象");

        int index = 0;
        for (Object obj : objects) {
            index++;
            System.out.println("\n处理第 " + index + " 个资源:");

            try {
                if (obj instanceof V1Deployment) {
                    V1Deployment deployment = (V1Deployment) obj;
                    System.out.println("资源类型: Deployment, 名称: " + deployment.getMetadata().getName());
                    createOrUpdateDeployment(deployment);
                } else if (obj instanceof V1Service) {
                    V1Service service = (V1Service) obj;
                    System.out.println("资源类型: Service, 名称: " + service.getMetadata().getName());
                    createOrUpdateService(service);
                } else if (obj instanceof V2HorizontalPodAutoscaler) {
                    V2HorizontalPodAutoscaler hpa = (V2HorizontalPodAutoscaler) obj;
                    System.out.println("资源类型: HPA, 名称: " + hpa.getMetadata().getName());
                    createOrUpdateHPA(hpa);
                } else {
                    System.err.println("不支持的资源类型: " + obj.getClass().getName());
                }
            } catch (Exception e) {
                System.err.println("处理资源失败: " + e.getMessage());
                e.printStackTrace();
                // 继续处理下一个资源
                continue;
            }
        }
    }

    private void applyResource(Map<String, Object> resource) {
        try {
            String apiVersion = (String) resource.get("apiVersion");
            String kind = (String) resource.get("kind");
            Map<String, Object> metadata = (Map<String, Object>) resource.get("metadata");
            String name = (String) metadata.get("name");
            String namespace = (String) metadata.getOrDefault("namespace", "default");

            System.out.printf("\n正在处理 %s %s 在命名空间 %s\n", kind, name, namespace);

            String[] apiVersionParts = apiVersion.split("/");
            String group = apiVersionParts.length > 1 ? apiVersionParts[0] : "";
            String version = apiVersionParts.length > 1 ? apiVersionParts[1] : apiVersionParts[0];

            // 将Map转换为具体的Kubernetes对象
            String yamlContent = Yaml.dump(resource);

            if (group.isEmpty()) {
                // 核心API组
                if (kind.equalsIgnoreCase("service")) {
                    V1Service service = Yaml.loadAs(yamlContent, V1Service.class);
                    createOrUpdateService(service);
                } else {
                    System.err.println("不支持的核心资源类型: " + kind);
                }
            } else {
                switch (group) {
                    case "apps":
                        if (kind.equalsIgnoreCase("deployment")) {
                            V1Deployment deployment = Yaml.loadAs(yamlContent, V1Deployment.class);
                            createOrUpdateDeployment(deployment);
                        }
                        break;
                    case "autoscaling":
                        if (kind.equalsIgnoreCase("horizontalpodautoscaler")) {
                            V2HorizontalPodAutoscaler hpa = Yaml.loadAs(yamlContent, V2HorizontalPodAutoscaler.class);
                            createOrUpdateHPA(hpa);
                        }
                        break;
                    default:
                        System.err.println("不支持的API组: " + group);
                }
            }
        } catch (Exception e) {
            System.err.printf("处理资源失败: %s\n", e.getMessage());
            e.printStackTrace();
        }
    }

    private void createOrUpdateDeployment(V1Deployment deployment) {
        try {
            String namespace = deployment.getMetadata().getNamespace();
            String name = deployment.getMetadata().getName();
            appsV1Api.readNamespacedDeployment(name, namespace, null);
            appsV1Api.replaceNamespacedDeployment(name, namespace, deployment, null, null, null, null);
            System.out.printf("更新 Deployment: %s\n", name);
        } catch (ApiException e) {
            if (e.getCode() == 404) {
                try {
                    String namespace = deployment.getMetadata().getNamespace();
                    appsV1Api.createNamespacedDeployment(namespace, deployment, null, null, null, null);
                    System.out.printf("创建 Deployment: %s\n", deployment.getMetadata().getName());
                } catch (ApiException ex) {
                    System.err.println("创建Deployment失败: " + ex.getMessage());
                }
            } else {
                System.err.println("更新Deployment失败: " + e.getMessage());
            }
        }
    }

    private void createOrUpdateService(V1Service service) {
        try {
            String namespace = service.getMetadata().getNamespace();
            String name = service.getMetadata().getName();
            coreV1Api.readNamespacedService(name, namespace, null);
            coreV1Api.replaceNamespacedService(name, namespace, service, null, null, null, null);
            System.out.printf("更新 Service: %s\n", name);
        } catch (ApiException e) {
            if (e.getCode() == 404) {
                try {
                    String namespace = service.getMetadata().getNamespace();
                    coreV1Api.createNamespacedService(namespace, service, null, null, null, null);
                    System.out.printf("创建 Service: %s\n", service.getMetadata().getName());
                } catch (ApiException ex) {
                    System.err.println("创建Service失败: " + ex.getMessage());
                }
            } else {
                System.err.println("更新Service失败: " + e.getMessage());
            }
        }
    }

    private void createOrUpdateHPA(V2HorizontalPodAutoscaler hpa) {
        try {
            String namespace = hpa.getMetadata().getNamespace();
            String name = hpa.getMetadata().getName();
            autoscalingV2Api.readNamespacedHorizontalPodAutoscaler(name, namespace, null);
            autoscalingV2Api.replaceNamespacedHorizontalPodAutoscaler(name, namespace, hpa, null, null, null, null);
            System.out.printf("更新 HPA: %s\n", name);
        } catch (ApiException e) {
            if (e.getCode() == 404) {
                try {
                    String namespace = hpa.getMetadata().getNamespace();
                    autoscalingV2Api.createNamespacedHorizontalPodAutoscaler(namespace, hpa, null, null, null, null);
                    System.out.printf("创建 HPA: %s\n", hpa.getMetadata().getName());
                } catch (ApiException ex) {
                    System.err.println("创建HPA失败: " + ex.getMessage());
                }
            } else {
                System.err.println("更新HPA失败: " + e.getMessage());
            }
        }
    }

    public void delete(String yamlPath) throws IOException {
        String content = new String(Files.readAllBytes(Paths.get(yamlPath)));
        List<Object> objects = Yaml.loadAll(content);

        for (Object obj : objects) {
            if (obj instanceof Map) {
                deleteResource((Map<String, Object>) obj);
            }
        }
    }

    private void deleteResource(Map<String, Object> resource) {
        try {
            String apiVersion = (String) resource.get("apiVersion");
            String kind = (String) resource.get("kind");
            Map<String, Object> metadata = (Map<String, Object>) resource.get("metadata");
            String name = (String) metadata.get("name");
            String namespace = (String) metadata.getOrDefault("namespace", "default");

            System.out.printf("正在删除 %s %s 在命名空间 %s\n", kind, name, namespace);

            String[] apiVersionParts = apiVersion.split("/");
            String group = apiVersionParts.length > 1 ? apiVersionParts[0] : "";
            String version = apiVersionParts.length > 1 ? apiVersionParts[1] : apiVersionParts[0];
            String plural = kind.toLowerCase() + "s";

            GenericKubernetesApi<KubernetesObject, KubernetesListObject> api = 
                new GenericKubernetesApi<>(
                    KubernetesObject.class,
                    KubernetesListObject.class,
                    group,
                    version,
                    plural,
                    client
                );

            var response = api.delete(namespace, name);

            if (response.isSuccess()) {
                System.out.printf("成功删除 %s: %s\n", kind, name);
            } else {
                System.out.printf("%s %s 不存在或删除失败\n", kind, name);
            }
        } catch (Exception e) {
            System.err.printf("删除资源失败: %s\n", e.getMessage());
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        if (args.length < 2) {
            System.out.println("用法: java -jar kubectl-java.jar <命令> <YAML文件路径>");
            System.out.println("支持的命令: apply, delete");
            System.exit(1);
        }

        String command = args[0];
        String yamlPath = args[1];
        String kubeConfigPath = System.getProperty("user.home") + "/.kube/config";

        try {
            KubectlJava kubectl = new KubectlJava(kubeConfigPath);

            switch (command) {
                case "apply":
                    kubectl.apply(yamlPath);
                    break;
                case "delete":
                    kubectl.delete(yamlPath);
                    break;
                default:
                    System.out.println("不支持的命令: " + command);
                    System.exit(1);
            }
        } catch (Exception e) {
            System.err.println("执行失败: " + e.getMessage());
            e.printStackTrace();
            System.exit(1);
        }
    }
}
zking2000 commented 4 weeks ago
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example</groupId>
    <artifactId>kubectl-java</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>io.kubernetes</groupId>
            <artifactId>client-java</artifactId>
            <version>18.0.1</version>
        </dependency>
        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.6</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>3.3.0</version>
                <configuration>
                    <archive>
                        <manifest>
                            <mainClass>com.example.KubectlJava</mainClass>
                        </manifest>
                    </archive>
                    <descriptorRefs>
                        <descriptorRef>jar-with-dependencies</descriptorRef>
                    </descriptorRefs>
                </configuration>
                <executions>
                    <execution>
                        <id>make-assembly</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>
zking2000 commented 4 weeks ago
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
        </encoder>
    </appender>

    <root level="INFO">
        <appender-ref ref="CONSOLE" />
    </root>
</configuration>