Skip to content
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
15 changes: 11 additions & 4 deletions internal/cmdget/cmdget.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,11 @@ func NewRunner(ctx context.Context, parent string) *Runner {
_ = c.RegisterFlagCompletionFunc("strategy", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return kptfilev1.UpdateStrategiesAsStrings(), cobra.ShellCompDirectiveDefault
})

c.Flags().BoolVar(&r.localGcloudConfig, "local-gcloud", false, "pull local gcloud config as default package value.")
_ = c.RegisterFlagCompletionFunc("local-gcloud", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
return kptfilev1.UpdateStrategiesAsStrings(), cobra.ShellCompDirectiveDefault
})
return r
}

Expand All @@ -64,10 +69,11 @@ func NewCommand(ctx context.Context, parent string) *cobra.Command {

// Runner contains the run function
type Runner struct {
ctx context.Context
Get get.Command
Command *cobra.Command
strategy string
ctx context.Context
Get get.Command
Command *cobra.Command
strategy string
localGcloudConfig bool
}

func (r *Runner) preRunE(_ *cobra.Command, args []string) error {
Expand Down Expand Up @@ -101,6 +107,7 @@ func (r *Runner) preRunE(_ *cobra.Command, args []string) error {
return err
}
r.Get.UpdateStrategy = strategy
r.Get.EnableDefaultGcloud = r.localGcloudConfig
return nil
}

Expand Down
10 changes: 10 additions & 0 deletions internal/docs/generated/pkgdocs/docs.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion internal/fnruntime/runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -499,6 +499,5 @@ data: {}
}
return configNode, nil
}
// no need to return ConfigMap if no config given
return nil, nil
}
8 changes: 8 additions & 0 deletions internal/util/get/get.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ type Command struct {
// Kptfile. This determines how changes will be merged when updating the
// package.
UpdateStrategy kptfilev1.UpdateStrategyType

EnableDefaultGcloud bool
}

// Run runs the Command.
Expand Down Expand Up @@ -100,6 +102,12 @@ func (c Command) Run(ctx context.Context) error {
return cleanUpDirAndError(c.Destination, err)
}

if c.EnableDefaultGcloud {
if err := AddGcloudConfigMap(c.Destination, c.Name); err != nil {
return err
}
}

inout := &kio.LocalPackageReadWriter{PackagePath: c.Destination, PreserveSeqIndent: true, WrapBareSeqNode: true}
amc := &addmergecomment.AddMergeComment{}
at := &attribution.Attributor{PackagePaths: []string{c.Destination}, CmdGroup: "pkg"}
Expand Down
136 changes: 136 additions & 0 deletions internal/util/get/local.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package get

import (
"bytes"
"fmt"
"io/ioutil"
"os/exec"
"path/filepath"
"regexp"
"strings"

"github.com/GoogleContainerTools/kpt/internal/errors"
"github.com/GoogleContainerTools/kpt/internal/util/pkgutil"
"sigs.k8s.io/kustomize/kyaml/yaml"
)

var domainRegex = regexp.MustCompile(`\S+@(\S+)`)

// AddGcloudConfigMap creates a `gcloud-config.yaml` file under PKG_DIR.
// This file has a ConfigMap `gcloud-config` whose `data` stores local
// gcloud configurations.
func AddGcloudConfigMap(dir, pkgName string) error {
const op errors.Op = "kptfileutil.PullLocalGcloudConfig"
data, err := pullLocalGcloudConfig(pkgName)
if err != nil {
return err
}
cm := yaml.MustParse(`
apiVersion: v1
kind: ConfigMap
metadata:
name:
data: {}
`)
// !! This ConfigMap should always be assigned to this value to make it "convention over configuration".
cm.SetName(pkgutil.GcloudMetaName)
cm.SetDataMap(data)
return writeFile(filepath.Join(dir, pkgutil.GcloudConfigFile), cm)
}

