I'm writing a Go program that will run in a kubernetes cluster.
I want the program to apply a kubernetes workload using a yaml (yaml in json format)
import (
"encoding/json"
"fmt"
corev1 "k8s.io/api/core/v1"
)
var (
workload = `{
"apiVersion": "v1",
"kind": "Pod",
"metadata": {
"name": "sleep",
},
"spec": {
"containers": [
{
"name": "sleep2",
"image": "tutum/curl",
"command": [
"/bin/sleep",
"infinity"
],
"imagePullPolicy": "Always",
"env": [
{
"name": "ENV_VAR",
"value": "i/love/sleeping"
}
]
}
]
}
}`
)
func ApplyWorkload(){
pod := corev1.Pod{}
if err := json.Unmarshal(workload, &pod); err != nil {
fmt.Errorf("%v", err)
}
// apply pod here
}
How can I apply the workload in Go?
What can I do if my workload is a deployment, should I run a switch-case for each possible workload?
You need kubernetes client-go to create pod or deployment.
import "k8s.io/client-go/kubernetes"
clientset, err := kubernetes.NewForConfig(cfg) // cfg is the *config
// .... ... .. create deployment
result, err := clientset.AppsV1().Deployments(namespaceName).Create(deployment) // deployment object
// ... .... ... create pod
result, err := clientset.CoreV1().Pods(namespaceName).Create(Pod) // Pod object
Related
I'm trying to use otelgin to trace my project, and it's says that where required. It is available from gin.Context.Request.Context(), so how can i get the detail information from gin.context to see if it works.
Officially, they add a stdout as the exporter when init tracer provider:
func initTracer() (*sdktrace.TracerProvider, error) {
// stdout as exporter
exporter, err := stdout.New(stdout.WithPrettyPrint())
if err != nil {
return nil, err
}
tp := sdktrace.NewTracerProvider(
sdktrace.WithSampler(sdktrace.AlwaysSample()),
sdktrace.WithBatcher(exporter),
)
otel.SetTracerProvider(tp)
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(propagation.TraceContext{}, propagation.Baggage{}))
return tp, nil
}
here is part of the command line output:
"Name": "/users/:id",
"SpanContext": {
"TraceID": "e7a43d30c0e507b4c59fd65dc3bc6d77",
"SpanID": "636c22201c903573",
"TraceFlags": "01",
"TraceState": "",
"Remote": false
},
"Parent": {
"TraceID": "00000000000000000000000000000000",
"SpanID": "0000000000000000",
"TraceFlags": "00",
"TraceState": "",
"Remote": false
},
"SpanKind": 2,
"StartTime": "2022-11-12T16:02:07.871843+08:00",
"EndTime": "2022-11-12T16:02:07.871843+08:00",
But is there any way to get this form gin.Context? Or can I get the exporter's detail information from gin.Context? I have tried to add a middleware to capture them below:
func TracerGetMiddleware(c *gin.Context) {
//var tracer oteltrace.Tracer
//tracerInterface, ok := c.Get("otel-go-contrib-tracer")
//if ok {
/// tracer, ok = tracerInterface.(oteltrace.Tracer)
//}
//tracer.Start(c, "test")
fmt.Println(c.Request.Context())
}
But this is output of c.Request.Context()
(type *http.contextKey, val <not Stringer>).WithValue(type *http.contextKey, val [::1]:8088).WithCancel.WithCancel.WithValue(type trace.traceContextKeyType, val <not Stringer>)
At present, I understand the answer I originally wanted to get, which is to get traceID, SpanID and other data in gin.context
import (
"fmt"
"github.com/gin-gonic/gin"
oteltrace "go.opentelemetry.io/otel/trace"
)
func GetIDMiddleware() gin.HandlerFunc {
return func(c *gin.Context) {
if oteltrace.SpanFromContext(c.Request.Context()).SpanContext().IsValid() {
TraceID := oteltrace.SpanFromContext(c.Request.Context()).SpanContext().TraceID().String()
SpanID := oteltrace.SpanFromContext(c.Request.Context()).SpanContext().SpanID().String()
fmt.Println(TraceID)
fmt.Println(SpanID)
}
}
}
My initial idea was to pass trace information in the context through otelgin, and then capture traceID and so on through context in gin's middleware for zap logging, but at that time I didn't know how to get TraceID and other information, and when I saw gin-contrib/zap library find the right way.
I'm trying to create a pod using Kubernetes client api in Go and I've been getting below error in TravisCI,
ERRO Running error: buildir: analysis skipped: errors in package: [/home/travis/gopath/src/github.com/pravarag/test-repo/check_pod.go:25:70: cannot use desiredPod (variable of type *"k8s.io/api/core/v1".Pod) as context.Context value in argument to s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create: missing method Deadline /home/travis/gopath/src/github.com/pravarag/test-repo/check_pod.go:25:80: too few arguments in call to s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create
Below is the code,
import (
"fmt"
"go.uber.org/zap"
core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (s *server) createPod() {
// build the pod definition
desiredPod := getPodObjet()
pod, err := s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create(desiredPod)
if err != nil {
s.log.Fatal("Failed to create the static pod", zap.Error(err))
}
fmt.Println("Created Pod: ", pod.Name)
}
func getPodObjet() *core.Pod {
pod := &core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod",
Namespace: "default",
Labels: map[string]string{
"app": "test-pod",
},
},
Spec: core.PodSpec{
Containers: []core.Container{
{
Name: "busybox",
Image: "busybox",
ImagePullPolicy: core.PullIfNotPresent,
Command: []string{
"sleep",
"3600",
},
},
},
},
}
return pod
}
I tried to check what that error is pointing to and it seems, the actual pod Interface in K8s client code here: https://godoc.org/k8s.io/client-go/kubernetes/typed/core/v1#PodInterface
is expecting 3 arguments: one is "context.Context", "pod *v1.Pod" and "opts metav1.CreateOptions"
I tried to pass the values as:
pod, err :=s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create(context.Context, desiredPod, opts metav1.CreateOptions{})
But that doesn't work also. Even in the IDE, the code lint is pointing to missing arguments but I've seen couple of examples used to create a pod in above mentioned way that worked previously.
just use context.TODO() as argument to pass context.
try this one.
pod, err := s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create( context.TODO(), desiredPod , metav1.CreateOptions{})
here is the updated code:
import (
"fmt"
"context"
"go.uber.org/zap"
core "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (s *server) createPod() {
// build the pod definition
desiredPod := getPodObjet()
pod, err := s.kubeClient.CoreV1().Pods(desiredPod.Namespace).Create( context.TODO(), desiredPod , metav1.CreateOptions{})
if err != nil {
s.log.Fatal("Failed to create the static pod", zap.Error(err))
}
fmt.Println("Created Pod: ", pod.Name)
}
func getPodObjet() *core.Pod {
pod := &core.Pod{
ObjectMeta: metav1.ObjectMeta{
Name: "test-pod",
Namespace: "default",
Labels: map[string]string{
"app": "test-pod",
},
},
Spec: core.PodSpec{
Containers: []core.Container{
{
Name: "busybox",
Image: "busybox",
ImagePullPolicy: core.PullIfNotPresent,
Command: []string{
"sleep",
"3600",
},
},
},
},
}
return pod
}
Similar to this question
How to extract schema for avro file in python
Is there a way to read in an avro file in golang without knowing the schema beforehand and extract a schema?
How about something like this (adapted code from https://github.com/hamba/avro/blob/master/ocf/ocf.go):
package main
import (
"github.com/hamba/avro"
"log"
"os"
)
// HeaderSchema is the Avro schema of a container file header.
var HeaderSchema = avro.MustParse(`{
"type": "record",
"name": "org.apache.avro.file.Header",
"fields": [
{"name": "magic", "type": {"type": "fixed", "name": "Magic", "size": 4}},
{"name": "meta", "type": {"type": "map", "values": "bytes"}},
{"name": "sync", "type": {"type": "fixed", "name": "Sync", "size": 16}}
]
}`)
var magicBytes = [4]byte{'O', 'b', 'j', 1}
const (
schemaKey = "avro.schema"
)
// Header represents an Avro container file header.
type Header struct {
Magic [4]byte `avro:"magic"`
Meta map[string][]byte `avro:"meta"`
Sync [16]byte `avro:"sync"`
}
func main() {
r, err := os.Open("path/my.avro")
if err != nil {
log.Fatal(err)
}
defer r.Close()
reader := avro.NewReader(r, 1024)
var h Header
reader.ReadVal(HeaderSchema, &h)
if reader.Error != nil {
log.Println("decoder: unexpected error: %v", reader.Error)
}
if h.Magic != magicBytes {
log.Println("decoder: invalid avro file")
}
schema, err := avro.Parse(string(h.Meta[schemaKey]))
if err != nil {
log.Println(err)
}
log.Println(schema)
}
Both https://github.com/hamba/avro and https://github.com/linkedin/goavro can decode Avro OCF files (which it sounds like is what you have) without an explicit schema file.
Once you've created a new reader/decoder, you can retrieve the metadata, which includes the schema at key avro.schema: https://pkg.go.dev/github.com/hamba/avro/ocf#Decoder.Metadata and https://pkg.go.dev/github.com/linkedin/goavro#OCFReader.MetaData
I have the eclipse software ready to go.
What I am looking for is to debug output the return data for calling search.RetrieveFeeds().
So, in essence, I'd be able to see an array of Feed structs so i know it processed the json data file
When I execute I get this error:
main\main.go:10:38: multiple-value search.RetrieveFeeds() in single-value context
I looked here: Multiple values in single-value context but it was a bit over my head.
Here is what I have so far as my architecture:
Data Json File Path
src/data/data.json
Data for Json File
[
{
"site": "npr",
"link": "http://www.npr.org/rss/rss.php?id=1001",
"type": "rss"
},
{
"site": "cnn",
"link": "http://rss.cnn.com/rss/cnn_world.rss",
"type": "rss"
},
{
"site": "foxnews",
"link": "http://feeds.foxnews.com/foxnews/world?format=xml",
"type": "rss"
},
{
"site": "nbcnews",
"link": "http://feeds.nbcnews.com/feeds/topstories",
"type": "rss"
}
]
Main Method File Path
src/main/main.go
Code for Main Method
package main
import (
"fmt"
"search"
)
func main() {
fmt.Println("HellAo")
var feeds = search.RetrieveFeeds()
fmt.Printf("%v",feeds)
}
Search File Path
src/search/feed.go
Search File Code
package search
import (
"encoding/json"
"os"
)
const dataFile = "data/data.json"
type Feed struct {
Name string `json:"site"`
URI string `json:"link"`
Type string `json:"type"`
}
func RetrieveFeeds() ([]*Feed, error){
file, err := os.Open(dataFile)
if err != nil {
return nil, err
}
defer file.Close()
var feeds []*Feed
err = json.NewDecoder(file).Decode(&feeds)
return feeds, err
}
UPDATE
I changed the data json path to:
const dataFile = "src/data/data.json"
And now the debug dump says:
<nil>
Trying to unmarshal a json text into my own struct. My struct definitions seem correct but json.Unmarshal doesn't return anything.
package main
import (
"encoding/json"
"fmt"
)
type CmdUnit struct {
Command string
Description string
}
type CmdList struct {
ListOfCommands []CmdUnit
}
type OneCmdList struct {
Area string
CmdList CmdList
}
type AllCommands struct {
AllAreas []OneCmdList
}
func main() {
jsonTxt := `
{
"Area1": [{
"Command": "cmd1",
"Desc": "cmd1 desc"
}, {
"Command": "cmd2",
"Desc": "cmd2 desc"
}],
"Area2": [{
"Command": "cmd1",
"Desc": "cmd1 desc"
}]
}
`
cmds := AllCommands{}
if err := json.Unmarshal([]byte(jsonTxt), &cmds); err != nil {
fmt.Println("Failed to unmarshal:", err)
} else {
fmt.Printf("%+v\n", cmds)
}
}
$ go run j.go
{AllAreas:[]}
Your structs have a different structure from the json you're providing. Marshalling the structs in your example would result in json that looks like:
{
"AllAreas": [
{
"Area": "Area1",
"CmdList": {
"ListOfCommands": [
{
"Command": "cmd1",
"Description": "cmd1 desc"
},
{
"Command": "cmd2",
"Description": "cmd2 desc"
}
]
}
}
]
}
The json in your example can be unmarshaled directly into a map[string][]CmdUnit{} with the minor change of CmdUnit.Description to CmdUnit.Desc.
cmds := map[string][]CmdUnit{}
if err := json.Unmarshal(jsonTxt, &cmds); err != nil {
log.Fatal("Failed to unmarshal:", err)
}
fmt.Printf("%+v\n", cmds)
https://play.golang.org/p/DFLYAfNLES