github.com/SamarSidharth/kpt@v0.0.0-20231122062228-c7d747ae3ace/site/book/05-developing-functions/02-developing-in-Go.md (about)

     1  You can develop a KRM function in Go using [the kpt function SDK].
     2  
     3  - **General-purpose language:** Compared to Domain Specific Languages (DSL), Go
     4    is a general-purpose programming language that provides:
     5    - Proper abstractions and language features
     6    - An extensive ecosystem of tooling (e.g. IDE support)
     7    - A comprehensive catalog of well-supported libraries
     8    - Robust community support and detailed documentation
     9  
    10  ## Prerequisites
    11  
    12  - [Install kpt](https://kpt.dev/installation/)
    13  
    14  - [Install Docker](https://docs.docker.com/get-docker/)
    15  
    16  - [Golang](https://go.dev/dl/) (at least version 1.19)
    17  
    18  ## Quickstart
    19  
    20  In this quickstart, we will write a function that adds an annotation 
    21  `config.kubernetes.io/managed-by=kpt` to all `Deployment` resources.
    22  
    23  ### Initialize your project
    24  
    25  We start from a "get-started" package which contains a `main.go` file with some scaffolding code.
    26  
    27  ```shell
    28  # Set your KRM function name.
    29  export FUNCTION_NAME=set-annotation
    30  
    31  # Get the "get-started" package.
    32  kpt pkg get https://github.com/GoogleContainerTools/kpt-functions-sdk.git/go/get-started@master ${FUNCTION_NAME}
    33  
    34  cd ${FUNCTION_NAME}
    35  
    36  # Initialize the Go module
    37  go mod init
    38  go mod tidy
    39  ```
    40  
    41  ### Write the KRM function logic
    42   
    43  Take a look at the `main.go` (as below) and complete the `Run` function.
    44  
    45  ```go
    46  // Copyright 2022 The kpt Authors
    47  //
    48  // Licensed under the Apache License, Version 2.0 (the "License");
    49  // you may not use this file except in compliance with the License.
    50  // You may obtain a copy of the License at
    51  //
    52  //      http://www.apache.org/licenses/LICENSE-2.0
    53  //
    54  // Unless required by applicable law or agreed to in writing, software
    55  // distributed under the License is distributed on an "AS IS" BASIS,
    56  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    57  // See the License for the specific language governing permissions and
    58  // limitations under the License.
    59  
    60  package main
    61  
    62  import (
    63  	"context"
    64  	"os"
    65  
    66  	"github.com/GoogleContainerTools/kpt-functions-sdk/go/fn"
    67  )
    68  
    69  var _ fn.Runner = &YourFunction{}
    70  
    71  // TODO: Change to your functionConfig "Kind" name.
    72  type YourFunction struct {
    73  	FnConfigBool bool
    74  	FnConfigInt  int
    75  	FnConfigFoo  string
    76  }
    77  
    78  // Run is the main function logic.
    79  // `items` is parsed from the STDIN "ResourceList.Items".
    80  // `functionConfig` is from the STDIN "ResourceList.FunctionConfig". The value has been assigned to the r attributes
    81  // `results` is the "ResourceList.Results" that you can write result info to.
    82  func (r *YourFunction) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn.KubeObjects, results *fn.Results) bool {
    83  	// TODO: Write your code.
    84  	return true
    85  }
    86  
    87  func main() {
    88  	runner := fn.WithContext(context.Background(), &YourFunction{})
    89  	if err := fn.AsMain(runner); err != nil {
    90  		os.Exit(1)
    91  	}
    92  }
    93  ```
    94  
    95  The [`fn`] library provides a series of KRM level operations for [`ResourceList`]. 
    96  Basically, the KRM resource `ResourceList.FunctionConfig` and KRM resources `ResourceList.Items` are both converted to 
    97  `KubeObject` objects. You can use `KubeObject` similar as [`unstructured.Unstrucutred`].
    98  
    99  The set-annotation function (see below) iterates the `ResourceList.Items`, finds out the `Deployment` resources and
   100  adds the annotation. After the iteration, it adds some user message to the `ResourceList.Results`
   101  
   102  ```go
   103  func (r *YourFunction) Run(ctx *fn.Context, functionConfig *fn.KubeObject, items fn.KubeObjects, results *fn.Results) bool {
   104  	for _, kubeObject := range items {
   105  		if kubeObject.IsGVK("apps", "v1", "Deployment") {
   106  			kubeObject.SetAnnotation("config.kubernetes.io/managed-by", "kpt")
   107  		}
   108  	}
   109  	// This result message will be displayed in the function evaluation time.
   110  	*results = append(*results, fn.GeneralResult("Add config.kubernetes.io/managed-by=kpt to all `Deployment` resources", fn.Info))
   111  	return true
   112  }
   113  ```
   114  
   115  Learn more about the `KubeObject` from the [go doc](https://pkg.go.dev/github.com/GoogleContainerTools/kpt-functions-sdk/go/fn).
   116  
   117  
   118  ### Test the KRM function
   119  
   120  The "get-started" package contains a `./testdata` directory. You can use this to test out your functions. 
   121  
   122  ```shell
   123  # Edit the `testdata/resources.yaml` with your KRM resources. 
   124  # resources.yaml already has a `Deployment` and `Service` as test data. 
   125  vim data/resources.yaml
   126  
   127  # Convert the KRM resources and FunctionConfig resource to `ResourceList`, and 
   128  # then pipe the ResourceList as StdIn to your function
   129  kpt fn source testdata | go run main.go
   130  
   131  # Verify the KRM function behavior in the StdOutput `ResourceList`
   132  ```
   133  
   134  ### Build the KRM function as a Docker image
   135  
   136  Build the image
   137  
   138  The "get-started" package provides the `Dockerfile` that you can download using:
   139  ```shell
   140  wget https://raw.githubusercontent.com/GoogleContainerTools/kpt-functions-sdk/master/go/kfn/commands/embed/Dockerfile
   141  ```
   142  
   143  ```shell
   144  export FN_CONTAINER_REGISTRY=<Your GCR or docker hub>
   145  export TAG=<Your KRM function tag>
   146  docker build . -t ${FN_CONTAINER_REGISTRY}/${FUNCTION_NAME}:${TAG}
   147  ```
   148  
   149  To verify the image using the same `./testdata` resources
   150  ```shell
   151  kpt fn eval ./testdata/test1/resources.yaml --image ${FN_CONTAINER_REGISTRY}/${FUNCTION_NAME}:${TAG}
   152  ```
   153  
   154  ## Next Steps
   155  
   156  - See other [go doc examples] to use KubeObject.
   157  - To contribute to KRM catalog functions, please follow the [contributor guide](https://github.com/GoogleContainerTools/kpt-functions-catalog/blob/master/CONTRIBUTING.md)
   158  
   159  [the kpt function SDK]: https://pkg.go.dev/github.com/GoogleContainerTools/kpt-functions-sdk/go/fn
   160  [go doc examples]: https://pkg.go.dev/github.com/GoogleContainerTools/kpt-functions-sdk/go/fn/examples
   161  [`fn`]: https://pkg.go.dev/github.com/GoogleContainerTools/kpt-functions-sdk/go/fn
   162  [`ResourceList`]: https://github.com/kubernetes-sigs/kustomize/blob/master/cmd/config/docs/api-conventions/functions-spec.md
   163  [`unstructured.Unstructured`]: https://pkg.go.dev/k8s.io/apimachinery/pkg/apis/meta/v1/unstructured