k8s.io/client-go@v0.22.2/examples/dynamic-create-update-delete-deployment/main.go (about) 1 /* 2 Copyright 2019 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 // Note: the example only works with the code within the same release/branch. 18 package main 19 20 import ( 21 "bufio" 22 "context" 23 "flag" 24 "fmt" 25 "os" 26 "path/filepath" 27 28 apiv1 "k8s.io/api/core/v1" 29 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 30 "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" 31 "k8s.io/apimachinery/pkg/runtime/schema" 32 "k8s.io/client-go/dynamic" 33 "k8s.io/client-go/tools/clientcmd" 34 "k8s.io/client-go/util/homedir" 35 "k8s.io/client-go/util/retry" 36 // 37 // Uncomment to load all auth plugins 38 // _ "k8s.io/client-go/plugin/pkg/client/auth" 39 // 40 // Or uncomment to load specific auth plugins 41 // _ "k8s.io/client-go/plugin/pkg/client/auth/azure" 42 // _ "k8s.io/client-go/plugin/pkg/client/auth/gcp" 43 // _ "k8s.io/client-go/plugin/pkg/client/auth/oidc" 44 // _ "k8s.io/client-go/plugin/pkg/client/auth/openstack" 45 ) 46 47 func main() { 48 var kubeconfig *string 49 if home := homedir.HomeDir(); home != "" { 50 kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file") 51 } else { 52 kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file") 53 } 54 flag.Parse() 55 56 namespace := "default" 57 58 config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig) 59 if err != nil { 60 panic(err) 61 } 62 client, err := dynamic.NewForConfig(config) 63 if err != nil { 64 panic(err) 65 } 66 67 deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"} 68 69 deployment := &unstructured.Unstructured{ 70 Object: map[string]interface{}{ 71 "apiVersion": "apps/v1", 72 "kind": "Deployment", 73 "metadata": map[string]interface{}{ 74 "name": "demo-deployment", 75 }, 76 "spec": map[string]interface{}{ 77 "replicas": 2, 78 "selector": map[string]interface{}{ 79 "matchLabels": map[string]interface{}{ 80 "app": "demo", 81 }, 82 }, 83 "template": map[string]interface{}{ 84 "metadata": map[string]interface{}{ 85 "labels": map[string]interface{}{ 86 "app": "demo", 87 }, 88 }, 89 90 "spec": map[string]interface{}{ 91 "containers": []map[string]interface{}{ 92 { 93 "name": "web", 94 "image": "nginx:1.12", 95 "ports": []map[string]interface{}{ 96 { 97 "name": "http", 98 "protocol": "TCP", 99 "containerPort": 80, 100 }, 101 }, 102 }, 103 }, 104 }, 105 }, 106 }, 107 }, 108 } 109 110 // Create Deployment 111 fmt.Println("Creating deployment...") 112 result, err := client.Resource(deploymentRes).Namespace(namespace).Create(context.TODO(), deployment, metav1.CreateOptions{}) 113 if err != nil { 114 panic(err) 115 } 116 fmt.Printf("Created deployment %q.\n", result.GetName()) 117 118 // Update Deployment 119 prompt() 120 fmt.Println("Updating deployment...") 121 // You have two options to Update() this Deployment: 122 // 123 // 1. Modify the "deployment" variable and call: Update(deployment). 124 // This works like the "kubectl replace" command and it overwrites/loses changes 125 // made by other clients between you Create() and Update() the object. 126 // 2. Modify the "result" returned by Get() and retry Update(result) until 127 // you no longer get a conflict error. This way, you can preserve changes made 128 // by other clients between Create() and Update(). This is implemented below 129 // using the retry utility package included with client-go. (RECOMMENDED) 130 // 131 // More Info: 132 // https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency 133 134 retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error { 135 // Retrieve the latest version of Deployment before attempting update 136 // RetryOnConflict uses exponential backoff to avoid exhausting the apiserver 137 result, getErr := client.Resource(deploymentRes).Namespace(namespace).Get(context.TODO(), "demo-deployment", metav1.GetOptions{}) 138 if getErr != nil { 139 panic(fmt.Errorf("failed to get latest version of Deployment: %v", getErr)) 140 } 141 142 // update replicas to 1 143 if err := unstructured.SetNestedField(result.Object, int64(1), "spec", "replicas"); err != nil { 144 panic(fmt.Errorf("failed to set replica value: %v", err)) 145 } 146 147 // extract spec containers 148 containers, found, err := unstructured.NestedSlice(result.Object, "spec", "template", "spec", "containers") 149 if err != nil || !found || containers == nil { 150 panic(fmt.Errorf("deployment containers not found or error in spec: %v", err)) 151 } 152 153 // update container[0] image 154 if err := unstructured.SetNestedField(containers[0].(map[string]interface{}), "nginx:1.13", "image"); err != nil { 155 panic(err) 156 } 157 if err := unstructured.SetNestedField(result.Object, containers, "spec", "template", "spec", "containers"); err != nil { 158 panic(err) 159 } 160 161 _, updateErr := client.Resource(deploymentRes).Namespace(namespace).Update(context.TODO(), result, metav1.UpdateOptions{}) 162 return updateErr 163 }) 164 if retryErr != nil { 165 panic(fmt.Errorf("update failed: %v", retryErr)) 166 } 167 fmt.Println("Updated deployment...") 168 169 // List Deployments 170 prompt() 171 fmt.Printf("Listing deployments in namespace %q:\n", apiv1.NamespaceDefault) 172 list, err := client.Resource(deploymentRes).Namespace(namespace).List(context.TODO(), metav1.ListOptions{}) 173 if err != nil { 174 panic(err) 175 } 176 for _, d := range list.Items { 177 replicas, found, err := unstructured.NestedInt64(d.Object, "spec", "replicas") 178 if err != nil || !found { 179 fmt.Printf("Replicas not found for deployment %s: error=%s", d.GetName(), err) 180 continue 181 } 182 fmt.Printf(" * %s (%d replicas)\n", d.GetName(), replicas) 183 } 184 185 // Delete Deployment 186 prompt() 187 fmt.Println("Deleting deployment...") 188 deletePolicy := metav1.DeletePropagationForeground 189 deleteOptions := metav1.DeleteOptions{ 190 PropagationPolicy: &deletePolicy, 191 } 192 if err := client.Resource(deploymentRes).Namespace(namespace).Delete(context.TODO(), "demo-deployment", deleteOptions); err != nil { 193 panic(err) 194 } 195 196 fmt.Println("Deleted deployment.") 197 } 198 199 func prompt() { 200 fmt.Printf("-> Press Return key to continue.") 201 scanner := bufio.NewScanner(os.Stdin) 202 for scanner.Scan() { 203 break 204 } 205 if err := scanner.Err(); err != nil { 206 panic(err) 207 } 208 fmt.Println() 209 }