From 49505beca42858e7d406df90cc00eb41ad7e2530 Mon Sep 17 00:00:00 2001 From: Arturo Contreras Date: Tue, 2 Mar 2021 10:11:16 -0800 Subject: [PATCH] Have option to specify gitops path where to place generated files --- README.md | 1 + examples/.gitignore | 1 + examples/e2e-test.sh | 7 ++++++- examples/helloworld/BUILD | 20 ++++++++++++++++++++ gitops/git/git.go | 9 +++++---- gitops/prer/create_gitops_prs.go | 5 +++-- skylib/k8s.bzl | 2 ++ skylib/kustomize/kustomize.bzl | 10 ++++++---- 8 files changed, 44 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index ad3ba6d3..6d3722f0 100644 --- a/README.md +++ b/README.md @@ -108,6 +108,7 @@ When you run `bazel run ///helloworld:mynamespace.apply`, it applies this file i | ***image_repository_prefix*** | `None` | Add a prefix to the image_repository. Can be used to upload the images in | ***release_branch_prefix*** | `master` | A git branch name/prefix. Automatically run GitOps while building this branch. See [GitOps and Deployment](#gitops_and_deployment). | ***deployment_branch*** | `None` | Automatic GitOps output will appear in a branch and PR with this name. See [GitOps and Deployment](#gitops_and_deployment). +| ***gitops_path*** | `cloud` | Path within the git repo where gitops files get generated into | ***visibility*** | [Default_visibility](https://docs.bazel.build/versions/master/be/functions.html#package.default_visibility) | Changes the visibility of all rules generated by this macro. See [Bazel docs on visibility](https://docs.bazel.build/versions/master/be/common-definitions.html#common-attributes). diff --git a/examples/.gitignore b/examples/.gitignore index 59ef5f05..42d0155f 100644 --- a/examples/.gitignore +++ b/examples/.gitignore @@ -1 +1,2 @@ cloud/ +custom_cloud/ diff --git a/examples/e2e-test.sh b/examples/e2e-test.sh index f196c58e..b76c9d95 100755 --- a/examples/e2e-test.sh +++ b/examples/e2e-test.sh @@ -39,9 +39,14 @@ rm -rf cloud bazel run //helloworld:canary.gitops bazel run //helloworld:release.gitops +bazel run //helloworld:gitops_custom_path.gitops #the result of .gitops operation goes into /cloud directory and should be submitted back to the repo #apply everything generated kubectl apply -f cloud -R + +#apply gitops_custom_path gen +kubectl apply -f custom_cloud -R + #wait for readiness -kubectl -n hwteam wait --timeout=60s --for=condition=Available deployment/helloworld deployment/helloworld-canary +kubectl -n hwteam wait --timeout=60s --for=condition=Available deployment/helloworld deployment/helloworld-canary deployment/helloworld-gitops-custom-path diff --git a/examples/helloworld/BUILD b/examples/helloworld/BUILD index 1e5d209e..b297deda 100644 --- a/examples/helloworld/BUILD +++ b/examples/helloworld/BUILD @@ -102,6 +102,26 @@ k8s_deploy( user = USER, ) +k8s_deploy( + name = "gitops_custom_path", + cluster = CLUSTER, + deployment_branch = "helloworld-gitops-custom-path", + gitops_path = "custom_cloud", + image_digest_tag = True, # test optional image tagging + image_registry = REGISTRY, # override the default registry host for production + image_repository_prefix = "k8s", + images = { + "helloworld-image": ":image", + }, + manifests = [ + "deployment.yaml", + "service.yaml", + ], + name_suffix = "-gitops-custom-path", + namespace = NAMESPACE, + user = USER, +) + sh_test( name = "k8s_deploy_test", srcs = ["k8s_deploy_test.sh"], diff --git a/gitops/git/git.go b/gitops/git/git.go index 9ae4c2af..78181649 100644 --- a/gitops/git/git.go +++ b/gitops/git/git.go @@ -32,7 +32,7 @@ var ( // repo: https://aleksey.pesternikov@bitbucket.tubemogul.info/scm/tm/repo.git // dir: /tmp/cloudrepo // mirrorDir: optional (if not empty) local mirror of the repository -func Clone(repo, dir, mirrorDir, primaryBranch string) (*Repo, error) { +func Clone(repo, dir, mirrorDir, primaryBranch, gitopsPath string) (*Repo, error) { if err := os.RemoveAll(dir); err != nil { return nil, fmt.Errorf("Unable to clone repo: %w", err) } @@ -42,7 +42,8 @@ func Clone(repo, dir, mirrorDir, primaryBranch string) (*Repo, error) { exec.Mustex("", "git", "clone", "-n", repo, dir) } exec.Mustex(dir, "git", "config", "--local", "core.sparsecheckout", "true") - if err := ioutil.WriteFile(filepath.Join(dir, ".git/info/sparse-checkout"), []byte("cloud/\n"), 0644); err != nil { + genPath := fmt.Sprintf("%s/\n", gitopsPath) + if err := ioutil.WriteFile(filepath.Join(dir, ".git/info/sparse-checkout"), []byte(genPath), 0644); err != nil { return nil, fmt.Errorf("Unable to create .git/info/sparse-checkout: %w", err) } exec.Mustex(dir, "git", "checkout", primaryBranch) @@ -93,8 +94,8 @@ func (r *Repo) GetLastCommitMessage() (msg string) { } // Commit all changes to the current branch. returns true if there were any changes -func (r *Repo) Commit(message string) bool { - exec.Mustex(r.Dir, "git", "add", "cloud") +func (r *Repo) Commit(message, gitopsPath string) bool { + exec.Mustex(r.Dir, "git", "add", gitopsPath) if r.IsClean() { return false } diff --git a/gitops/prer/create_gitops_prs.go b/gitops/prer/create_gitops_prs.go index 44177699..55d09ced 100644 --- a/gitops/prer/create_gitops_prs.go +++ b/gitops/prer/create_gitops_prs.go @@ -39,6 +39,7 @@ var ( workspace = flag.String("workspace", "", "path to workspace root") repo = flag.String("git_repo", "https://bitbucket.tubemogul.info/scm/tm/repo.git", "git repo location") gitMirror = flag.String("git_mirror", "", "git mirror location, like /mnt/mirror/bitbucket.tubemogul.info/tm/repo.git for jenkins") + gitopsPath = flag.String("gitops_path", "cloud", "location to store files in repo.") gitopsTmpDir = flag.String("gitops_tmpdir", os.TempDir(), "location to check out git tree with /cloud.") target = flag.String("target", "//... except //experimental/...", "target to scan. Useful for debugging only") pushParallelism = flag.Int("push_parallelism", 5, "Number of image pushes to perform concurrently") @@ -116,7 +117,7 @@ func main() { log.Fatalf("Unable to create tempdir in %s: %v", *gitopsTmpDir, err) } defer os.RemoveAll(gitopsdir) - workdir, err := git.Clone(*repo, gitopsdir, *gitMirror, *prInto) + workdir, err := git.Clone(*repo, gitopsdir, *gitMirror, *prInto, *gitopsPath) if err != nil { log.Fatalf("Unable to clone repo: %v", err) } @@ -149,7 +150,7 @@ func main() { bin := bazel.TargetToExecutable(target) exec.Mustex("", bin, "--nopush", "--nobazel", "--deployment_root", gitopsdir) } - if workdir.Commit(fmt.Sprintf("GitOps for release branch %s from %s commit %s\n%s", *releaseBranch, *branchName, *gitCommit, commitmsg.Generate(targets))) { + if workdir.Commit(fmt.Sprintf("GitOps for release branch %s from %s commit %s\n%s", *releaseBranch, *branchName, *gitCommit, commitmsg.Generate(targets)), *gitopsPath) { log.Println("branch", branch, "has changes, push is required") updatedGitopsTargets = append(updatedGitopsTargets, targets...) updatedGitopsBranches = append(updatedGitopsBranches, branch) diff --git a/skylib/k8s.bzl b/skylib/k8s.bzl index 41cc3fdd..a29ddf39 100644 --- a/skylib/k8s.bzl +++ b/skylib/k8s.bzl @@ -125,6 +125,7 @@ def k8s_deploy( image_repository_prefix = None, # Mutually exclusive with 'image_repository'. Add a prefix to the repository name generated from the image bazel path objects = [], gitops = True, # make sure to use gitops = False to work with individual namespace. This option will be turned False if namespace is '{BUILD_USER}' + gitops_path = "cloud", deployment_branch = None, release_branch_prefix = "master", flatten_manifest_directories = False, @@ -258,6 +259,7 @@ def k8s_deploy( srcs = [name], cluster = cluster, namespace = namespace, + gitops_path = gitops_path, strip_prefixes = [ namespace + "-", cluster + "-", diff --git a/skylib/kustomize/kustomize.bzl b/skylib/kustomize/kustomize.bzl index 844abb5c..a5f902ab 100644 --- a/skylib/kustomize/kustomize.bzl +++ b/skylib/kustomize/kustomize.bzl @@ -442,14 +442,15 @@ fi if "{" in namespace: fail("unable to gitops namespace with placeholders %s" % inattr.label) #mynamespace should not be gitopsed for infile in inattr.files.to_list(): - statements += ("echo $TARGET_DIR/cloud/{namespace}/{cluster}/{file}\n" + - "mkdir -p $TARGET_DIR/cloud/{namespace}/{cluster}\n" + - "echo '# GENERATED BY {rulename} -> {gitopsrulename}' > $TARGET_DIR/cloud/{namespace}/{cluster}/{file}\n" + - "{template_engine} --template={infile} --variable=NAMESPACE={namespace} --stamp_info_file={info_file} >> $TARGET_DIR/cloud/{namespace}/{cluster}/{file}\n").format( + statements += ("echo $TARGET_DIR/{gitops_path}/{namespace}/{cluster}/{file}\n" + + "mkdir -p $TARGET_DIR/{gitops_path}/{namespace}/{cluster}\n" + + "echo '# GENERATED BY {rulename} -> {gitopsrulename}' > $TARGET_DIR/{gitops_path}/{namespace}/{cluster}/{file}\n" + + "{template_engine} --template={infile} --variable=NAMESPACE={namespace} --stamp_info_file={info_file} >> $TARGET_DIR/{gitops_path}/{namespace}/{cluster}/{file}\n").format( infile = infile.path, rulename = inattr.label, gitopsrulename = ctx.label, namespace = namespace, + gitops_path = ctx.attr.gitops_path, cluster = cluster, file = _remove_prefixes(infile.path.split("/")[-1], strip_prefixes), template_engine = "${RUNFILES}/%s" % _get_runfile_path(ctx, ctx.executable._template_engine), @@ -483,6 +484,7 @@ gitops = rule( "cluster": attr.string(mandatory = True), "namespace": attr.string(mandatory = True), "deployment_branch": attr.string(), + "gitops_path": attr.string(), "release_branch_prefix": attr.string(), "strip_prefixes": attr.string_list(), "_info_file": attr.label(