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  }