Skip to content

Add set-org-id function #763

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions functions/go/gcp-set-org-id/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
FROM golang:1.17-alpine3.13
ENV CGO_ENABLED=0
WORKDIR /go/src/

COPY go.mod go.sum ./

COPY . .
RUN go build -o /usr/local/bin/function ./

#############################################

FROM alpine:3.13
COPY --from=0 /usr/local/bin/function /usr/local/bin/function
ENTRYPOINT ["function"]
11 changes: 11 additions & 0 deletions functions/go/gcp-set-org-id/consts/organization.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package consts

// OrgFieldSpec contains the fieldSpec paths of Google Cloud OrganizationID
const OrgFieldSpec = `
organizationsIDs:
# Blueprint iam-foundation
- path: spec/resourceRef
group: iam.cnrm.cloud.google.com
version: v1beta1
kind: IAMPolicyMember
`
33 changes: 33 additions & 0 deletions functions/go/gcp-set-org-id/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
module github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/gcp-set-org-id

go 1.17

require (
sigs.k8s.io/kustomize/api v0.11.1
sigs.k8s.io/kustomize/kyaml v0.13.3
)

require (
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-errors/errors v1.0.1 // indirect
github.com/go-openapi/jsonpointer v0.19.3 // indirect
github.com/go-openapi/jsonreference v0.19.3 // indirect
github.com/go-openapi/swag v0.19.5 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/mailru/easyjson v0.7.0 // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/spf13/cobra v1.2.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.7.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
golang.org/x/text v0.3.5 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/kube-openapi v0.0.0-20210421082810-95288971da7e // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
646 changes: 646 additions & 0 deletions functions/go/gcp-set-org-id/go.sum

Large diffs are not rendered by default.

58 changes: 58 additions & 0 deletions functions/go/gcp-set-org-id/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package main

import (
"fmt"
"os"

"sigs.k8s.io/kustomize/api/hasher"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/resource"
"sigs.k8s.io/kustomize/kyaml/fn/framework"
"sigs.k8s.io/kustomize/kyaml/fn/framework/command"
)

type Processor struct {}

func newResMapFactory() *resmap.Factory {
resourceFactory := resource.NewFactory(&hasher.Hasher{})
resourceFactory.IncludeLocalConfigs = true
return resmap.NewFactory(resourceFactory)
}

func (p *Processor) Process(resourceList *framework.ResourceList) error {
err := func() error{
trans := &Transformer{}
err := trans.Config(resourceList.FunctionConfig)
if err != nil {
return err
}
resmapFactory := newResMapFactory()
resMap, err := resmapFactory.NewResMapFromRNodeSlice(resourceList.Items)
if err != nil {
return fmt.Errorf("failed to convert items to resource map: %w", err)
}
if err := trans.Transform(resMap); err != nil {
return err
}
resourceList.Items = resMap.ToRNodeSlice()
return nil
}()
if err != nil {
resourceList.Results = framework.Results{
&framework.Result{
Message: err.Error(),
Severity: framework.Error,
},
}
return resourceList.Results
}
return nil
}

func main() {
cmd := command.Build(&Processor{}, command.StandaloneEnabled, false)
if err := cmd.Execute(); err != nil {
fmt.Fprintln(os.Stderr, err)
os.Exit(1)
}
}
62 changes: 62 additions & 0 deletions functions/go/gcp-set-org-id/plugins/filter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package plugins

import (
"sigs.k8s.io/kustomize/api/filters/fieldspec"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/kio"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

const OrgKind = "Organization"

var _ kio.Filter = Filter{}

type Filter struct {
OrgID string
FsSlice []types.FieldSpec
}

// isOrg determins if the rnode in current fieldspec has "kind: Organization". Expecting the orgId to be
// spec:
// resourceRef:
// apiVersion: resourcemanager.cnrm.cloud.google.com/v1beta1
// kind: Organization <-- kind has to be Organization
// external: 433637338589 <-- OrgID
func isOrg(node *yaml.RNode) bool {
for i := 0; i < len(node.YNode().Content); i += 2 {
if node.YNode().Content[i].Value == "kind" {
return node.YNode().Content[i+1].Value == OrgKind
}
}
return false
}

// setOrg updates the "external" rnode's value to OrgID.
func setOrg(node *yaml.RNode, orgID string) {
for i := 0; i < len(node.YNode().Content); i += 2 {
if node.YNode().Content[i].Value == "external" {
node.YNode().Content[i+1].SetString(orgID)
}
}
}

func (f Filter) Filter(nodes []*yaml.RNode) ([]*yaml.RNode, error) {
_, err := kio.FilterAll(yaml.FilterFunc(
func(node *yaml.RNode) (*yaml.RNode, error) {
var fns []yaml.Filter
for _, fs := range f.FsSlice {
fn := fieldspec.Filter{
FieldSpec: fs,
SetValue: func(node *yaml.RNode) error {
if isOrg(node) {
setOrg(node, f.OrgID)
}
return nil
},
}
fns = append(fns, fn)
}
return node.Pipe(fns...)
})).Filter(nodes)
return nodes, err
}
43 changes: 43 additions & 0 deletions functions/go/gcp-set-org-id/transformer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
package main

import (
"fmt"

"github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/gcp-set-org-id/consts"
"github.com/GoogleContainerTools/kpt-functions-catalog/functions/go/gcp-set-org-id/plugins"
"sigs.k8s.io/kustomize/api/resmap"
"sigs.k8s.io/kustomize/api/types"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

const (
OrgIDKey = "orgID"
)

type Transformer struct {
FieldSpecs []types.FieldSpec `json:"organizationsIDs,omitempty" yaml:"organizationsIDs,omitempty"`
OrgID string
}

func (p *Transformer) Config(fnConfigNode *yaml.RNode) error {
if err := yaml.Unmarshal([]byte(consts.OrgFieldSpec), &p); err != nil {
return err
}
data := fnConfigNode.GetDataMap()
if data == nil {
return fmt.Errorf("missing `data` field in `ConfigMap` FunctionConfig")
}
orgID, ok := data[OrgIDKey]
if !ok {
return fmt.Errorf("missing `.data.%s` field in `ConfigMap` FunctionConfig", OrgIDKey)
}
p.OrgID = orgID
return nil
}

func (p *Transformer) Transform(m resmap.ResMap) error {
return m.ApplyFilter(plugins.Filter{
OrgID: p.OrgID,
FsSlice: p.FieldSpecs,
})
}