Can not create kubernetes secret using go client - go

I am trying to create a secret using this function
func (ks *KubeSession) DeploySecret(secretName string, secretType string, secretMap map[string][]byte) error {
InfoLogger.Printf("deploying secret %s", secretName)
secret := corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: secretName,
},
Data: secretMap,
Type: secretType,
}
_, err := ks.ClientSet.CoreV1().Secrets(JOB_NAMESPACE).Create(context.TODO(), &secret, metav1.CreateOptions{})
if err != nil {
return err
}
return nil
}
It is getting the following error:
cannot use secretType (variable of type string) as "k8s.io/api/core/v1".SecretType value in struct literal
Though, it works fine when I use a hardcoded string instead, like that:
...
Type: "generic"
...
How can I substitute this variable, so that I do not have to use hardcoded values instead?

Resolved.
Found the right way to declare the composite type:
Type: corev1.SecretType(secretType)

Related

K8s client nullptr dereference

Following the k8s/controller-runtime/client example code (see here), which goes a bit like this
var c client.Client
func main() {
// Using a typed object.
pod := &corev1.Pod{
ObjectMeta: metav1.ObjectMeta{
Namespace: "namespace",
Name: "name",
},
Spec: corev1.PodSpec{
Containers: []corev1.Container{
{
Image: "nginx",
Name: "nginx",
},
},
},
}
// c is a created client.
_ = c.Create(context.Background(), pod) // nil deref here
}
I get a nullptr dereference on _ = c.Create(context.Background(), pod). To me this makes sense, since I declared c, but never initialised it. However the example code also does that. What is going on here?
The correct way to initialise the client can be found here: https://pkg.go.dev/sigs.k8s.io/controller-runtime#v0.14.4/pkg/client#example-New
cl, err := client.New(config.GetConfigOrDie(), client.Options{})
if err != nil {
fmt.Println("failed to create client")
os.Exit(1)
}

k6 - create custom resource using go client

Anyone know how to create a Custom Resource using go-client. basically equivalent of kubectl apply -f 'yaml path'
apiVersion: k6.io/v1alpha1
kind: K6
metadata:
name: k6-sample
spec:
parallelism: 1
#arguments: --out statsd
#cleanup: post
script:
configMap:
name: "staging-stress-test"
file: "staging.js"
Have a go-client code to generate a Custom Resource below
func createk6CR(clientset *kubernetes.Clientset) (string, error) {
k6plugin := &v1alpha1.K6{
TypeMeta: metav1.TypeMeta{
APIVersion: "k6.io/v1alpha1",
Kind: "K6",
},
ObjectMeta: metav1.ObjectMeta{
Name: "k6-sample-1",
Namespace: "default",
},
Spec: v1alpha1.K6Spec{
Parallelism: 3,
Script: v1alpha1.K6Script{
ConfigMap: v1alpha1.K6Configmap{
Name: "staging-stress-test",
File: "staging.js",
},
},
},
// Status: v1alpha1.K6Status{
// Stage: "started",
// },
}
body, err := json.Marshal(k6plugin)
if err != nil {
fmt.Printf("error getting Kubernetes config: %v\n", err)
os.Exit(1)
}
data, err := clientset.RESTClient().
Post().
AbsPath("/apis/k6.io/v1alpha1/namespaces/default/k6").
Body(body).
DoRaw(context.TODO())
if data != nil {
str := string(data[:])
fmt.Printf("return data: %v\n", str)
//os.Exit(1)
}
return "success", err
}
But I get Page 404 not found on AbsPath("/apis/k6.io/v1alpha1/namespaces/default/k6").
Found what was wrong with it, when you do kubectl apply pass it with -v 8 to see the Abspath check for POST
kubectl apply -f 'resource path'
I0816 09:20:56.239402 15535 round_trippers.go:463] POST https://0.0.0.0:43117/apis/k6.io/v1alpha1/namespaces/default/k6s?fieldManager=kubectl-client-side-apply&fieldValidation=Strict
I0816 09:20:56.239428 15535 round_trippers.go:469] Request Headers:
so the code with corrected AbsPath should be below,
data, err := clientset.RESTClient().
Post().
AbsPath("/apis/k6.io/v1alpha1/namespaces/default/k6s").
Body(body).
DoRaw(context.TODO())

Create/Get a custom kubernetes resource

