<|start_filename|>hack/Makefile<|end_filename|>
# This is a temp directory where we check out the repo.
#
# Note that this makefile does *not* attempt to clean up the temp dirs created
# above. I found some cases where I couldn't remove the files even after the
# container, images and volumes had all been nuked. So please remember to clean
# your /tmp dir from time to time, kids.
PROW_TMP := $(shell mktemp -d)

# The KRTE image to use (see prow-run-e2e.sh for information about why we use krte).
#
# The current version (20210129) includes Go 1.15.7 and kubectl 1.17. UPGRADE
# TO A NEW VERSION WHEN WE STOP SUPPORTING K8s 1.17 as that seems like a
# reasonable time. At that point, I'd just upgrade to the latest image that
# works; we don't have to increment one by one. Honestly I doubt the *exact*
# version matters too much; look at the version in
# https://github.com/kubernetes/test-infra/blob/master/config/jobs/kubernetes-sigs/kind/kind-postsubmits.yaml
# and that's probably good enough for us.
#
# Please keep this in sync with
# https://github.com/kubernetes/test-infra/tree/master/config/jobs/kubernetes-sigs/hierarchical-namespaces/hnc-e2e.yaml.
# Also, when you do this, please also upgrade the version of Kind we download
# in prow-run-e2e.sh in this directory.
PROW_IMG ?= gcr.io/k8s-testimages/krte:v20210129-3799a64-master

# This is for debugging prow-run-e2e.sh; see that script for more information.
#
# The entire repo is cloned and checked out at the master branch, except for
# prow-run-e2e.sh which is copied from this directory.
#
# The '-it' arg is needed to allow you to hit ctrl-c while the tests are still
# running.
prow-test:
	@echo ~~~ Preparing to test prow-run-e2e.sh ~~~
	@echo
	@echo Cloning the repo
	git clone https://github.com/kubernetes-sigs/hierarchical-namespaces ${PROW_TMP}
	@echo
	@echo Copying run-e2e-tests in this directory to the synced directory
	cp -p ./prow-run-e2e.sh ${PROW_TMP}/hack
	@echo
	@echo ~~~ Testing prow-run-e2e.sh in KRTE ~~~
	@echo
	docker run \
		-e DOCKER_IN_DOCKER_ENABLED=true \
		-v /var/run/docker.sock:/var/run/docker.sock \
		-v ${PROW_TMP}:/local-test-start-dir \
		-w /local-test-start-dir \
		--network="host" \
		-it \
		${PROW_IMG} \
		/local-test-start-dir/hack/prow-run-e2e.sh

# After calling 'make prow-test', the Kind cluster might still be present on the
# *host* even though the Docker container has exited. Run this to find and
# delete any Kind cluster starting with 'hnc-postsubmit-'
prow-clean:
	kind get clusters | grep hnc-postsubmit- | xargs kind delete clusters


<|start_filename|>internal/forest/namespacestructure_test.go<|end_filename|>
package forest

import (
	"sort"
	"testing"

	. "github.com/onsi/gomega"
)

func TestSetParentAndAncestorNames(t *testing.T) {
	tests := []struct {
		name  string
		chain []string
	}{
		{name: "no parent", chain: []string{"foo"}},
		{name: "two-level", chain: []string{"foo", "bar"}},
		{name: "cycle", chain: []string{"foo", "bar", "foo"}},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			g := NewWithT(t)
			// Create the chain
			f := NewForest()
			var last *Namespace
			for _, nm := range tc.chain {
				parent := last
				last = f.Get(nm)
				last.SetParent(parent)
			}
			g.Expect(last.AncestryNames()).Should(Equal(tc.chain))
		})
	}
}

func TestCycleNames(t *testing.T) {
	tests := []struct {
		name  string
		chain []string
		want  []string
	}{
		{name: "no parent", chain: []string{"foo"}},
		{name: "two-level", chain: []string{"foo", "bar"}},
		{name: "in cycle", chain: []string{"foo", "bar", "foo"}, want: []string{"bar", "foo", "bar"}}, // rotated so smallest name is first/last
		{name: "below cycle", chain: []string{"foo", "bar", "foo", "baz"}},                            // baz isn't in a cycle itself
		{name: "longer cycle ordered", chain: []string{"a", "c", "z", "a"}, want: []string{"a", "c", "z", "a"}},
		{name: "longer cycle unordered", chain: []string{"c", "z", "a", "c"}, want: []string{"a", "c", "z", "a"}},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			g := NewWithT(t)
			// Create the chain
			f := NewForest()
			var last *Namespace
			for _, nm := range tc.chain {
				parent := last
				last = f.Get(nm)
				last.SetParent(parent)
			}
			g.Expect(last.CycleNames()).Should(Equal(tc.want))
		})
	}
}

func TestDescendantNames(t *testing.T) {
	// Test a tree has the following structure:
	//         a
	//       /  \
	//     /     \
	//    b       c
	//  / | \    /  \
	// x  y z  123 456
	//          |
	//         789
	kinship := map[string][]string{
		"a":   []string{"b", "c"},
		"b":   []string{"x", "y", "z"},
		"c":   []string{"123", "456"},
		"123": []string{"789"},
	}

	// Create the forest
	f := NewForest()
	for parentName, childrenNames := range kinship {
		parent := f.Get(parentName)
		for _, childName := range childrenNames {
			child := f.Get(childName)
			child.SetParent(parent)
		}
	}

	tests := []struct {
		name string
		root string
		want []string
	}{
		{name: "no descendant", root: "456", want: nil},
		{name: "one descendant", root: "123", want: []string{"789"}},
		{name: "one-level descendants", root: "b", want: []string{"x", "y", "z"}},
		{name: "two-level descendants", root: "c", want: []string{"123", "456", "789"}},
		{name: "three-level descendants", root: "a", want: []string{"b", "c", "x", "y", "z", "123", "456", "789"}},
	}

	for _, tc := range tests {
		sort.Strings(tc.want)
		t.Run(tc.name, func(t *testing.T) {
			g := NewWithT(t)
			root := f.Get(tc.root)
			g.Expect(root.DescendantNames()).Should(Equal(tc.want))
		})
	}
}


