how to convert the given code in go templating - go

I am using go's text/template. I want to do something like:
method = some_var
path = some_other_var
if method is "GET" and "ID" in path
How can I do this in a go template? I am doing it like this.
{{- if and eq .Method "GET" contains "AssetID" .OperationId -}}
EDIT:
The thing is I am working with openAPI to generate a server-code boilerplate. So the templates are in that repo. I am doing it something like:
$ go get github.com/deepmap/oapi-codegen/cmd/oapi-codegen
$ oapi-codegen \
-templates my-templates/ \
-generate types,server \
example-expanded.yaml
above oapi-codegen line is here.
my-templates contains the templates I have changed. These are also provided by oapi-codegen. this dir contains them and I have copied and changed a few of them and followed the steps as directed here.
in one of those templates that I changed, I want to use contains.
What would be the best way to do this?

There is no builtin contains function in templates, so you have to register your function for that. You may use the strings.Contains() function from the standard lib. For reference, the available builtin template functions are listed here: Functions
And you have to group the params of the eq and contains like this:
{{if and (eq .Method "GET") (contains .AssetID .OperationId)}}
true
{{else}}
false
{{end}}
Example code to register the strings.Contains() function, parse the template and execute it:
t := template.Must(template.New("").Funcs(template.FuncMap{
"contains": strings.Contains,
}).Parse(src))
params := map[string]interface{}{
"Method": "GET",
"AssetID": "/some/path/123",
"OperationId": "123",
}
if err := t.Execute(os.Stdout, params); err != nil {
panic(err)
}
params["OperationId"] = "xxx"
if err := t.Execute(os.Stdout, params); err != nil {
panic(err)
}
This will output (try it on the Go Playground):
true
false

Related

How to use go-github to post a comment on a Github issue?

I want to use https://github.com/google/go-github for creating a comment on an issue, but this test code fails:
package main
import (
"golang.org/x/oauth2"
"github.com/google/go-github/v49/github"
)
func main() {
ctx := context.Background()
ts := oauth2.StaticTokenSource(
&oauth2.Token{AccessToken: "token_here"},
)
tc := oauth2.NewClient(ctx, ts)
client := github.NewClient(tc)
// list all repositories for the authenticated user
repos, _, err := client.Repositories.List(ctx, "", nil)
}
but I'm just getting
# command-line-arguments
./main.go:9:9: undefined: context
./main.go:18:2: repos declared but not used
./main.go:18:12: err declared but not used
back...
So - what I have to do to get this working and how can I send a comment (via my token) to an issue on github?
./main.go:9:9: undefined: context
You need to import the "context" package to be able to call context.Background()
./main.go:18:2: repos declared but not used
./main.go:18:12: err declared but not used
After calling client.Repositories.List(ctx, "", nil) you created 2 new variables: repos and err, but never used them anywhere. In Go, an unused variable is a compiler error, so either remove those variables, or preferably use them as you would.
So - what i have to do to get this working and how can i send a comment (via my token) to an issue on github?
To use the Github API, you will need to get yourself an access token, and replace "token_here" with that. Then you can do something as follows:
comment := &github.IssueComment{
Body: github.String("Hello, world!"),
}
comment, _, err := client.Issues.CreateComment(
context.Background(),
"OWNER",
"REPO",
ISSUE_NUMBER,
comment,
)
if err != nil {
// handle any errors
}
... where OWNER is the owner of the repository, REPO is the name of the repository, and ISSUE_NUMBER is the number of the issue where you want to write the comment.

How to handle SPA urls correctly in Golang?

I am trying to embed and serve my frontend (nextjs with static export) with echo. I am currently using:
//go:embed all:frontend/out
var FrontendFS embed.FS
func BuildFrontendFS() http.FileSystem {
build, err := fs.Sub(FrontendFS, "frontend/out")
if err != nil {
log.Fatal(err)
}
return http.FS(build)
}
e := echo.New()
e.Use(middleware.StaticWithConfig(middleware.StaticConfig{
Filesystem: BuildFrontendFS(),
HTML5: true,
}))
e.Logger.Fatal(e.Start(":1323"))
It works great however when I try to open a url like localhost:1323/example it routes back to index.html. The problem is that there is a page called example.html and I am expecting to see that page instead. If I call the url like localhost:1323/example.html it works.
Any ideas how I can solve this so that I can just use localhost:1323/example ?
I see an ./out directory being referenced, so it looks like you're exporting to static HTML. If that's the case, enable the trailingSlash setting in your next.config.js:
module.exports = {
trailingSlash: true,
}
./example.html will become ./example/index.html after the export.

how to do open api format yaml validation, without using clusters?