I want to create a custom kubernetes resource with go. The application is deployed in the kubernetes cluster. I want to create e.g. the followng resource:
apiVersion: configuration.konghq.com/v1
kind: KongPlugin
metadata:
name: add-response-header
config:
add:
headers:
- "demo: injected-by-kong"
plugin: response-transformer
So far I always created the 'standard' resources e.g. a secret with the following code:
CreateSecret(name string, data map[string]string) error {
confs, err := rest.InClusterConfig()
if err != nil {
panic(err)
}
clientset, err = kubernetes.NewForConfig(confs)
i := clientset.CoreV1()
if _, err := i.Secrets(namespace).Create(&v1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: name,
},
StringData: data,
Type: "Opaque",
}); err != nil {
return err
}
}
In addition I tried to get a resource with the following code:
b, err := clientset.RESTClient().Get().Namespace(namespace).Resource("KongPlugin").DoRaw()
I get the following err:
the server could not find the requested resource (get KongPlugin)
If I make a request at the command line k get KongPlugin I can see all the resources.
NAME PLUGIN-TYPE AGE
add-proxy-headers request-transformer 3h34m
So how can view the custom resoources?
For RESTClient 👇🏼
Get:
You have to fully specify path to you custom resource.
Use fluent interface
data, err := clientset.RESTClient().
Get().
AbsPath("/apis/<api>/<version>").
Namespace("<namespace>").
Resource("kongplugins").
Name("kongplugin-sample").
DoRaw(context.TODO())
or specify manually
data, err := clientset.RESTClient().
Get().
AbsPath("/apis/<api>/<version>/namespaces/<namespace>/kongplugins/kongplugin-sample").
DoRaw(context.TODO())
You can find AbsPath in selfLink of custom resource.
Create:
For example, you can post marshaled data use AbsPath
kongPlugin := &KongPlugin{
TypeMeta: metav1.TypeMeta{
APIVersion: "<api>/<version>",
Kind: "KongPlugin",
},
ObjectMeta: metav1.ObjectMeta{
Name: "kongplugin-sample",
Namespace: "<namespace>",
},
...}}
body, err := json.Marshal(kongPlugin)
data, err := clientset.RESTClient().
Post().
AbsPath("/apis/<api>/<version>/namespaces/<namespace>/kongplugins").
Body(body).
DoRaw(context.TODO())
because arg of the method Body(obj interface{}) is an empty interface, you can use different types of arguments according to documentation:
k8s.io/client-go/rest - func (*Request) Body

Generic client.Get for custom Kubernetes GO operator