<|start_filename|>internal/logutils/log.go<|end_filename|>
/*

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package logutils

import (
	"sync/atomic"

	"github.com/go-logr/logr"
)

// reconcileID is used purely to set the "rid" field in the log, so we can tell which log messages
// were part of the same reconciliation attempt, even if multiple are running parallel (or it's
// simply hard to tell when one ends and another begins).
//
// The ID is shared among all reconcilers so that each log message gets a unique ID across all of
// HNC.
var nextReconcileID int64

// WithRID  adds a reconcile ID (rid) to the given logger.
func WithRID(log logr.Logger) logr.Logger {
	rid := atomic.AddInt64(&nextReconcileID, 1)
	return log.WithValues("rid", rid)
}


<|start_filename|>internal/kubectl/set.go<|end_filename|>
/*

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubectl

import (
	"fmt"
	"os"
	"strings"

	"github.com/spf13/cobra"

	api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
)

//hcUpdates struct stores name of namespaces against type of flag passed
type hcUpdates struct {
	root     bool
	parent   string
	allowCD  bool
	forbidCD bool
}

var setCmd = &cobra.Command{
	Use:   "set NAMESPACE",
	Short: "Sets hierarchical properties of the given namespace",
	Example: `	# Make 'foo' the parent of 'bar'
	kubectl hns set bar --parent foo
	kubectl hns set bar -p foo

	# Make 'foo' a root (remove 'bar' as its parent)
	kubectl hns set bar --root
	kubectl hns set bar -r

	# Not allowed: give 'bar' a parent and make it a root at the same time
	kubectl hns set bar --root --parent foo # error

	# Allow 'foo', or any of its descendants, to be cascading deleted
	kubectl hns set foo --allowCascadingDeletion
	kubectl hns set foo -a

	# Forbids cascading deletion on 'foo' and its subtree (unless specifically
	# allowed on any descendants).
	kubectl hns set foo --forbidCascadingDeletion
	kubectl hns set foo -f`,
	Args: cobra.ExactArgs(1),
	Run: func(cmd *cobra.Command, args []string) {
		nnm := args[0]
		flags := cmd.Flags()
		parent, _ := flags.GetString("parent")
		allowCD, _ := flags.GetBool("allowCascadingDeletion")
		forbidCD, _ := flags.GetBool("forbidCascadingDeletion")

		updates := hcUpdates{
			root:     flags.Changed("root"),
			parent:   parent,
			allowCD:  allowCD,
			forbidCD: forbidCD,
		}

		updateHC(client, updates, nnm)
	},
}

func updateHC(cl Client, updates hcUpdates, nnm string) {
	hc := cl.getHierarchy(nnm)
	oldpnm := hc.Spec.Parent
	numChanges := 0

	if updates.root && updates.parent != "" {
		fmt.Println("Cannot give the namespace a parent and make it a root at the same time")
		os.Exit(1)
	}

	if updates.root {
		setRoot(hc, oldpnm, nnm, &numChanges)
	}

	if updates.parent != "" {
		setParent(hc, oldpnm, updates.parent, nnm, &numChanges)
	}

	setAllowCascadingDeletion(hc, nnm, updates.allowCD, updates.forbidCD, &numChanges)

	if numChanges > 0 {
		cl.updateHierarchy(hc, fmt.Sprintf("update the hierarchical configuration of %s", nnm))
		word := "property"
		if numChanges > 1 {
			word = "properties"
		}
		fmt.Printf("Succesfully updated %d %s of the hierarchical configuration of %s\n", numChanges, word, nnm)
	} else {
		fmt.Printf("No changes made\n")
	}
}

func setRoot(hc *api.HierarchyConfiguration, oldpnm, nnm string, numChanges *int) {
	if oldpnm == "" {
		fmt.Printf("%s is already a root namespace; unchanged \n", nnm)
	} else {
		hc.Spec.Parent = ""
		fmt.Printf("Unsetting the parent of %s (was previously %s)\n", nnm, oldpnm)
		*numChanges++
	}
}

func setParent(hc *api.HierarchyConfiguration, oldpnm, pnm, nnm string, numChanges *int) {
	if oldpnm == pnm {
		fmt.Printf("Parent of %s is already %s; unchanged\n", nnm, pnm)
	} else {
		hc.Spec.Parent = pnm
		if oldpnm == "" {
			fmt.Printf("Setting the parent of %s to %s\n", nnm, pnm)
		} else {
			fmt.Printf("Changing the parent of %s from %s to %s\n", nnm, oldpnm, pnm)
		}
		*numChanges++
	}
}

func setAllowCascadingDeletion(hc *api.HierarchyConfiguration, nnm string, allow, forbid bool, numChanges *int) {
	if allow && forbid {
		fmt.Printf("Cannot set both --allowCascadingDeletion and --forbidCascadingDeletion\n")
		os.Exit(1)
	}

	if !allow && !forbid {
		// nothing specified
		return
	}

	// We now know that allow != forbid, so we can just look at allow
	if hc.Spec.AllowCascadingDeletion == allow {
		fmt.Printf("Cascading deletion for '%s' is already set to %t; unchanged\n", nnm, allow)
	} else {
		hc.Spec.AllowCascadingDeletion = allow
		if allow {
			fmt.Printf("Allowing cascading deletion on '%s'\n", nnm)
		} else {
			fmt.Printf("Forbidding cascading deletion on '%s'\n", nnm)
		}
		*numChanges++
	}
}

func normalizeStringArray(in []string) []string {
	out := []string{}
	for _, val := range in {
		for _, s := range strings.Split(val, ",") {
			out = append(out, s)
		}
	}
	return out
}

func newSetCmd() *cobra.Command {
	setCmd.Flags().BoolP("root", "r", false, "Removes the current parent namespace, making this namespace a root")
	setCmd.Flags().StringP("parent", "p", "", "Sets the parent namespace")
	setCmd.Flags().BoolP("allowCascadingDeletion", "a", false, "Allows cascading deletion of its subnamespaces.")
	setCmd.Flags().BoolP("forbidCascadingDeletion", "f", false, "Protects cascading deletion of its subnamespaces.")
	return setCmd
}


<|start_filename|>tools/ans2hns/Dockerfile<|end_filename|>
FROM golang:1.15
ENV CGO_ENABLED=0
WORKDIR /go/src/
COPY . .
RUN go build -v -o /usr/local/bin/function ./

FROM gcr.io/distroless/static:nonroot
COPY --from=0 /usr/local/bin/function /usr/local/bin/function
USER nonroot:nonroot
CMD ["function"]


<|start_filename|>internal/stats/counter.go<|end_filename|>
package stats

import "sync/atomic"

type counter int32

func (c *counter) incr() {
	i := int32(*c)
	atomic.AddInt32(&i, 1)
	*c = counter(i)
}

func (c *counter) decr() {
	i := int32(*c)
	atomic.AddInt32(&i, -1)
	*c = counter(i)
}


<|start_filename|>internal/metadata/metav1.go<|end_filename|>
package metadata

import (
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)

func GetLabel(inst metav1.Object, label string) (string, bool) {
	labels := inst.GetLabels()
	if labels == nil {
		return "", false
	}
	value, ok := labels[label]
	return value, ok
}

func SetLabel(inst metav1.Object, label string, value string) {
	labels := inst.GetLabels()
	if labels == nil {
		labels = map[string]string{}
	}
	labels[label] = value
	inst.SetLabels(labels)
}

func SetAnnotation(inst metav1.Object, annotation string, value string) {
	annotations := inst.GetAnnotations()
	if annotations == nil {
		annotations = map[string]string{}
	}
	annotations[annotation] = value
	inst.SetAnnotations(annotations)
}


<|start_filename|>vendor/google.golang.org/genproto/googleapis/monitoring/v3/query_service.pb.go<|end_filename|>
// Copyright 2021 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// Code generated by protoc-gen-go. DO NOT EDIT.
// versions:
// 	protoc-gen-go v1.26.0
// 	protoc        v3.12.2
// source: google/monitoring/v3/query_service.proto

package monitoring

import (
	context "context"
	reflect "reflect"

	_ "google.golang.org/genproto/googleapis/api/annotations"
	_ "google.golang.org/genproto/googleapis/api/label"
	grpc "google.golang.org/grpc"
	codes "google.golang.org/grpc/codes"
	status "google.golang.org/grpc/status"
	protoreflect "google.golang.org/protobuf/reflect/protoreflect"
	protoimpl "google.golang.org/protobuf/runtime/protoimpl"
)

const (
	// Verify that this generated code is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
	// Verify that runtime/protoimpl is sufficiently up-to-date.
	_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)

var File_google_monitoring_v3_query_service_proto protoreflect.FileDescriptor

var file_google_monitoring_v3_query_service_proto_rawDesc = []byte{
	0x0a, 0x28, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72,
	0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x71, 0x75, 0x65, 0x72, 0x79, 0x5f, 0x73, 0x65, 0x72,
	0x76, 0x69, 0x63, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x14, 0x67, 0x6f, 0x6f, 0x67,
	0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33,
	0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e,
	0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x16,
	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x6c, 0x61, 0x62, 0x65, 0x6c,
	0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x21, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x6d,
	0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f, 0x6d, 0x65, 0x74,
	0x72, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x29, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
	0x65, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2f, 0x76, 0x33, 0x2f,
	0x6d, 0x65, 0x74, 0x72, 0x69, 0x63, 0x5f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x70,
	0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x61, 0x70, 0x69,
	0x2f, 0x63, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x32, 0xde, 0x02,
	0x0a, 0x0c, 0x51, 0x75, 0x65, 0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0xa1,
	0x01, 0x0a, 0x0f, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69,
	0x65, 0x73, 0x12, 0x2c, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69,
	0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54,
	0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
	0x1a, 0x2d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f,
	0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x54, 0x69, 0x6d,
	0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22,
	0x31, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x2b, 0x22, 0x26, 0x2f, 0x76, 0x33, 0x2f, 0x7b, 0x6e, 0x61,
	0x6d, 0x65, 0x3d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x73, 0x2f, 0x2a, 0x7d, 0x2f, 0x74,
	0x69, 0x6d, 0x65, 0x53, 0x65, 0x72, 0x69, 0x65, 0x73, 0x3a, 0x71, 0x75, 0x65, 0x72, 0x79, 0x3a,
	0x01, 0x2a, 0x1a, 0xa9, 0x01, 0xca, 0x41, 0x19, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
	0x6e, 0x67, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f,
	0x6d, 0xd2, 0x41, 0x89, 0x01, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
	0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
	0x61, 0x75, 0x74, 0x68, 0x2f, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x70, 0x6c, 0x61, 0x74, 0x66,
	0x6f, 0x72, 0x6d, 0x2c, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e,
	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61,
	0x75, 0x74, 0x68, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2c, 0x68,
	0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
	0x65, 0x61, 0x70, 0x69, 0x73, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x61, 0x75, 0x74, 0x68, 0x2f, 0x6d,
	0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x72, 0x65, 0x61, 0x64, 0x42, 0xc9,
	0x01, 0x0a, 0x18, 0x63, 0x6f, 0x6d, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x6d, 0x6f,
	0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x76, 0x33, 0x42, 0x11, 0x51, 0x75, 0x65,
	0x72, 0x79, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01,
	0x5a, 0x3e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x67, 0x6f, 0x6c, 0x61, 0x6e, 0x67, 0x2e,
	0x6f, 0x72, 0x67, 0x2f, 0x67, 0x65, 0x6e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x6f, 0x6f,
	0x67, 0x6c, 0x65, 0x61, 0x70, 0x69, 0x73, 0x2f, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69,
	0x6e, 0x67, 0x2f, 0x76, 0x33, 0x3b, 0x6d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67,
	0xaa, 0x02, 0x1a, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x2e,
	0x4d, 0x6f, 0x6e, 0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x2e, 0x56, 0x33, 0xca, 0x02, 0x1a,
	0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5c, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x5c, 0x4d, 0x6f, 0x6e,
	0x69, 0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x5c, 0x56, 0x33, 0xea, 0x02, 0x1d, 0x47, 0x6f, 0x6f,
	0x67, 0x6c, 0x65, 0x3a, 0x3a, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x3a, 0x3a, 0x4d, 0x6f, 0x6e, 0x69,
	0x74, 0x6f, 0x72, 0x69, 0x6e, 0x67, 0x3a, 0x3a, 0x56, 0x33, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
	0x6f, 0x33,
}

var file_google_monitoring_v3_query_service_proto_goTypes = []interface{}{
	(*QueryTimeSeriesRequest)(nil),  // 0: google.monitoring.v3.QueryTimeSeriesRequest
	(*QueryTimeSeriesResponse)(nil), // 1: google.monitoring.v3.QueryTimeSeriesResponse
}
var file_google_monitoring_v3_query_service_proto_depIdxs = []int32{
	0, // 0: google.monitoring.v3.QueryService.QueryTimeSeries:input_type -> google.monitoring.v3.QueryTimeSeriesRequest
	1, // 1: google.monitoring.v3.QueryService.QueryTimeSeries:output_type -> google.monitoring.v3.QueryTimeSeriesResponse
	1, // [1:2] is the sub-list for method output_type
	0, // [0:1] is the sub-list for method input_type
	0, // [0:0] is the sub-list for extension type_name
	0, // [0:0] is the sub-list for extension extendee
	0, // [0:0] is the sub-list for field type_name
}

func init() { file_google_monitoring_v3_query_service_proto_init() }
func file_google_monitoring_v3_query_service_proto_init() {
	if File_google_monitoring_v3_query_service_proto != nil {
		return
	}
	file_google_monitoring_v3_metric_proto_init()
	file_google_monitoring_v3_metric_service_proto_init()
	type x struct{}
	out := protoimpl.TypeBuilder{
		File: protoimpl.DescBuilder{
			GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
			RawDescriptor: file_google_monitoring_v3_query_service_proto_rawDesc,
			NumEnums:      0,
			NumMessages:   0,
			NumExtensions: 0,
			NumServices:   1,
		},
		GoTypes:           file_google_monitoring_v3_query_service_proto_goTypes,
		DependencyIndexes: file_google_monitoring_v3_query_service_proto_depIdxs,
	}.Build()
	File_google_monitoring_v3_query_service_proto = out.File
	file_google_monitoring_v3_query_service_proto_rawDesc = nil
	file_google_monitoring_v3_query_service_proto_goTypes = nil
	file_google_monitoring_v3_query_service_proto_depIdxs = nil
}

// Reference imports to suppress errors if they are not otherwise used.
var _ context.Context
var _ grpc.ClientConnInterface

// This is a compile-time assertion to ensure that this generated file
// is compatible with the grpc package it is being compiled against.
const _ = grpc.SupportPackageIsVersion6

// QueryServiceClient is the client API for QueryService service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.
type QueryServiceClient interface {
	// Queries time series using Monitoring Query Language. This method does not require a Workspace.
	QueryTimeSeries(ctx context.Context, in *QueryTimeSeriesRequest, opts ...grpc.CallOption) (*QueryTimeSeriesResponse, error)
}

type queryServiceClient struct {
	cc grpc.ClientConnInterface
}

func NewQueryServiceClient(cc grpc.ClientConnInterface) QueryServiceClient {
	return &queryServiceClient{cc}
}

func (c *queryServiceClient) QueryTimeSeries(ctx context.Context, in *QueryTimeSeriesRequest, opts ...grpc.CallOption) (*QueryTimeSeriesResponse, error) {
	out := new(QueryTimeSeriesResponse)
	err := c.cc.Invoke(ctx, "/google.monitoring.v3.QueryService/QueryTimeSeries", in, out, opts...)
	if err != nil {
		return nil, err
	}
	return out, nil
}

// QueryServiceServer is the server API for QueryService service.
type QueryServiceServer interface {
	// Queries time series using Monitoring Query Language. This method does not require a Workspace.
	QueryTimeSeries(context.Context, *QueryTimeSeriesRequest) (*QueryTimeSeriesResponse, error)
}

// UnimplementedQueryServiceServer can be embedded to have forward compatible implementations.
type UnimplementedQueryServiceServer struct {
}

func (*UnimplementedQueryServiceServer) QueryTimeSeries(context.Context, *QueryTimeSeriesRequest) (*QueryTimeSeriesResponse, error) {
	return nil, status.Errorf(codes.Unimplemented, "method QueryTimeSeries not implemented")
}

func RegisterQueryServiceServer(s *grpc.Server, srv QueryServiceServer) {
	s.RegisterService(&_QueryService_serviceDesc, srv)
}

func _QueryService_QueryTimeSeries_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
	in := new(QueryTimeSeriesRequest)
	if err := dec(in); err != nil {
		return nil, err
	}
	if interceptor == nil {
		return srv.(QueryServiceServer).QueryTimeSeries(ctx, in)
	}
	info := &grpc.UnaryServerInfo{
		Server:     srv,
		FullMethod: "/google.monitoring.v3.QueryService/QueryTimeSeries",
	}
	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
		return srv.(QueryServiceServer).QueryTimeSeries(ctx, req.(*QueryTimeSeriesRequest))
	}
	return interceptor(ctx, in, info, handler)
}

var _QueryService_serviceDesc = grpc.ServiceDesc{
	ServiceName: "google.monitoring.v3.QueryService",
	HandlerType: (*QueryServiceServer)(nil),
	Methods: []grpc.MethodDesc{
		{
			MethodName: "QueryTimeSeries",
			Handler:    _QueryService_QueryTimeSeries_Handler,
		},
	},
	Streams:  []grpc.StreamDesc{},
	Metadata: "google/monitoring/v3/query_service.proto",
}


<|start_filename|>internal/forest/namespaceobjects.go<|end_filename|>
package forest

import (
	"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
	"k8s.io/apimachinery/pkg/runtime/schema"
)

// SetSourceObject updates or creates the source object in forest.namespace.
func (ns *Namespace) SetSourceObject(obj *unstructured.Unstructured) {
	gvk := obj.GroupVersionKind()
	name := obj.GetName()
	_, ok := ns.sourceObjects[gvk]
	if !ok {
		ns.sourceObjects[gvk] = map[string]*unstructured.Unstructured{}
	}
	ns.sourceObjects[gvk][name] = obj
}

// GetSourceObject gets a source object by name. If it doesn't exist, return nil.
func (ns *Namespace) GetSourceObject(gvk schema.GroupVersionKind, nm string) *unstructured.Unstructured {
	return ns.sourceObjects[gvk][nm]
}

// HasSourceObject returns if the namespace has a source object.
func (ns *Namespace) HasSourceObject(gvk schema.GroupVersionKind, oo string) bool {
	return ns.GetSourceObject(gvk, oo) != nil
}

// DeleteSourceObject deletes a source object by name.
func (ns *Namespace) DeleteSourceObject(gvk schema.GroupVersionKind, nm string) {
	delete(ns.sourceObjects[gvk], nm)
	// Garbage collection
	if len(ns.sourceObjects[gvk]) == 0 {
		delete(ns.sourceObjects, gvk)
	}
}

// GetSourceObjects returns all source objects in the namespace.
func (ns *Namespace) GetSourceObjects(gvk schema.GroupVersionKind) []*unstructured.Unstructured {
	o := []*unstructured.Unstructured{}
	for _, obj := range ns.sourceObjects[gvk] {
		o = append(o, obj)
	}
	return o
}

// GetNumSourceObjects returns the total number of source objects of a specific
// GVK in the namespace.
func (ns *Namespace) GetNumSourceObjects(gvk schema.GroupVersionKind) int {
	return len(ns.sourceObjects[gvk])
}

// GetAncestorSourceObjects returns all source objects with the specified name
// in the ancestors (including itself) from top down. If the name is not
// specified, all the source objects in the ancestors will be returned.
func (ns *Namespace) GetAncestorSourceObjects(gvk schema.GroupVersionKind, name string) []*unstructured.Unstructured {
	// The namespace could be nil when we use this function on "ns.Parent()" to
	// get the source objects of the ancestors excluding itself without caring if
	// the "ns.Parent()" is nil.
	if ns == nil {
		return nil
	}

	// Get the source objects in the ancestors from top down.
	objs := []*unstructured.Unstructured{}
	ans := ns.AncestryNames()
	for _, n := range ans {
		nsObjs := ns.forest.Get(n).GetSourceObjects(gvk)
		if name == "" {
			// Get all the source objects if the name is not specified.
			objs = append(objs, ns.forest.Get(n).GetSourceObjects(gvk)...)
		} else {
			// If a name is specified, return the matching objects.
			for _, o := range nsObjs {
				if o.GetName() == name {
					objs = append(objs, o)
				}
			}
		}
	}

	return objs
}


<|start_filename|>internal/config/namespace_test.go<|end_filename|>
package config

import (
	. "github.com/onsi/gomega"
	"testing"
)

func TestIsNamespaceIncluded(t *testing.T) {

	tests := []struct {
		name     string
		regex    string
		excluded []string
		expect   bool
	}{
		{name: "foobar", regex: "foo.*", excluded: []string{"bar"}, expect: true},
		{name: "bar", regex: "foo-.*", excluded: []string{"bar"}, expect: false},
		{name: "bar", regex: ".*", excluded: []string{"bar"}, expect: false},
		{name: "foo", regex: ".*", excluded: []string{"bar"}, expect: true},
		{name: "foo", regex: ".*", excluded: []string{"bar", "foo"}, expect: false},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			g := NewWithT(t)

			// Test
			SetNamespaces(tc.regex, tc.excluded...)
			got := IsManagedNamespace(tc.name)

			// Report
			g.Expect(got).Should(Equal(tc.expect))
		})
	}

}


<|start_filename|>tools/ans2hns/main.go<|end_filename|>
// See README.md for more information
package main

import (
	"fmt"
	"os"
	"strings"

	"sigs.k8s.io/kustomize/kyaml/fn/framework"
	"sigs.k8s.io/kustomize/kyaml/yaml"
)

// nsInfo defines all the information we need to know about a namespace
type nsInfo struct{
	parent string
	hasConfig bool
}

// forestType is the type of the forest: a map of namespace names -> nsInfo
type forestType map[string]*nsInfo

var (
	// forest is the hierarchical structure of all namespaces found in a structured Git repo, when run
	// in the "namespaces" directory.
	forest forestType

	// resourceList is populated by the call to framework.Command() in main() and includes all K8s
	// objects found in the directory.
	resourceList *framework.ResourceList
)

func main() {
	// Set up variables
	resourceList = &framework.ResourceList{}
	forest = forestType{}

	// Define and execute the only command
	cmd := framework.Command(resourceList, process)
	if err := cmd.Execute(); err != nil {
		fmt.Fprintf(os.Stderr, "Error: %s\n", err)
		os.Exit(1)
	}
}

// process reads all K8s objects, corrects them as necessary, and generates/fixes any necessary
// HierarchyConfiguration objects.
func process() error {
	if err := processItems(); err != nil {
		return err
	}

	if err := addConfigs(); err != nil {
		return err
	}

	return nil
}

// processItems reads each item, infers the desired hierarchy, and corrects any existing objects.
func processItems() error {
	for i, item := range resourceList.Items {
		// Get basic information about the object
		meta, err := item.GetMeta()
		if err != nil {
			return fmt.Errorf("cannot get meta for item %d: %w", i, err)
		}

		// path is the *file* path, which kpt adds into the object as a well-known annotation. From this
		// file path, we infer the hierarchy by looking at the path segments.
		path := meta.Annotations["config.kubernetes.io/path"]
		nnms, err := getNamespaces(path)
		if err != nil {
			return err
		}
		if nnms == nil {
			continue
		}
		fmt.Fprintf(os.Stderr, "Processing %s...\n", path)

		// Update the inferred hierarchy
		if err := updateForest(nnms); err != nil {
			return fmt.Errorf("while inferring hierarchy from %q: %w", path, err)
		}

		if err := setNamespace(nnms, item, meta); err != nil {
			return fmt.Errorf("cannot set namespace for %s: %w", path, err)
		}

		// If this is a hierarchy config, make sure it's correct
		if err := processConfig(item, meta); err != nil {
			return fmt.Errorf("cannot update hierarchy config %s: %w", path, err)
		}
	}
	return nil
}

// getNamespaces takes the path and returns the namespace hierarchy, with the first element being
// the root namespaces and the last element being the leaf. If it returns an empty list, that means
// that this object is not in the `namespaces/` directory and should be ignored.
func getNamespaces(path string) ([]string, error) {
	segs := strings.Split(path, "/")

	// We only care about objects in the 'namespaces' directory.
	if segs[0] != "namespaces" {
		return nil, nil
	}

	// There shouldn't be any objects directly in the namespaces directory.
	if len(segs) < 3 {
		return nil, fmt.Errorf("file %q is directly under 'namespaces/' but should be in a namespace directory", path)
	}

	// After stripping off the 'namespaces/' and the filename, what remains is the list of namespaces
	// from root to leaf.
	return segs[1:len(segs)-1], nil
}

// updateForest updates the inferred forest based on the directory components in the item's
// filename.
func updateForest(nnms []string) error {
	pnm := "" // The root has no parent
	for _, nnm := range nnms {
		// Update our forest with the inferred hierarchy
		if ns, exists := forest[nnm]; exists {
			if ns.parent != pnm {
				return fmt.Errorf("namespace %q has conflicting parents: %q and %q\n", nnm, ns.parent, pnm)
			}
		} else {
			ns = &nsInfo{}
			ns.parent = pnm
			forest[nnm] = ns
		}

		// Update the parent for the next iteration
		pnm = nnm
	}
	return nil
}

// setNamespace updates the object with its namespace, unless the object *is* the namespace.
func setNamespace(nnms []string, item *yaml.RNode, meta yaml.ResourceMeta) error {
	// The namespace to set is the leaf namespace (the last element of the namespaces slice)
	nnm := nnms[len(nnms)-1]

	if meta.APIVersion == "v1" && meta.Kind == "Namespace" {
		// don't set the namespace field on the namespace object. However, do validate that the names
		// match!
		if meta.Name != nnm {
			return fmt.Errorf("namespace directory %q contains namespace config for %q", nnm, meta.Name)
		}
		return nil
	}

	return item.PipeE(yaml.SetK8sNamespace(nnm))
}

// processConfig marks the config as existing and corrects its .spec.parent field if it's wrong. It
// ignores the object if it's not a HierarchyConfiguration.
func processConfig(item *yaml.RNode, meta yaml.ResourceMeta) error {
	if meta.APIVersion != "hnc.x-k8s.io/v1alpha2" || meta.Kind != "HierarchyConfiguration" {
		return nil
	}
	ns := forest[meta.Namespace]
	ns.hasConfig = true

	spec, err := item.Pipe(yaml.Get("spec"))
	if err != nil {
		return fmt.Errorf("couldn't get spec: %w", err)
	}
	parent, err := spec.Pipe(yaml.Get("parent"))
	if err != nil {
		return fmt.Errorf("couldn't get spec.parent: %w", err)
	}

	oldParent := strings.TrimSpace(parent.MustString())
	if oldParent != ns.parent {
		fmt.Fprintf(os.Stderr, "HC config for %q has the wrong parent %q; updating to %q\n", meta.Namespace, oldParent, ns.parent)
		if err := spec.PipeE(yaml.SetField("parent", yaml.MustParse(ns.parent))); err != nil {
			return fmt.Errorf("couldn't update HC config: %s\n", err)
		}
	}
	return nil
}

// addConfigs looks through the forest for missing HierarchyConfigurations and adds any if they're
// missing.
func addConfigs() error {
	const template = `apiVersion: hnc.x-k8s.io/v1alpha2
kind: HierarchyConfiguration
metadata:
  name: hierarchy
  namespace: %s
  annotations:
    config.kubernetes.io/path: %s
spec:
  parent: %s`

	for nm, ns := range forest {
		if ns.hasConfig || ns.parent == ""{
			// Don't generate configs if one already exists or for roots
			continue
		}

		// Build the filepath for this new yaml object based on its hierarchical path
		path := nm + "/hierarchyconfiguration.yaml"
		pnm := ns.parent
		for pnm != "" {
			path = pnm + "/" + path
			pnm = forest[pnm].parent
		}
		path = "namespaces/" + path

		// Generate the config from the template
		config := fmt.Sprintf(template, nm, path, ns.parent)
		n, err := yaml.Parse(config)
		if err != nil {
			fmt.Fprintf(os.Stderr, "HC config was:\n%s\n", config)
			return fmt.Errorf("couldn't generate hierarchy config for %q: %s\n", nm, err)
		}
		fmt.Fprintf(os.Stderr, "Generating %q\n", path)
		resourceList.Items = append(resourceList.Items, n)
	}

	return nil
}


<|start_filename|>internal/crd/crd.go<|end_filename|>
// Package CRD has utilities relating to CRDs.
package crd

import (
	"context"
	"fmt"

	apiextensions "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
	apierrors "k8s.io/apimachinery/pkg/api/errors"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/client"
	"sigs.k8s.io/controller-runtime/pkg/client/config"

	api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
)

// fakeDeleteCRDClient is a fake client used for testing only
type fakeDeleteCRDClient struct{}

// fakeDeleteCRDClient doesn't return any err on Get() because none of the reconciler test performs CRD deletion
func (f fakeDeleteCRDClient) Get(context.Context, types.NamespacedName, client.Object) error {
	return nil
}

// crdClientType could be either a real client or fakeDeleteCRDClient
type crdClientType interface {
	Get(context.Context, types.NamespacedName, client.Object) error
}

// crdClient is an uncached client for checking CRD deletion (or a fake for testing)
var crdClient crdClientType

// Setup decides whether to use the fake client
func Setup(mgr ctrl.Manager, fake bool) error {
	if fake {
		crdClient = fakeDeleteCRDClient{}
		return nil
	}

	//TODO(aludwin): can we just use mgr.GetClient()? If not, document why not
	var err error
	crdClient, err = client.New(config.GetConfigOrDie(), client.Options{
		Scheme: mgr.GetScheme(),
		// I'm not sure if this mapper is needed - @ginnyji Dec2020
		Mapper: mgr.GetRESTMapper(),
	})
	if err != nil {
		return fmt.Errorf("cannot create crdClient: %s", err.Error())
	}

	return nil
}

// IsDeletingCRD returns true if the specified HNC CRD is being or has been deleted. The argument
// expected is the CRD name minus the HNC suffix, e.g. "hierarchyconfigurations".
func IsDeletingCRD(ctx context.Context, nm string) (bool, error) {
	crd := &apiextensions.CustomResourceDefinition{}
	nsn := types.NamespacedName{Name: nm + "." + api.MetaGroup}
	if err := crdClient.Get(ctx, nsn, crd); err != nil {
		if apierrors.IsNotFound(err) {
			return true, nil
		}
		return false, err
	}
	return !crd.DeletionTimestamp.IsZero(), nil
}


<|start_filename|>internal/kubectl/configdelete.go<|end_filename|>
/*

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubectl

import (
	"fmt"

	"github.com/spf13/cobra"

	api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
)

var configDeleteCmd = &cobra.Command{
	Use:   "delete-type --group X --resource Y",
	Short: "Delete the HNC configuration of a specific type",
	Example: fmt.Sprintf("  # Delete configuration of a core type\n" +
		"  kubectl hns config delete-type --resource secrets\n\n" +
		"  # Delete configuration of a custom type\n" +
		"  kubectl hns config delete-type --group stable.example.com --resource crontabs"),
	Run: func(cmd *cobra.Command, args []string) {
		flags := cmd.Flags()
		group, _ := flags.GetString("group")
		resource, _ := flags.GetString("resource")
		config := client.getHNCConfig()

		var newRscs []api.ResourceSpec
		exist := false
		for _, r := range config.Spec.Resources {
			if r.Group == group && r.Resource == resource {
				exist = true
			} else {
				newRscs = append(newRscs, r)
			}
		}
		if !exist {
			fmt.Printf("Nothing to delete; No configuration for type with group: %s, "+
				"resource: %s\n", group, resource)
			return
		}
		config.Spec.Resources = newRscs
		client.updateHNCConfig(config)
		fmt.Printf("Configuration for type with group: %s, resource: %s is deleted\n", group, resource)
	},
}

func newConfigDeleteCmd() *cobra.Command {
	configDeleteCmd.Flags().String("group", "", "group of the resource")
	configDeleteCmd.Flags().String("resource", "", "resource to be configured")
	return configDeleteCmd
}


<|start_filename|>internal/forest/namespacestructure.go<|end_filename|>
package forest

import (
	"fmt"
	"sort"
	"strings"
)

// ChildNames returns a sorted list of names or nil if there are no children.
func (ns *Namespace) ChildNames() []string {
	if len(ns.children) == 0 {
		return nil
	}
	nms := []string{}
	for k := range ns.children {
		nms = append(nms, k)
	}
	sort.Strings(nms)
	return nms
}

// IsAncestor is *not* cycle-safe, so should only be called from namespace trees that are known not
// to have cycles.
func (ns *Namespace) IsAncestor(other *Namespace) bool {
	if ns.parent == other {
		return true
	}
	if ns.parent == nil {
		return false
	}
	return ns.parent.IsAncestor(other)
}

// SetParent modifies the namespace's parent, including updating the list of children. It may result
// in a cycle being created; this can be prevented by calling CanSetParent before, or seeing if it
// happened by calling CycleNames afterwards.
func (ns *Namespace) SetParent(p *Namespace) {
	// Remove old parent and cleans it up.
	if ns.parent != nil {
		delete(ns.parent.children, ns.name)
		if len(ns.parent.children) == 0 {
			ns.parent.clean()
		}
	}

	// Update new parent.
	ns.parent = p
	if p != nil {
		p.children[ns.name] = ns
	}
}

// CanSetParent returns the empty string if the assignment is currently legal, or a non-empty string
// indicating the reason if it cannot be done.
func (ns *Namespace) CanSetParent(p *Namespace) string {
	if p == nil {
		return ""
	}

	// Simple case
	if p == ns {
		return fmt.Sprintf("%q cannot be set as its own parent", p.name)
	}

	// Check for cycles; see if the current namespace (the proposed child) is already an ancestor of
	// the proposed parent. Start at the end of the ancestry (e.g. at the proposed parent) and work
	// our way up to the root.
	ancestors := p.AncestryNames()
	cycle := []string{}
	found := false
	for i := len(ancestors) - 1; !found && i >= 0; i-- {
		cycle = append(cycle, ancestors[i])
		found = (ancestors[i] == ns.name)
	}
	if found {
		return fmt.Sprintf("cycle when making %q the parent of %q: current ancestry is %s",
			p.name, ns.name, strings.Join(cycle, " -> "))
	}

	return ""
}

// RelativesNames returns the children and parent.
func (ns *Namespace) RelativesNames() []string {
	a := []string{}
	if ns.parent != nil {
		a = append(a, ns.parent.name)
	}
	for k := range ns.children {
		a = append(a, k)
	}

	return a
}

// AncestryNames returns all ancestors of this namespace. The namespace itself is the last element
// of the returned slice, with the root at the beginning of the list.
//
// This method is cycle-safe, and can be used to detect and recover from cycles. If there's a cycle,
// the first ancestor that's a member of the cycle we encounter is repeated at the beginning of the
// list.
func (ns *Namespace) AncestryNames() []string {
	if ns == nil {
		return nil
	}

	cycleCheck := map[string]bool{ns.name: true}
	ancestors := []string{ns.name}
	anc := ns.parent
	for anc != nil {
		ancestors = append([]string{anc.name}, ancestors...)
		if cycleCheck[anc.name] {
			return ancestors
		}
		cycleCheck[anc.name] = true
		anc = anc.parent
	}

	return ancestors
}

// CycleNames returns nil if the namespace is not in a cycle, or a list of names in the cycle if
// it is. All namespaces in the cycle return the same list, which is the same as calling
// ns.AncestryNames() on the namespaces with the lexicographically smallest name.
func (ns *Namespace) CycleNames() []string {
	// If this namespaces is *in* a cycle, it will be the first repeated element encountered by
	// AncestryNames(), and therefore will be both the first and the last element.
	ancestors := ns.AncestryNames()
	if len(ancestors) == 1 || ancestors[0] != ns.name {
		return nil
	}
	ancestors = ancestors[1:] // don't need the repeated element

	// Find the smallest name and where it is
	sidx := 0
	snm := ancestors[0]
	for idx, nm := range ancestors {
		if nm < snm {
			sidx = idx
			snm = nm
		}
	}

	// Rotate the slice, and then duplicate the smallest element
	ancestors = append(ancestors[sidx:], ancestors[:sidx]...)
	return append(ancestors, snm)
}

// DescendantNames returns a slice of strings like ["achild", "agrandchild", "bchild", ...] of names
// of all namespaces in its subtree, or nil if the namespace has no descendents. The names are
// returned in alphabetical order (as defined by `sort.Strings()`), *not* depth-first,
// breadth-first, etc.
//
// This method is cycle-safe. If there are cycles, each namespace is only listed once.
func (ns *Namespace) DescendantNames() []string {
	ds := map[string]bool{}
	ns.populateDescendants(ds)
	if len(ds) == 0 {
		return nil
	}
	d := []string{}
	for k, _ := range ds {
		d = append(d, k)
	}
	sort.Strings(d)
	return d
}

// populateDescendants is a cycle-safe way of finding all descendants of a namespace. If any
// namespace turns out to be its own descendant, it's skipped on subsequent encounters.
func (ns *Namespace) populateDescendants(d map[string]bool) {
	for _, c := range ns.ChildNames() {
		if d[c] {
			continue
		}
		d[c] = true
		cns := ns.forest.Get(c)
		cns.populateDescendants(d)
	}
}

// FullDescendantNames returns a sorted list of descendant namespaces that are full namespaces.
func (ns *Namespace) FullDescendantNames() []string {
	fd := []string{}
	for _, dnm := range ns.DescendantNames() {
		if !ns.forest.Get(dnm).IsSub {
			fd = append(fd, dnm)
		}
	}
	if len(fd) == 0 {
		return nil
	}
	sort.Strings(fd)
	return fd
}


<|start_filename|>internal/namespace/mutator_test.go<|end_filename|>
package namespaces

import (
	"testing"

	. "github.com/onsi/gomega"
	corev1 "k8s.io/api/core/v1"
	"sigs.k8s.io/controller-runtime/pkg/log/zap"

	api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
	"sigs.k8s.io/hierarchical-namespaces/internal/config"
)

func TestMutateNamespaceIncludedLabel(t *testing.T) {
	m := &Mutator{}
	l := zap.New()
	config.SetNamespaces("", "excluded")

	tests := []struct {
		name       string
		nsn        string
		lval       string
		expectlval string
	}{
		{name: "Set label on non-excluded namespace without label", nsn: "a", expectlval: "true"},
		{name: "No operation on non-excluded namespace with label (e.g. from a yaml file)", nsn: "a", lval: "true", expectlval: "true"},
		{name: "No operation on non-excluded namespace with label with wrong value(e.g. from a yaml file)", nsn: "a", lval: "wrong", expectlval: "wrong"},
		{name: "No operation on excluded namespace without label", nsn: "excluded"},
		{name: "No operation on excluded namespace with label (e.g. from a yaml file)", nsn: "excluded", lval: "true", expectlval: "true"},
		{name: "No operation on excluded namespace with label with wrong value (e.g. from a yaml file)", nsn: "excluded", lval: "wrong", expectlval: "wrong"},
	}
	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			g := NewWithT(t)

			nsInst := &corev1.Namespace{}
			nsInst.Name = tc.nsn
			if tc.lval != "" {
				nsInst.SetLabels(map[string]string{api.LabelIncludedNamespace: tc.lval})
			}

			// Test
			m.handle(l, nsInst)

			// Report
			g.Expect(nsInst.Labels[api.LabelIncludedNamespace]).Should(Equal(tc.expectlval))
		})
	}
}


<|start_filename|>internal/kubectl/tree.go<|end_filename|>
/*

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

    http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package kubectl

import (
	"context"
	"fmt"
	"os"
	"sort"
	"strconv"
	"strings"
	"time"

	"github.com/spf13/cobra"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"

	api "sigs.k8s.io/hierarchical-namespaces/api/v1alpha2"
)

var (
	footnotesByMsg  map[string]int
	footnotes       []string
	hasSubnamespace bool
)

var treeCmd = &cobra.Command{
	Use:   "tree TREE",
	Short: "Display one or more hierarchy trees",
	Run: func(cmd *cobra.Command, args []string) {
		flags := cmd.Flags()
		footnotesByMsg = map[string]int{}
		footnotes = []string{}
		defaultList := len(args) == 0
		nsList := args
		if flags.Changed("all-namespaces") {
			nsList = getAllNamespaces()
		}
		if defaultList && !flags.Changed("all-namespaces") {
			fmt.Printf("Error: Must specify the root of the tree(s) to display or else specify --all-namespaces\n")
			os.Exit(1)
		}

		for _, nnm := range nsList {
			hier := client.getHierarchy(nnm)
			// If we're showing the default list, skip all non-root namespaces since they'll be displayed
			// as part of another namespace's tree. Get the text first though because that will reveal if
			// the tree's in a cycle, in which case, even though the NS isn't a root, we'll display it
			// anyway.
			txt, cycle := nameAndFootnotes(hier)
			if defaultList && (!cycle && hier.Spec.Parent != "") {
				continue
			}
			fmt.Println(txt)
			printSubtree("", hier, cycle)
		}

		if hasSubnamespace {
			fmt.Printf("\n[s] indicates subnamespaces\n")
		}

		if len(footnotes) > 0 {
			fmt.Printf("\nConditions:\n")

			for i, n := range footnotes {
				fmt.Printf("%d) %s\n", i+1, n)
			}
		}
	},
}

func printSubtree(prefix string, hier *api.HierarchyConfiguration, inCycle bool) {
	for i, cn := range hier.Status.Children {
		ch := client.getHierarchy(cn)
		txt, cycle := nameAndFootnotes(ch)
		if cycle && inCycle {
			continue
		}

		ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
		defer cancel()

		ns, err := k8sClient.CoreV1().Namespaces().Get(ctx, cn, metav1.GetOptions{})
		if err != nil {
			fmt.Printf("Could not get namespaces: %s\n", err)
			os.Exit(1)
		}

		if _, ok := ns.ObjectMeta.Annotations[api.SubnamespaceOf]; ok {
			txt = "[s] " + txt
			hasSubnamespace = true
		}

		if i < len(hier.Status.Children)-1 {
			fmt.Printf("%s├── %s\n", prefix, txt)
			printSubtree(prefix+"│   ", ch, cycle)
		} else {
			fmt.Printf("%s└── %s\n", prefix, txt)
			printSubtree(prefix+"    ", ch, cycle)
		}
	}
}

// nameAndFootnotes returns the text to print to describe the namespace, in the form of the
// namespace's name along with references to any footnotes. Example: default (1).
//
// The second param is true if this namespace is part of a cycle, in which case we shouldn't
// recurse.
func nameAndFootnotes(hier *api.HierarchyConfiguration) (string, bool) {
	cycle := false
	notes := []int{}
	for _, cond := range hier.Status.Conditions {
		if cond.Reason == api.ReasonInCycle {
			cycle = true
		}
		txt := cond.Type + " (" + cond.Reason + "): " + cond.Message
		if idx, ok := footnotesByMsg[txt]; ok {
			notes = append(notes, idx)
		} else {
			footnotes = append(footnotes, txt)
			footnotesByMsg[txt] = len(footnotes)
			notes = append(notes, len(footnotes))
		}
	}

	if len(notes) == 0 {
		return hier.Namespace, false
	}
	sort.Ints(notes)
	ns := []string{}
	for _, n := range notes {
		ns = append(ns, strconv.Itoa(n))
	}
	return fmt.Sprintf("%s (%s)", hier.Namespace, strings.Join(ns, ",")), cycle
}

func newTreeCmd() *cobra.Command {
	treeCmd.Flags().BoolP("all-namespaces", "A", false, "Displays all trees on the cluster")
	return treeCmd
}

func getAllNamespaces() []string {
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	nsList, err := k8sClient.CoreV1().Namespaces().List(ctx, metav1.ListOptions{})
	if err != nil {
		fmt.Printf("Could not list namespaces: %s\n", err)
		os.Exit(1)
	}
	result := []string{}
	for _, each := range nsList.Items {
		result = append(result, each.Name)
	}
	sort.Strings(result)
	return result
}


<|start_filename|>internal/setup/webhooks.go<|end_filename|>
package setup

import (
	"fmt"

	cert "github.com/open-policy-agent/cert-controller/pkg/rotator"
	"k8s.io/apimachinery/pkg/types"
	ctrl "sigs.k8s.io/controller-runtime"
	"sigs.k8s.io/controller-runtime/pkg/webhook"

	"sigs.k8s.io/hierarchical-namespaces/internal/anchor"
	"sigs.k8s.io/hierarchical-namespaces/internal/forest"
	"sigs.k8s.io/hierarchical-namespaces/internal/hierarchyconfig"
	"sigs.k8s.io/hierarchical-namespaces/internal/hncconfig"
	ns "sigs.k8s.io/hierarchical-namespaces/internal/namespace" // for some reason, by default this gets imported as "namespace*s*"
	"sigs.k8s.io/hierarchical-namespaces/internal/objects"
)

const (
	serviceName     = "hnc-webhook-service"
	vwhName         = "hnc-validating-webhook-configuration"
	mwhName         = "hnc-mutating-webhook-configuration"
	caName          = "hnc-ca"
	caOrganization  = "hnc"
	secretNamespace = "hnc-system"
	secretName      = "hnc-webhook-server-cert"
	certDir         = "/tmp/k8s-webhook-server/serving-certs"
)

// DNSName is <service name>.<namespace>.svc
var dnsName = fmt.Sprintf("%s.%s.svc", serviceName, secretNamespace)

// CreateCertsIfNeeded creates all certs for webhooks. This function is called from main.go.
func CreateCertsIfNeeded(mgr ctrl.Manager, novalidation, internalCert, restartOnSecretRefresh bool) (chan struct{}, error) {
	setupFinished := make(chan struct{})
	if novalidation || !internalCert {
		close(setupFinished)
		return setupFinished, nil
	}

	return setupFinished, cert.AddRotator(mgr, &cert.CertRotator{
		SecretKey: types.NamespacedName{
			Namespace: secretNamespace,
			Name:      secretName,
		},
		CertDir:        certDir,
		CAName:         caName,
		CAOrganization: caOrganization,
		DNSName:        dnsName,
		IsReady:        setupFinished,
		Webhooks: []cert.WebhookInfo{{
			Type: cert.Validating,
			Name: vwhName,
		}, {
			Type: cert.Mutating,
			Name: mwhName,
		}},
		RestartOnSecretRefresh: restartOnSecretRefresh,
	})
}

// CreateWebhooks creates all mutators and validators. This function is called from main.go.
func CreateWebhooks(mgr ctrl.Manager, f *forest.Forest) {
	// Create webhook for Hierarchy
	mgr.GetWebhookServer().Register(hierarchyconfig.ServingPath, &webhook.Admission{Handler: &hierarchyconfig.Validator{
		Log:    ctrl.Log.WithName("hierarchyconfig").WithName("validate"),
		Forest: f,
	}})

	// Create webhooks for managed objects
	mgr.GetWebhookServer().Register(objects.ServingPath, &webhook.Admission{Handler: &objects.Validator{
		Log:    ctrl.Log.WithName("objects").WithName("validate"),
		Forest: f,
	}})

	// Create webhook for the config
	mgr.GetWebhookServer().Register(hncconfig.ServingPath, &webhook.Admission{Handler: &hncconfig.Validator{
		Log:    ctrl.Log.WithName("hncconfig").WithName("validate"),
		Forest: f,
	}})

	// Create webhook for the subnamespace anchors.
	mgr.GetWebhookServer().Register(anchor.ServingPath, &webhook.Admission{Handler: &anchor.Validator{
		Log:    ctrl.Log.WithName("anchor").WithName("validate"),
		Forest: f,
	}})

	// Create webhook for the namespaces (core type).
	mgr.GetWebhookServer().Register(ns.ServingPath, &webhook.Admission{Handler: &ns.Validator{
		Log:    ctrl.Log.WithName("namespace").WithName("validate"),
		Forest: f,
	}})

	// Create mutator for namespace `included-namespace` label.
	mgr.GetWebhookServer().Register(ns.MutatorServingPath, &webhook.Admission{Handler: &ns.Mutator{
		Log: ctrl.Log.WithName("namespace").WithName("mutate"),
	}})
}
