...

Source file src/k8s.io/client-go/examples/dynamic-create-update-delete-deployment/main.go

Documentation: k8s.io/client-go/examples/dynamic-create-update-delete-deployment

     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  )
    45  
    46  func main() {
    47  	var kubeconfig *string
    48  	if home := homedir.HomeDir(); home != "" {
    49  		kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
    50  	} else {
    51  		kubeconfig = flag.String("kubeconfig", "", "absolute path to the kubeconfig file")
    52  	}
    53  	flag.Parse()
    54  
    55  	config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
    56  	if err != nil {
    57  		panic(err)
    58  	}
    59  	client, err := dynamic.NewForConfig(config)
    60  	if err != nil {
    61  		panic(err)
    62  	}
    63  
    64  	deploymentRes := schema.GroupVersionResource{Group: "apps", Version: "v1", Resource: "deployments"}
    65  
    66  	deployment := &unstructured.Unstructured{
    67  		Object: map[string]interface{}{
    68  			"apiVersion": "apps/v1",
    69  			"kind":       "Deployment",
    70  			"metadata": map[string]interface{}{
    71  				"name": "demo-deployment",
    72  			},
    73  			"spec": map[string]interface{}{
    74  				"replicas": 2,
    75  				"selector": map[string]interface{}{
    76  					"matchLabels": map[string]interface{}{
    77  						"app": "demo",
    78  					},
    79  				},
    80  				"template": map[string]interface{}{
    81  					"metadata": map[string]interface{}{
    82  						"labels": map[string]interface{}{
    83  							"app": "demo",
    84  						},
    85  					},
    86  
    87  					"spec": map[string]interface{}{
    88  						"containers": []map[string]interface{}{
    89  							{
    90  								"name":  "web",
    91  								"image": "nginx:1.12",
    92  								"ports": []map[string]interface{}{
    93  									{
    94  										"name":          "http",
    95  										"protocol":      "TCP",
    96  										"containerPort": 80,
    97  									},
    98  								},
    99  							},
   100  						},
   101  					},
   102  				},
   103  			},
   104  		},
   105  	}
   106  
   107  	// Create Deployment
   108  	fmt.Println("Creating deployment...")
   109  	result, err := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Create(context.TODO(), deployment, metav1.CreateOptions{})
   110  	if err != nil {
   111  		panic(err)
   112  	}
   113  	fmt.Printf("Created deployment %q.\n", result.GetName())
   114  
   115  	// Update Deployment
   116  	prompt()
   117  	fmt.Println("Updating deployment...")
   118  	//    You have two options to Update() this Deployment:
   119  	//
   120  	//    1. Modify the "deployment" variable and call: Update(deployment).
   121  	//       This works like the "kubectl replace" command and it overwrites/loses changes
   122  	//       made by other clients between you Create() and Update() the object.
   123  	//    2. Modify the "result" returned by Get() and retry Update(result) until
   124  	//       you no longer get a conflict error. This way, you can preserve changes made
   125  	//       by other clients between Create() and Update(). This is implemented below
   126  	//			 using the retry utility package included with client-go. (RECOMMENDED)
   127  	//
   128  	// More Info:
   129  	// https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#concurrency-control-and-consistency
   130  
   131  	retryErr := retry.RetryOnConflict(retry.DefaultRetry, func() error {
   132  		// Retrieve the latest version of Deployment before attempting update
   133  		// RetryOnConflict uses exponential backoff to avoid exhausting the apiserver
   134  		result, getErr := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Get(context.TODO(), "demo-deployment", metav1.GetOptions{})
   135  		if getErr != nil {
   136  			panic(fmt.Errorf("failed to get latest version of Deployment: %v", getErr))
   137  		}
   138  
   139  		// update replicas to 1
   140  		if err := unstructured.SetNestedField(result.Object, int64(1), "spec", "replicas"); err != nil {
   141  			panic(fmt.Errorf("failed to set replica value: %v", err))
   142  		}
   143  
   144  		// extract spec containers
   145  		containers, found, err := unstructured.NestedSlice(result.Object, "spec", "template", "spec", "containers")
   146  		if err != nil || !found || containers == nil {
   147  			panic(fmt.Errorf("deployment containers not found or error in spec: %v", err))
   148  		}
   149  
   150  		// update container[0] image
   151  		if err := unstructured.SetNestedField(containers[0].(map[string]interface{}), "nginx:1.13", "image"); err != nil {
   152  			panic(err)
   153  		}
   154  		if err := unstructured.SetNestedField(result.Object, containers, "spec", "template", "spec", "containers"); err != nil {
   155  			panic(err)
   156  		}
   157  
   158  		_, updateErr := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Update(context.TODO(), result, metav1.UpdateOptions{})
   159  		return updateErr
   160  	})
   161  	if retryErr != nil {
   162  		panic(fmt.Errorf("update failed: %v", retryErr))
   163  	}
   164  	fmt.Println("Updated deployment...")
   165  
   166  	// List Deployments
   167  	prompt()
   168  	fmt.Printf("Listing deployments in namespace %q:\n", apiv1.NamespaceDefault)
   169  	list, err := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).List(context.TODO(), metav1.ListOptions{})
   170  	if err != nil {
   171  		panic(err)
   172  	}
   173  	for _, d := range list.Items {
   174  		replicas, found, err := unstructured.NestedInt64(d.Object, "spec", "replicas")
   175  		if err != nil || !found {
   176  			fmt.Printf("Replicas not found for deployment %s: error=%s", d.GetName(), err)
   177  			continue
   178  		}
   179  		fmt.Printf(" * %s (%d replicas)\n", d.GetName(), replicas)
   180  	}
   181  
   182  	// Delete Deployment
   183  	prompt()
   184  	fmt.Println("Deleting deployment...")
   185  	deletePolicy := metav1.DeletePropagationForeground
   186  	deleteOptions := metav1.DeleteOptions{
   187  		PropagationPolicy: &deletePolicy,
   188  	}
   189  	if err := client.Resource(deploymentRes).Namespace(apiv1.NamespaceDefault).Delete(context.TODO(), "demo-deployment", deleteOptions); err != nil {
   190  		panic(err)
   191  	}
   192  
   193  	fmt.Println("Deleted deployment.")
   194  }
   195  
   196  func prompt() {
   197  	fmt.Printf("-> Press Return key to continue.")
   198  	scanner := bufio.NewScanner(os.Stdin)
   199  	for scanner.Scan() {
   200  		break
   201  	}
   202  	if err := scanner.Err(); err != nil {
   203  		panic(err)
   204  	}
   205  	fmt.Println()
   206  }
   207  

View as plain text