I have build a schema in open api format:
type Test_manifest struct {
metav1.TypeMeta
metav1.ObjectMeta
Spec spec
}
type spec struct {
Policies []string
Resources resources
Results []results
Variables variables
}
This is not complete schema, just a part of it.
And here below is the actual yaml file:
apiVersion: cli.kyverno.io/v1beta1
kind: kyvernotest
metadata:
name: test-check-nvidia-gpus
labels:
foolabel: foovalue
annotations:
fookey: foovalue
I'm trying to validate this incoming yaml file from the user, I can convert this yaml to json and then validate the value of the fields, but I'm not getting how to validate the field itself, I mean if user write name1 rather than name then how to show error on it. Basically how to validate the key.
Here's what I've implemented for value validation:
test := "cmd/cli/kubectl-kyverno/test/test.yaml"
yamlFile, err := ioutil.ReadFile(test)
if err != nil {
fmt.Printf("Error: failed to read file %v", err)
}
policyBytes, err1 := yaml.ToJSON(yamlFile)
if err1 != nil {
fmt.Printf("failed to convert to JSON")
}
tests := &kyvernov1.Test_manifest{}
if err := json.Unmarshal(policyBytes, tests); err != nil {
fmt.Printf("failed to decode yaml")
}
if tests.TypeMeta.APIVersion == "" {
fmt.Printf("skipping file as tests.TypeMeta.APIVersion not found")
}
if tests.TypeMeta.Kind == "" {
fmt.Printf("skipping file as tests.TypeMeta.Kind not found")
} else if tests.TypeMeta.Kind != "KyvernoTest" {
fmt.Printf("skipping file as tests.TypeMeta.Kind is not `KyvernoTest`")
}
Also we want this valiadtion to happen outside the cluster.
Two things come to my mind:
I notice that you are trying to build a k8s API extension manually which is a lot of rework, I will suggest you use a framework which will handle this for you. This is the recommended best practice that is used very frequently. It is too complicated to be done manually. Here are some resources. (kube-builder, operator-sdk). These solution are Open-API based as well. They will let you define your schema in a simple template, and generate all the validation and API + controller code for you.
If you want more validation and sanity testing, typically this is done with the help of an admission controller in your cluster. It intercepts the incoming request, and before it is processed by the API server, performs actions on it. (For verification, compliance, policy enforcement, authentication etc.) You can read more about admission controllers here.

How do you marshal a line break in Go YAML?

In a golang CLI I'm programming I collect information on how to configure the tool and I marhsal that as a YAML file. However, I'm not sure how I would add line breaks to make the file more readable?
type Config struct {
Author string `yaml:"author"`
License string `yaml:"license"`
// Marhsal a line break here
Workspace string `yaml:"workspace"`
Description string `yaml:"description"`
// Marhsal a line break here
Target string `yaml:"target"`
}
One way to implement this that allows format (and comments) is to use a template engine.
Here is a running example that generates a string with the formatted yaml, that can be then saved to a .yml file.
No additional libraries are needed and the template is included inside the go file.
package main
import (
"bytes"
"fmt"
"text/template"
)
type Config struct {
Author string
License string
Workspace string
Description string
Target string
}
const cfg_template = `
conf:
author: {{ .Author }}
licence: {{ .License }}
workspace: {{ .Workspace }}
description: {{ .Description }}
# you can even add comments to the template
target: {{ .Target }}
# other hardcoded config
foo: bar
`
func generate(config *Config) string {
t, err := template.New("my yaml generator").Parse(cfg_template)
if err != nil {
panic(err)
}
buf := &bytes.Buffer{}
err = t.Execute(buf, config)
if err != nil {
panic(err)
}
return buf.String()
}
func main() {
c := Config{
Author: "Germanio",
License: "MIT",
Workspace: "/home/germanio/workspace",
Description: "a cool description",
Target: "/home/germanio/target",
}
yaml := generate(&c)
fmt.Printf("yaml:\n%s", yaml)
}
The result looks like this:
$ go run yaml_generator.go
yaml:
conf:
author: Germanio
licence: MIT
workspace: /home/germanio/workspace
description: a cool description
# you can even add comments to the template
target: /home/germanio/target
# other hardcoded config
foo: bar
I'm sure there are better ways to implement it, just want to show a quick working example.
As empty line don't have a meaning in yaml, the default library does not create them, and does not expose an option to do so in the struct field tag.
However, if you want fine grained control of how a type is marshalled in yaml, you can always make it implements yaml.Marshaller by defining a method MarshalYAML() (interface{}, error)

Google Directory API add Custom Schema/Update it to Users per google API (in go)

I am trying to upload a CustomSchema to all Users of a company in GSuite. This Custom Schema contains their Github Usernames, which I extracted with the github API.
The problem is, after running the code, the account in Gsuite is not added.
Relevant code (A connection to GSuite with admin Authentication is established, the map has all user entries. If you still want more code, I can provide you with it - just trying to keep it simple):
for _, u := range allUsers.Users {
if u.CustomSchemas != nil {
log.Printf("%v", string(u.CustomSchemas["User_Names"]))
}else{
u.CustomSchemas = map[string]googleapi.RawMessage{}
}
nameFromGsuite := u.Name.FullName
if githubLogin, ok := gitHubAccs[nameFromGsuite]; ok {
userSchemaForGithub := GithubAcc{GitHub: githubLogin}
jsonRaw, err := json.Marshal(userSchemaForGithub)
if err != nil {
log.Fatalf("Something went wrong logging: %v", err)
}
u.CustomSchemas["User_Names"] = jsonRaw
adminService.Users.Update(u.Id, u)
} else {
log.Printf("User not found for %v\n", nameFromGsuite)
}
}
This is the struct for the json encoding:
type GithubAcc struct {
GitHub string `json:"GitHub"`
}
For anyone stumbling upon this.
Everything in the code snippet is correct. By the way the method is written, I expected that adminService.Users.Update() actually updates the user. Instead, it returns an UserUpdatesCall.
You need to execute that update by calling .Do()
From the API:
Do executes the "directory.users.update" call.
So the solution is to change adminService.Users.Update(u.Id, u)
into adminService.Users.Update(u.Id, u).Do()

Resources