In a custom Kubernetes operator implemented with the operator-sdk in golang is it possible to call the custom API directly and retrieve the object as YAML?
For example. I have a custom resource
apiVersion: test.com/v1alpha1
kind: TEST
metadata::
name: example-test
spec:
replicas: 3
randomname: value
I don't know ahead of time what the fields in the spec are going to be apart from replicas. So I am not able to create a go type that includes structs to hold the entries.
So rather than doing:
instance := &testv1alpha1.Test{}
err := r.client.Get(context.TODO(), nameSpaceName, instance)
I want to be able to do something like:
instanceYAML := genericContainer{}
err := r.client.GetGeneric(context.TODO(), nameSpaceName, instance)
and then parse the instanceYAML to check the entries.
This is called the "unstructured" client. The docs are pretty light so I recommend looking over the tests as examples https://github.com/kubernetes-sigs/controller-runtime/blob/ea32729106c995d9df310ac4731c2061490addfb/pkg/client/client_test.go#L1536-L1566
Using the unstructured type client all the operation done on the CoreAPI resource can be done on the CustomResourceDefinition(CRD)
package util
import (
"context"
"encoding/json"
"strconv"
"github.com/go-logr/logr"
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
"k8s.io/apimachinery/pkg/runtime/schema"
types "k8s.io/apimachinery/pkg/types"
_ "k8s.io/client-go/plugin/pkg/client/auth"
"sigs.k8s.io/controller-runtime/pkg/client"
)
var reqLogger logr.Logger
func CRUDonCRD(c client.Client) {
u := createUnstructuredObject(c)
GetCR(u, c)
PatchCR(u, c, 1)
DeleteCR(u, c)
}
func createUnstructuredObject(c client.Client) *unstructured.Unstructured {
u := &unstructured.Unstructured{}
u.SetGroupVersionKind(schema.GroupVersionKind{
// Group: "<crd group name>",
// Kind: "<crd kind>",
// Version: "<crd version>",
Group: "com.cumulus.netq.operator.transport",
Kind: "TransportOperator",
Version: "v1",
})
_ = c.Get(context.Background(), client.ObjectKey{
// Namespace: "<namespace>",
// Name: "cr name",
Namespace: "default",
Name: "transport-operator",
}, u)
return u
}
type patchStringValue struct {
Op string `json:"op"`
Path string `json:"path"`
Value string `json:"value"`
}
func PatchCR(u *unstructured.Unstructured, c client.Client, replicaCount int) error {
payload := []patchStringValue{{
Op: "replace",
Path: "/spec/replicas/replicasOpta",
Value: strconv.Itoa(replicaCount),
}}
payloadBytes, _ := json.Marshal(payload)
err := c.Patch(context.Background(), u, client.RawPatch(types.JSONPatchType, payloadBytes))
if err != nil {
reqLogger.Error(err, "error occured while patching")
}
reqLogger.Info("Patching is successful", "Patched Transport Operator Object", u)
return err
}
func GetCR(u *unstructured.Unstructured, c client.Client) {
// key := client.ObjectKey{Namespace: "default", Name: "<cr-name>"}
key := client.ObjectKey{Namespace: "default", Name: "transport-operator"}
err := c.Get(context.Background(), key, u)
if err != nil {
reqLogger.Error(err, "error occured while getting the resource")
}
reqLogger.Info("Got the resource", "Resource Object", u)
}
func DeleteCR(u *unstructured.Unstructured, c client.Client) {
err := c.Delete(context.Background(), u)
if err != nil {
reqLogger.Error(err, "error occured while deleting the resource")
}
reqLogger.Info("Resource deleted", "Resource ", u)
}
Here is what I did in the Operator SDK to get a object from kubernetes.
Ref: https://github.com/kubernetes-sigs/controller-runtime/blob/master/pkg/client/example_test.go#L57
func (r *ConfigDeploymentReconciler) findObjectsForConfigMap(configMap client.Object) []reconcile.Request {
pod := &corev1.Pod{}
_ = r.Client.Get(context.Background(), client.ObjectKey{
Namespace: "prometheus",
Name: "prometheus-node-exporter-7vxqs",
}, pod)
fmt.Println("Got this pod", pod.String())
return nil
}

Add startup-script while creating instance in gcp using golang

I am trying to create an instance with a startup-script in gcp using google.golang.org/api/compute/v1. However I am having some problems setting up the metadata to pass the startup-script.
Link to a similar example.
Link to do library documentation.
The function I created is the following one:
func CreateInstance(service *compute.Service, projectId string, instanceName string, zone string) {
imageURL := "https://www.googleapis.com/compute/v1/projects/debian-cloud/global/images/debian-7-wheezy-v20140606"
prefix := "https://www.googleapis.com/compute/v1/projects/" + projectId
file, err := os.Open("startup-script.sh")
if err != nil {
log.Fatal(err)
}
instance := &compute.Instance{
Name: instanceName,
Description: "compute sample instance",
MachineType: prefix + "/zones/" + zone + "/machineTypes/n1-standard-1",
Disks: []*compute.AttachedDisk{
{
AutoDelete: true,
Boot: true,
Type: "PERSISTENT",
InitializeParams: &compute.AttachedDiskInitializeParams{
DiskName: "my-root-pd",
SourceImage: imageURL,
},
},
},
ServiceAccounts: []*compute.ServiceAccount{
{
Email: "default",
Scopes: []string{
compute.DevstorageFullControlScope,
compute.ComputeScope,
},
},
},
Metadata: &compute.Metadata{
{
Items: &compute.MetadataItems{
{
Key: "startup-script",
Value : file,
},
},
},
},
}
op, err := service.Instances.Insert(projectId, zone, instance).Do()
log.Printf("Got compute.Operation, err: %#v, %v", op, err)
etag := op.Header.Get("Etag")
log.Printf("Etag=%v", etag)
}
However I am getting the following error:
./createInstance.go:54:4: missing type in composite literal
./createInstance.go:54:4: too few values in &compute.Metadata literal
Can someone point what I am doing wrong?
The problem are the brackets around Metadata. It should be:
Metadata: &compute.Metadata{
Items: &compute.MetadataItems{
{
Key: "startup-script",
Value : file,
},
},
},

Resources