func pullLocalGcloudConfig(pkgName string) (map[string]string, error) {
projectID := getGcloudConfig("project")
if projectID == "" {
return nil, fmt.Errorf("`project` has not been set in `gcloud`")
}
zone := getGcloudConfig("compute/zone")
if zone == "" {
fmt.Println("`compute/zone` has not been set in `gcloud`")
}
region := getGcloudConfig("compute/region")
if region == "" {
fmt.Println(fmt.Errorf("`compute/region` has not been set in `gcloud`"))
}
var domain string
if account := getGcloudConfig("core/account"); account == "" {
fmt.Println("`core/account` has not been set in `gcloud`")
} else {
// e.g. account `[email protected]` has matching domain `COMPANY.com`
matches := domainRegex.FindStringSubmatch(account)
if len(matches) < 2 {
fmt.Println("`unable to parse `domain` from gcloud `core/account`")
} else {
domain = matches[1]
}
}
orgID, err := getGcloudOrgID(projectID)
if err != nil {
return nil, err
}
if orgID == "" {
fmt.Println("`Organization` or `Folder` not found")
}

return map[string]string{
// !!! `name` should not belong to gcloud-config.yaml. If needed, the user's Kptfile shall refer to the
// metadata resource which can be propagated in `kpt fn render` runtime. e.g. via --include-metadata-resource flag.
// This is a temporary workaround.
"name": pkgName,
"namespace": projectID,
"projectID": projectID,
"zone": zone,
"region": region,
"domain": domain,
"orgID": orgID,
}, nil

}

func getGcloudConfig(property string) string {
var cmdOut, cmdErr bytes.Buffer
cmd := exec.Command("gcloud", "config", "get-value", property)
cmd.Stdout = &cmdOut
cmd.Stderr = &cmdErr
err := cmd.Run()
if err != nil {
panic(fmt.Errorf("unable to run `gcloud` %v", err.Error()))
}
if cmdErr.Len() > 0 {
return ""
}
raw := cmdOut.String()
return strings.TrimSpace(raw)
}

func getGcloudOrgID(projectID string) (string, error) {
var buf, err, out bytes.Buffer
cmdListAncestors := exec.Command("gcloud", "projects", "get-ancestors",
projectID, "--format=get(id)")
cmdListAncestors.Stdout = &buf
cmdListAncestors.Stderr = &err
cmdListAncestors.Run()
if err.Len() > 0 {
return "", fmt.Errorf(err.String())
}
cmdOrgID := exec.Command("tail", "-1")
cmdOrgID.Stdin = &buf
cmdListAncestors.Stderr = &err
cmdOrgID.Stdout = &out
cmdOrgID.Run()
if err.Len() > 0 {
return "", fmt.Errorf(err.String())
}
raw := out.String()
return strings.TrimSpace(raw), nil
}

func writeFile(fpath string, cm *yaml.RNode) error {
const op errors.Op = "kptfileutil.WriteGcloudConfigMapFile"
out, err := cm.String()
if err != nil {
return err
}
yaml.MarshalWithOptions(cm.YNode().Value, &yaml.EncoderOptions{SeqIndent: yaml.WideSequenceStyle})
return ioutil.WriteFile(fpath, []byte(out), 0600)

}
5 changes: 5 additions & 0 deletions internal/util/pkgutil/pkgutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@ import (
"sigs.k8s.io/kustomize/kyaml/kio/filters"
)

const (
GcloudConfigFile = "gcloud-config.yaml"
GcloudMetaName = "gcloud-config.kpt.dev"
)

// WalkPackage walks the package defined at src and provides a callback for
// every folder and file. Any subpackages and the .git folder are excluded.
func WalkPackage(src string, c func(string, os.FileInfo, error) error) error {
Expand Down
10 changes: 10 additions & 0 deletions site/reference/cli/pkg/get/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,16 @@ LOCAL_DEST_DIRECTORY:
since it was fetched.
* force-delete-replace: Wipe all the local changes to the package and replace
it with the remote version.

--local-gcloud:
Pulls the local gcloud config as default function data. The gcloud config to function
data is based on best practice. For example, the default gcloud "project" is used by
"set-project-id" function to set project value for input resources' metadata.annotation
"cnrm.cloud.google.com/project-id" and other specific "project" field.
e.g. Resources of GVK "gkehub.cnrm.cloud.google.com_v1beta1_GKEHubFeatureMembership"
will have both `metadata.annotations[cnrm.cloud.google.com/project-id]` and
path `spec.projectRef.external` updated toe the local gcloud "project"
when running `set-project-id`.
```

#### Env Vars
Expand Down