From 9c2fe36c0e1436df2c8f19b21244b6e1456b6c9c Mon Sep 17 00:00:00 2001 From: Bhavin Gandhi Date: Tue, 2 Oct 2018 10:59:51 +0530 Subject: [PATCH 01/25] Remove weaveutil and weave from Dockerfile.cloud-agent - Moves the weave and weaveutil from Dockerfile.cloud-agent to Dockerfile.scope Signed-off-by: Bhavin Gandhi --- docker/Dockerfile.cloud-agent | 1 - docker/Dockerfile.scope | 1 + 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/Dockerfile.cloud-agent b/docker/Dockerfile.cloud-agent index 627fcfa2bc..8f74348542 100644 --- a/docker/Dockerfile.cloud-agent +++ b/docker/Dockerfile.cloud-agent @@ -2,7 +2,6 @@ FROM alpine:3.7 WORKDIR /home/weave RUN apk add --update bash conntrack-tools iproute2 util-linux curl && \ rm -rf /var/cache/apk/* -ADD ./weave ./weaveutil /usr/bin/ COPY ./scope /home/weave/ ENTRYPOINT ["/home/weave/scope", "--mode=probe", "--no-app", "--probe.docker=true"] diff --git a/docker/Dockerfile.scope b/docker/Dockerfile.scope index 9f2dc28514..7e0af4571d 100644 --- a/docker/Dockerfile.scope +++ b/docker/Dockerfile.scope @@ -2,6 +2,7 @@ FROM weaveworks/cloud-agent RUN apk add --update runit && \ rm -rf /var/cache/apk/* ADD ./demo.json / +ADD ./weave ./weaveutil /usr/bin/ COPY ./runsvinit ./entrypoint.sh /home/weave/ COPY ./run-app /etc/service/app/run COPY ./run-probe /etc/service/probe/run From 2ec58da1cf11c1eeac76636ce8faffda08fbc71c Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Tue, 9 Oct 2018 14:25:06 +0000 Subject: [PATCH 02/25] Don't report dead processes If the state is reported as dead or zombie, return an error so the process will be skipped. --- probe/process/walker_linux.go | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/probe/process/walker_linux.go b/probe/process/walker_linux.go index 05240bd971..b0cad69cd0 100644 --- a/probe/process/walker_linux.go +++ b/probe/process/walker_linux.go @@ -3,6 +3,7 @@ package process import ( "bytes" "encoding/binary" + "errors" "fmt" "os" "path" @@ -31,6 +32,8 @@ var ( // key: filename in /proc. Example: "42" // value: two strings separated by a '\0' cmdlineCache = freecache.NewCache(1024 * 16) + + errDeadProcess = errors.New("The process is dead") ) const ( @@ -75,6 +78,7 @@ func readStats(path string) (ppid, threads int, jiffies, rss, rssLimit uint64, e const ( // /proc//stat field positions, counting from zero // see "man 5 proc" + procStatFieldState int = 2 procStatFieldPpid int = 3 procStatFieldUserJiffies int = 13 procStatFieldSysJiffies int = 14 @@ -94,7 +98,16 @@ func readStats(path string) (ppid, threads int, jiffies, rss, rssLimit uint64, e // Parse the file without using expensive extra string allocations pos := 0 - skipNSpaces(&buf, &pos, procStatFieldPpid) + skipNSpaces(&buf, &pos, procStatFieldState) + + // Error on processes which are in zombie (defunct) or dead state, so they will be skipped + switch buf[pos] { + case 'Z', 'X', 'x': + err = errDeadProcess + return + } + + pos += 2 // Move past state and space after state ppid = parseIntWithSpaces(&buf, &pos) skipNSpaces(&buf, &pos, procStatFieldUserJiffies-procStatFieldPpid) From 9c4f6b5544bff64b55b4bba930aa70fed6d57f9a Mon Sep 17 00:00:00 2001 From: Rich Date: Tue, 9 Oct 2018 18:21:01 -0500 Subject: [PATCH 03/25] Update README.md Minor punctuation and capitalization edits --- README.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 051887fee3..2d79c32451 100644 --- a/README.md +++ b/README.md @@ -8,9 +8,9 @@ [![GoDoc](https://godoc.org/github.com/weaveworks/scope?status.svg)](https://godoc.org/github.com/weaveworks/scope) Weave Scope automatically generates a map of your application, enabling you to -intuitively understand, monitor, and control your containerized, microservices based application. +intuitively understand, monitor, and control your containerized, microservices-based application. -### Understand your Docker containers in real-time +### Understand your Docker containers in real time Map you architecture @@ -20,19 +20,19 @@ Choose an overview of your container infrastructure, or focus on a specific micr Focus on a single container -View contextual metrics, tags and metadata for your containers. Effortlessly navigate between processes inside your container to hosts your containers run on, arranged in expandable, sortable tables. Easily find the container using the most CPU or memory for a given host or service. +View contextual metrics, tags, and metadata for your containers. Effortlessly navigate between processes inside your container to hosts your containers run on, arranged in expandable, sortable tables. Easily find the container using the most CPU or memory for a given host or service. ### Interact with and manage containers Launch a command line. -Interact with your containers directly: pause, restart and stop containers. Launch a command line. All without leaving the scope browser window. +Interact with your containers directly: pause, restart, and stop containers. Launch a command line. All without leaving the scope browser window. ### Extend and customize via plugins -Add custom details or interactions for your hosts, containers and/or processes by creating Scope plugins; or just choose from some that others have already written at the Github [Weaveworks Scope Plugins](https://github.com/weaveworks-plugins/) organization. +Add custom details or interactions for your hosts, containers, and/or processes by creating Scope plugins. Or, just choose from some that others have already written at the GitHub [Weaveworks Scope Plugins](https://github.com/weaveworks-plugins/) organization. -## Getting started +## Getting Started ```console sudo curl -L git.io/scope -o /usr/local/bin/scope @@ -44,18 +44,18 @@ This script downloads and runs a recent Scope image from Docker Hub. Now, open your web browser to **http://localhost:4040**. (If you're using boot2docker, replace localhost with the output of `boot2docker ip`.) -For instructions on installing Scope on [Kubernetes](https://www.weave.works/docs/scope/latest/installing/#k8s), [DCOS](https://www.weave.works/docs/scope/latest/installing/#dcos) or [ECS](https://www.weave.works/docs/scope/latest/installing/#ecs), see [the docs](https://www.weave.works/docs/scope/latest/introducing/). +For instructions on installing Scope on [Kubernetes](https://www.weave.works/docs/scope/latest/installing/#k8s), [DCOS](https://www.weave.works/docs/scope/latest/installing/#dcos), or [ECS](https://www.weave.works/docs/scope/latest/installing/#ecs), see [the docs](https://www.weave.works/docs/scope/latest/introducing/). -## Getting help +## Getting Help -If you have any questions about, feedback for or problems with Scope: +If you have any questions, feedback, or problems with Scope: - Read [the Weave Scope docs](https://www.weave.works/docs/scope/latest/introducing/). -- Invite yourself to the Weave community slack. -- Ask a question on the [#scope](https://weave-community.slack.com/messages/scope/) slack channel. +- Invite yourself to the Weave community Slack. +- Ask a question on the [#scope](https://weave-community.slack.com/messages/scope/) Slack channel. - Join the [Weave User Group](https://www.meetup.com/pro/Weave/) and get invited to online talks, hands-on training and meetups in your area. - Send an email to [Scope community group](https://groups.google.com/forum/#!forum/scope-community). - Join (and read up on) the regular [Scope community meetings](https://docs.google.com/document/d/103_60TuEkfkhz_h2krrPJH8QOx-vRnPpbcCZqrddE1s/edit). - [File an issue](https://github.com/weaveworks/scope/issues/new). -Your feedback is always welcome! \ No newline at end of file +Your feedback is always welcome! From 4dd6f4cd2bdaa3ade85ce79e6e70b2c039156e0b Mon Sep 17 00:00:00 2001 From: Marcus Cobden Date: Wed, 10 Oct 2018 15:56:33 +0100 Subject: [PATCH 04/25] Create UI toolchain dirs from Makefile To prevent docker from creating it with root as the owner --- Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/Makefile b/Makefile index bde1bfbef6..608b00e903 100644 --- a/Makefile +++ b/Makefile @@ -147,6 +147,7 @@ SCOPE_UI_TOOLCHAIN=.cache/build_node_modules SCOPE_UI_TOOLCHAIN_UPTODATE=$(SCOPE_UI_TOOLCHAIN)/.uptodate $(SCOPE_UI_TOOLCHAIN_UPTODATE): client/yarn.lock $(SCOPE_UI_BUILD_UPTODATE) + mkdir -p $(SCOPE_UI_TOOLCHAIN) client/node_modules if test "true" != "$(SCOPE_SKIP_UI_ASSETS)"; then \ $(SUDO) docker run $(RM) $(RUN_FLAGS) \ -v $(shell pwd)/.cache:/home/weave/scope/.cache \ From dd21a55a1e6c6f59a6dd61dc36a5559b77399ee6 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 20 Jul 2018 21:57:05 +0000 Subject: [PATCH 05/25] Refactor: implement kubernetes tagger in separate struct --- probe/kubernetes/reporter.go | 9 ++++++++- probe/kubernetes/reporter_test.go | 3 +-- prog/probe.go | 2 +- 3 files changed, 10 insertions(+), 4 deletions(-) diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index 3dfa8c7939..f7e20acf0f 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -238,8 +238,15 @@ func isPauseContainer(n report.Node, rpt report.Report) bool { return false } +// Tagger adds pod parents to container nodes. +type Tagger struct { +} + +// Name of this tagger, for metrics gathering +func (Tagger) Name() string { return "K8s" } + // Tag adds pod parents to container nodes. -func (r *Reporter) Tag(rpt report.Report) (report.Report, error) { +func (r *Tagger) Tag(rpt report.Report) (report.Report, error) { for id, n := range rpt.Container.Nodes { uid, ok := n.Latest.Lookup(docker.LabelPrefix + "io.kubernetes.pod.uid") if !ok { diff --git a/probe/kubernetes/reporter_test.go b/probe/kubernetes/reporter_test.go index 70e083b3a6..bce58cd3a8 100644 --- a/probe/kubernetes/reporter_test.go +++ b/probe/kubernetes/reporter_test.go @@ -328,8 +328,7 @@ func TestTagger(t *testing.T) { docker.LabelPrefix + "io.kubernetes.pod.uid": "123456", })) - hr := controls.NewDefaultHandlerRegistry() - rpt, err := kubernetes.NewReporter(newMockClient(), nil, "", "", nil, hr, "", 0).Tag(rpt) + rpt, err := (&kubernetes.Tagger{}).Tag(rpt) if err != nil { t.Errorf("Unexpected error: %v", err) } diff --git a/prog/probe.go b/prog/probe.go index 756a5d00bf..abba705020 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -273,7 +273,7 @@ func probeMain(flags probeFlags, targets []appclient.Target) { reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName, flags.kubernetesKubeletPort) defer reporter.Stop() p.AddReporter(reporter) - p.AddTagger(reporter) + p.AddTagger(&kubernetes.Tagger{}) } else { log.Errorf("Kubernetes: failed to start client: %v", err) log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags") From 88049b081754808b8956d588bcb448ce11339634 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 20 Jul 2018 22:10:13 +0000 Subject: [PATCH 06/25] Add option for Kubernetes tagging when kubernetes probing disabled This enables us to run Kubernetes probing on one node for the whole cluster. --- prog/main.go | 2 ++ prog/probe.go | 5 ++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/prog/main.go b/prog/main.go index 9630b816bf..d9e51ec68e 100644 --- a/prog/main.go +++ b/prog/main.go @@ -124,6 +124,7 @@ type probeFlags struct { criEndpoint string kubernetesEnabled bool + kubernetesTagOnly bool kubernetesNodeName string kubernetesClientConfig kubernetes.ClientConfig kubernetesKubeletPort uint @@ -314,6 +315,7 @@ func setupFlags(flags *flags) { // K8s flag.BoolVar(&flags.probe.kubernetesEnabled, "probe.kubernetes", false, "collect kubernetes-related attributes for containers") + flag.BoolVar(&flags.probe.kubernetesTagOnly, "probe.kubernetes-tag", false, "tag containers with kubernetes parents") flag.StringVar(&flags.probe.kubernetesClientConfig.Server, "probe.kubernetes.api", "", "The address and port of the Kubernetes API server (deprecated in favor of equivalent probe.kubernetes.server)") flag.StringVar(&flags.probe.kubernetesClientConfig.CertificateAuthority, "probe.kubernetes.certificate-authority", "", "Path to a cert. file for the certificate authority") flag.StringVar(&flags.probe.kubernetesClientConfig.ClientCertificate, "probe.kubernetes.client-certificate", "", "Path to a client certificate file for TLS") diff --git a/prog/probe.go b/prog/probe.go index abba705020..a45833d173 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -273,13 +273,16 @@ func probeMain(flags probeFlags, targets []appclient.Target) { reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName, flags.kubernetesKubeletPort) defer reporter.Stop() p.AddReporter(reporter) - p.AddTagger(&kubernetes.Tagger{}) } else { log.Errorf("Kubernetes: failed to start client: %v", err) log.Errorf("Kubernetes: make sure to run Scope inside a POD with a service account or provide valid probe.kubernetes.* flags") } } + if flags.kubernetesEnabled || flags.kubernetesTagOnly { + p.AddTagger(&kubernetes.Tagger{}) + } + if flags.ecsEnabled { reporter := awsecs.Make(flags.ecsCacheSize, flags.ecsCacheExpiry, flags.ecsClusterRegion, handlerRegistry, probeID) defer reporter.Stop() From 38ea862bfd6e0660875e25c4f29c29595c7e75ea Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 20 Jul 2018 22:10:49 +0000 Subject: [PATCH 07/25] Check if dockerBridge is nonblank before using it This gives us the option of disabling the function --- prog/probe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/prog/probe.go b/prog/probe.go index a45833d173..c1463ea85f 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -233,7 +233,7 @@ func probeMain(flags probeFlags, targets []appclient.Target) { if flags.dockerEnabled { // Don't add the bridge in Kubernetes since container IPs are global and // shouldn't be scoped - if !flags.kubernetesEnabled { + if flags.dockerBridge != "" && !flags.kubernetesEnabled { if err := report.AddLocalBridge(flags.dockerBridge); err != nil { log.Errorf("Docker: problem with bridge %s: %v", flags.dockerBridge, err) } From 98d52bd48006d8b2b9df21896dd772ec4a98f0d2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 22 Jul 2018 21:37:34 +0000 Subject: [PATCH 08/25] Allow kubelet port to be disabled --- probe/kubernetes/reporter.go | 2 +- prog/main.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index f7e20acf0f..58f5b13415 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -561,7 +561,7 @@ func (r *Reporter) podTopology(services []Service, deployments []Deployment, dae } var localPodUIDs map[string]struct{} - if r.nodeName == "" { + if r.nodeName == "" && r.kubeletPort != 0 { // We don't know the node name: fall back to obtaining the local pods from kubelet var err error localPodUIDs, err = GetLocalPodUIDs(fmt.Sprintf("127.0.0.1:%d", r.kubeletPort)) diff --git a/prog/main.go b/prog/main.go index d9e51ec68e..b133a69187 100644 --- a/prog/main.go +++ b/prog/main.go @@ -330,7 +330,7 @@ func setupFlags(flags *flags) { flag.StringVar(&flags.probe.kubernetesClientConfig.User, "probe.kubernetes.user", "", "The name of the kubeconfig user to use") flag.StringVar(&flags.probe.kubernetesClientConfig.Username, "probe.kubernetes.username", "", "Username for basic authentication to the API server") flag.StringVar(&flags.probe.kubernetesNodeName, "probe.kubernetes.node-name", "", "Name of this node, for filtering pods") - flag.UintVar(&flags.probe.kubernetesKubeletPort, "probe.kubernetes.kubelet-port", 10255, "Node-local TCP port for contacting kubelet") + flag.UintVar(&flags.probe.kubernetesKubeletPort, "probe.kubernetes.kubelet-port", 10255, "Node-local TCP port for contacting kubelet (zero to disable)") // AWS ECS flag.BoolVar(&flags.probe.ecsEnabled, "probe.ecs", false, "Collect ecs-related attributes for containers on this node") From 1279a02b7dc3ec2c412b8711b01d3184ce058381 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 22 Jul 2018 21:59:50 +0000 Subject: [PATCH 09/25] Stop tagging pods with host ID So they can be reported centrally, find the pod host ID from the child containers. --- probe/host/tagger.go | 3 ++- render/pod.go | 36 ++++++++++++++++++++++++++++-------- 2 files changed, 30 insertions(+), 9 deletions(-) diff --git a/probe/host/tagger.go b/probe/host/tagger.go index 29e5413243..f466c96e71 100644 --- a/probe/host/tagger.go +++ b/probe/host/tagger.go @@ -30,7 +30,8 @@ func (t Tagger) Tag(r report.Report) (report.Report, error) { // Explicitly don't tag Endpoints, Addresses and Overlay nodes - These topologies include pseudo nodes, // and as such do their own host tagging. - for _, topology := range []report.Topology{r.Process, r.Container, r.ContainerImage, r.Host, r.Pod} { + // Don't tag Pods so they can be reported centrally. + for _, topology := range []report.Topology{r.Process, r.Container, r.ContainerImage, r.Host} { for _, node := range topology.Nodes { topology.ReplaceNode(node.WithLatests(metadata).WithParent(report.Host, t.hostNodeID)) } diff --git a/render/pod.go b/render/pod.go index c08ab0e515..d03b71b13a 100644 --- a/render/pod.go +++ b/render/pod.go @@ -53,14 +53,16 @@ var PodRenderer = Memoise(ConditionalRenderer(renderKubernetesTopologies, }, MakeReduce( PropagateSingleMetrics(report.Container, - Map2Parent{topologies: []string{report.Pod}, noParentsPseudoID: UnmanagedID, - chainRenderer: MakeFilter( - ComposeFilterFuncs( - IsRunning, - Complement(isPauseContainer), - ), - ContainerWithImageNameRenderer, - )}, + MakeMap(propagateHostID, + Map2Parent{topologies: []string{report.Pod}, noParentsPseudoID: UnmanagedID, + chainRenderer: MakeFilter( + ComposeFilterFuncs( + IsRunning, + Complement(isPauseContainer), + ), + ContainerWithImageNameRenderer, + )}, + ), ), ConnectionJoin(MapPod2IP, report.Pod), KubernetesVolumesRenderer, @@ -68,6 +70,24 @@ var PodRenderer = Memoise(ConditionalRenderer(renderKubernetesTopologies, ), )) +// Pods are not tagged with a Host ID, but their container children are. +// If n doesn't already have a host ID, copy it from one of the children +func propagateHostID(n report.Node) report.Node { + if _, found := n.Latest.Lookup(report.HostNodeID); found { + return n + } + var first *report.Node + n.Children.ForEach(func(child report.Node) { + if first == nil { + first = &child + } + }) + if first != nil { + n.Latest = n.Latest.Propagate(first.Latest, report.HostNodeID) + } + return n +} + // PodServiceRenderer is a Renderer which produces a renderable kubernetes services // graph by merging the pods graph and the services topology. // From 78eaf93c2159fed1ad1b2d5f0299976cefa9a356 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 11 Oct 2018 18:10:39 +0000 Subject: [PATCH 10/25] Make flag names easier to understand Now you specify a role instead of controlling the internal behaviour --- prog/main.go | 4 ++-- prog/probe.go | 18 ++++++++++++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/prog/main.go b/prog/main.go index b133a69187..13d1ae1a01 100644 --- a/prog/main.go +++ b/prog/main.go @@ -124,7 +124,7 @@ type probeFlags struct { criEndpoint string kubernetesEnabled bool - kubernetesTagOnly bool + kubernetesRole string kubernetesNodeName string kubernetesClientConfig kubernetes.ClientConfig kubernetesKubeletPort uint @@ -315,7 +315,7 @@ func setupFlags(flags *flags) { // K8s flag.BoolVar(&flags.probe.kubernetesEnabled, "probe.kubernetes", false, "collect kubernetes-related attributes for containers") - flag.BoolVar(&flags.probe.kubernetesTagOnly, "probe.kubernetes-tag", false, "tag containers with kubernetes parents") + flag.StringVar(&flags.probe.kubernetesRole, "probe.kubernetes.role", "", "host, cluster or blank for everything") flag.StringVar(&flags.probe.kubernetesClientConfig.Server, "probe.kubernetes.api", "", "The address and port of the Kubernetes API server (deprecated in favor of equivalent probe.kubernetes.server)") flag.StringVar(&flags.probe.kubernetesClientConfig.CertificateAuthority, "probe.kubernetes.certificate-authority", "", "Path to a cert. file for the certificate authority") flag.StringVar(&flags.probe.kubernetesClientConfig.ClientCertificate, "probe.kubernetes.client-certificate", "", "Path to a client certificate file for TLS") diff --git a/prog/probe.go b/prog/probe.go index c1463ea85f..9896e9f326 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -41,6 +41,9 @@ import ( const ( versionCheckPeriod = 6 * time.Hour defaultServiceHost = "https://cloud.weave.works.:443" + + kubernetesRoleHost = "host" + kubernetesRoleCluster = "cluster" ) var ( @@ -230,6 +233,17 @@ func probeMain(flags probeFlags, targets []appclient.Target) { defer endpointReporter.Stop() p.AddReporter(endpointReporter) + switch flags.kubernetesRole { + case "": // nothing special + case kubernetesRoleHost: + flags.kubernetesEnabled = true + case kubernetesRoleCluster: + flags.kubernetesKubeletPort = 0 + flags.kubernetesEnabled = true + default: + log.Warnf("unrecognized --probe.kubernetes.role: %s", flags.kubernetesRole) + } + if flags.dockerEnabled { // Don't add the bridge in Kubernetes since container IPs are global and // shouldn't be scoped @@ -267,7 +281,7 @@ func probeMain(flags probeFlags, targets []appclient.Target) { } } - if flags.kubernetesEnabled { + if flags.kubernetesEnabled && flags.kubernetesRole != kubernetesRoleHost { if client, err := kubernetes.NewClient(flags.kubernetesClientConfig); err == nil { defer client.Stop() reporter := kubernetes.NewReporter(client, clients, probeID, hostID, p, handlerRegistry, flags.kubernetesNodeName, flags.kubernetesKubeletPort) @@ -279,7 +293,7 @@ func probeMain(flags probeFlags, targets []appclient.Target) { } } - if flags.kubernetesEnabled || flags.kubernetesTagOnly { + if flags.kubernetesEnabled { p.AddTagger(&kubernetes.Tagger{}) } From fb96fe0024bc5df495f88c8a88e146d4812d5cc1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 12 Oct 2018 11:52:34 +0000 Subject: [PATCH 11/25] Turn everything else off in Kubernetes cluster probe --- prog/probe.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/prog/probe.go b/prog/probe.go index 9896e9f326..c06d6821dd 100644 --- a/prog/probe.go +++ b/prog/probe.go @@ -108,6 +108,21 @@ func probeMain(flags probeFlags, targets []appclient.Target) { logCensoredArgs() defer log.Info("probe exiting") + switch flags.kubernetesRole { + case "": // nothing special + case kubernetesRoleHost: + flags.kubernetesEnabled = true + case kubernetesRoleCluster: + flags.kubernetesKubeletPort = 0 + flags.kubernetesEnabled = true + flags.spyProcs = false + flags.procEnabled = false + flags.useConntrack = false + flags.useEbpfConn = false + default: + log.Warnf("unrecognized --probe.kubernetes.role: %s", flags.kubernetesRole) + } + if flags.spyProcs && os.Getegid() != 0 { log.Warn("--probe.proc.spy=true, but that requires root to find everything") } @@ -233,17 +248,6 @@ func probeMain(flags probeFlags, targets []appclient.Target) { defer endpointReporter.Stop() p.AddReporter(endpointReporter) - switch flags.kubernetesRole { - case "": // nothing special - case kubernetesRoleHost: - flags.kubernetesEnabled = true - case kubernetesRoleCluster: - flags.kubernetesKubeletPort = 0 - flags.kubernetesEnabled = true - default: - log.Warnf("unrecognized --probe.kubernetes.role: %s", flags.kubernetesRole) - } - if flags.dockerEnabled { // Don't add the bridge in Kubernetes since container IPs are global and // shouldn't be scoped From 0c394e689a25fc09692596c3c51311bb78abaf87 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Fri, 12 Oct 2018 13:47:39 +0000 Subject: [PATCH 12/25] Fix pod host propagation --- render/pod.go | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/render/pod.go b/render/pod.go index d03b71b13a..49b97be876 100644 --- a/render/pod.go +++ b/render/pod.go @@ -53,7 +53,7 @@ var PodRenderer = Memoise(ConditionalRenderer(renderKubernetesTopologies, }, MakeReduce( PropagateSingleMetrics(report.Container, - MakeMap(propagateHostID, + MakeMap(propagatePodHost, Map2Parent{topologies: []string{report.Pod}, noParentsPseudoID: UnmanagedID, chainRenderer: MakeFilter( ComposeFilterFuncs( @@ -70,21 +70,25 @@ var PodRenderer = Memoise(ConditionalRenderer(renderKubernetesTopologies, ), )) -// Pods are not tagged with a Host ID, but their container children are. -// If n doesn't already have a host ID, copy it from one of the children -func propagateHostID(n report.Node) report.Node { - if _, found := n.Latest.Lookup(report.HostNodeID); found { +// Pods are not tagged with a Host parent, but their container children are. +// If n doesn't already have a host, copy it from one of the children +func propagatePodHost(n report.Node) report.Node { + if n.Topology != report.Pod { + return n + } else if _, found := n.Parents.Lookup(report.Host); found { return n } - var first *report.Node + done := false n.Children.ForEach(func(child report.Node) { - if first == nil { - first = &child + if !done { + if hosts, found := child.Parents.Lookup(report.Host); found { + for _, h := range hosts { + n = n.WithParent(report.Host, h) + } + done = true + } } }) - if first != nil { - n.Latest = n.Latest.Propagate(first.Latest, report.HostNodeID) - } return n } From 64197d15bebcc668480523cde465953780fe10d1 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sat, 13 Oct 2018 12:46:14 +0000 Subject: [PATCH 13/25] Rate limit report publishing So that, if many shortcut reports are produced in quick succession, they will tend to get merged together. Expand the queue size for shortcut reports, to avoid holding up the producer so much. --- probe/probe.go | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/probe/probe.go b/probe/probe.go index b34f21cdec..1e386850d1 100644 --- a/probe/probe.go +++ b/probe/probe.go @@ -1,17 +1,20 @@ package probe import ( + "context" "sync" "time" "github.com/armon/go-metrics" log "github.com/sirupsen/logrus" + "golang.org/x/time/rate" "github.com/weaveworks/scope/report" ) const ( - reportBufferSize = 16 + spiedReportBufferSize = 16 + shortcutReportBufferSize = 1024 ) // ReportPublisher publishes reports, probably to a remote collector. @@ -23,6 +26,7 @@ type ReportPublisher interface { type Probe struct { spyInterval, publishInterval time.Duration publisher ReportPublisher + rateLimiter *rate.Limiter noControls bool tickers []Ticker @@ -79,10 +83,11 @@ func New( spyInterval: spyInterval, publishInterval: publishInterval, publisher: publisher, + rateLimiter: rate.NewLimiter(rate.Every(publishInterval)*10, 1), noControls: noControls, quit: make(chan struct{}), - spiedReports: make(chan report.Report, reportBufferSize), - shortcutReports: make(chan report.Report, reportBufferSize), + spiedReports: make(chan report.Report, spiedReportBufferSize), + shortcutReports: make(chan report.Report, shortcutReportBufferSize), } return result } @@ -197,6 +202,7 @@ func (p *Probe) tag(r report.Report) report.Report { } func (p *Probe) drainAndPublish(rpt report.Report, rs chan report.Report) { + p.rateLimiter.Wait(context.Background()) ForLoop: for { select { From b6d4538663225d0f3ea6088494a3e408dcd8c05a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tomasz=20Skowro=C5=84ski?= Date: Sat, 13 Oct 2018 19:13:52 +0200 Subject: [PATCH 14/25] scripts: replace share icon with sitemap (graph) fix confusing graph icon Fixes #2511 --- client/app/scripts/components/view-mode-selector.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/app/scripts/components/view-mode-selector.js b/client/app/scripts/components/view-mode-selector.js index b915bae3a5..0451ae0bf0 100644 --- a/client/app/scripts/components/view-mode-selector.js +++ b/client/app/scripts/components/view-mode-selector.js @@ -29,7 +29,7 @@ class ViewModeSelector extends React.Component {
From 52024d8b482a1016021692f2fb6866988472981b Mon Sep 17 00:00:00 2001 From: "Timm, Christopher" Date: Sat, 13 Oct 2018 17:48:19 -0500 Subject: [PATCH 15/25] build: Fix import for golint The import path for golint has changed Fixes #3388 --- backend/Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/Dockerfile b/backend/Dockerfile index 48d932d436..952a30643c 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -19,7 +19,7 @@ RUN go clean -i net && \ fi; \ go get -tags netgo \ github.com/fzipp/gocyclo \ - github.com/golang/lint/golint \ + golang.org/x/lint/golint \ github.com/kisielk/errcheck \ github.com/fatih/hclfmt \ github.com/mjibson/esc \ From 195c4e030ef18ea22bdbbc257a216665a55f9a4b Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 14 Oct 2018 12:04:03 +0000 Subject: [PATCH 16/25] Raise report publishing rate to 30ms default --- probe/probe.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/probe/probe.go b/probe/probe.go index 1e386850d1..4e9bac59e6 100644 --- a/probe/probe.go +++ b/probe/probe.go @@ -83,7 +83,7 @@ func New( spyInterval: spyInterval, publishInterval: publishInterval, publisher: publisher, - rateLimiter: rate.NewLimiter(rate.Every(publishInterval)*10, 1), + rateLimiter: rate.NewLimiter(rate.Every(publishInterval/100), 1), noControls: noControls, quit: make(chan struct{}), spiedReports: make(chan report.Report, spiedReportBufferSize), From b82aff121068e4c1cd16b968723bc2e631dd360d Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Sun, 14 Oct 2018 15:24:34 +0000 Subject: [PATCH 17/25] Discard pod updates for other nodes We were filtering pods to those on the local node already, for regular reports, so we should also filter events that come in asynchronously. --- probe/kubernetes/reporter.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index 3dfa8c7939..dffccfdf55 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -193,6 +193,10 @@ func (r *Reporter) Stop() { func (Reporter) Name() string { return "K8s" } func (r *Reporter) podEvent(e Event, pod Pod) { + // filter out non-local pods, if we have been given a node name to report on + if r.nodeName != "" && pod.NodeName() != r.nodeName { + return + } switch e { case ADD: rpt := report.MakeReport() From ea9ad0a1e628a2de5f6c682d6a8a2ff25145e6c8 Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Tue, 25 Sep 2018 18:22:37 +0530 Subject: [PATCH 18/25] Update topology to include tag Tag can be used to specify the sub-shape for the given node. Signed-off-by: Akash Srivastava --- client/app/scripts/charts/node-container.js | 1 + .../scripts/charts/nodes-chart-elements.js | 1 + render/detailed/node_test.go | 3 ++ render/detailed/summary.go | 3 ++ render/detailed/summary_test.go | 5 ++++ report/report.go | 1 + report/topology.go | 30 +++++++++++++++++++ 7 files changed, 44 insertions(+) diff --git a/client/app/scripts/charts/node-container.js b/client/app/scripts/charts/node-container.js index 2ef7d991a0..fa0dce2f27 100644 --- a/client/app/scripts/charts/node-container.js +++ b/client/app/scripts/charts/node-container.js @@ -60,6 +60,7 @@ class NodeContainer extends React.Component { Date: Tue, 25 Sep 2018 18:31:56 +0530 Subject: [PATCH 19/25] Add snapshot client as a dependency - Snapshot is a CRD residing in kubernetes-incubator/external-storage It doesn't have a proper clientset. - A PR for proper clientset is already raised. Until the PR is merged, we are using openebs/k8s-snapshot-client as a snapshot client. Signed-off-by: Akash Srivastava --- .../openebs/k8s-snapshot-client/LICENSE | 201 +++++++++ .../pkg/apis/volumesnapshot/v1/doc.go | 21 + .../pkg/apis/volumesnapshot/v1/register.go | 59 +++ .../pkg/apis/volumesnapshot/v1/types.go | 291 ++++++++++++ .../v1/zz_generated.deepcopy.go | 421 ++++++++++++++++++ .../client/clientset/versioned/clientset.go | 97 ++++ .../pkg/client/clientset/versioned/doc.go | 19 + .../versioned/fake/clientset_generated.go | 81 ++++ .../client/clientset/versioned/fake/doc.go | 19 + .../clientset/versioned/fake/register.go | 53 +++ .../client/clientset/versioned/scheme/doc.go | 19 + .../clientset/versioned/scheme/register.go | 53 +++ .../versioned/typed/volumesnapshot/v1/doc.go | 19 + .../typed/volumesnapshot/v1/fake/doc.go | 19 + .../v1/fake/fake_volumesnapshot.go | 139 ++++++ .../v1/fake/fake_volumesnapshot_client.go | 43 ++ .../v1/fake/fake_volumesnapshotdata.go | 130 ++++++ .../volumesnapshot/v1/generated_expansion.go | 22 + .../typed/volumesnapshot/v1/volumesnapshot.go | 173 +++++++ .../v1/volumesnapshot_client.go | 94 ++++ .../volumesnapshot/v1/volumesnapshotdata.go | 162 +++++++ .../informers/externalversions/factory.go | 179 ++++++++ .../informers/externalversions/generic.go | 63 +++ .../internalinterfaces/factory_interfaces.go | 37 ++ .../volumesnapshot/interface.go | 45 ++ .../volumesnapshot/v1/interface.go | 51 +++ .../volumesnapshot/v1/volumesnapshot.go | 88 ++++ .../volumesnapshot/v1/volumesnapshotdata.go | 87 ++++ .../volumesnapshot/v1/expansion_generated.go | 30 ++ .../volumesnapshot/v1/volumesnapshot.go | 93 ++++ .../volumesnapshot/v1/volumesnapshotdata.go | 64 +++ vendor/manifest | 8 + 32 files changed, 2880 insertions(+) create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/LICENSE create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/register.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/types.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/zz_generated.deepcopy.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/clientset.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/clientset_generated.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/register.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/register.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/doc.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot_client.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshotdata.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/generated_expansion.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot_client.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshotdata.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/factory.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/generic.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/interface.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/interface.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshot.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshotdata.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/expansion_generated.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshot.go create mode 100644 vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshotdata.go diff --git a/vendor/github.com/openebs/k8s-snapshot-client/LICENSE b/vendor/github.com/openebs/k8s-snapshot-client/LICENSE new file mode 100644 index 0000000000..261eeb9e9f --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/doc.go new file mode 100644 index 0000000000..2ff37018ad --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/doc.go @@ -0,0 +1,21 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ + +// +k8s:deepcopy-gen=package,register + +// Package v1 is the v1 version of the API. +// +groupName=volumesnapshot.external-storage.k8s.io +package v1 diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/register.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/register.go new file mode 100644 index 0000000000..7f9538e283 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/register.go @@ -0,0 +1,59 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 v1 + +import ( + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/runtime/schema" +) + +// GroupName is the group name use in this package. +const GroupName = "volumesnapshot.external-storage.k8s.io" + +var ( + // SchemeBuilder is the new scheme builder + SchemeBuilder = runtime.NewSchemeBuilder(addKnownTypes) + // AddToScheme adds to scheme + AddToScheme = SchemeBuilder.AddToScheme + // SchemeGroupVersion is the group version used to register these objects. + SchemeGroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1"} +) + +// Resource takes an unqualified resource and returns a Group-qualified GroupResource. +func Resource(resource string) schema.GroupResource { + return SchemeGroupVersion.WithResource(resource).GroupResource() +} + +func init() { + // We only register manually written functions here. The registration of the + // generated functions takes place in the generated files. The separation + // makes the code compile even when the generated files are missing. + SchemeBuilder.Register(addKnownTypes) +} + +// addKnownTypes adds the set of types defined in this package to the supplied scheme. +func addKnownTypes(scheme *runtime.Scheme) error { + scheme.AddKnownTypes(SchemeGroupVersion, + &VolumeSnapshot{}, + &VolumeSnapshotList{}, + &VolumeSnapshotData{}, + &VolumeSnapshotDataList{}, + ) + metav1.AddToGroupVersion(scheme, SchemeGroupVersion) + return nil +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/types.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/types.go new file mode 100644 index 0000000000..7cdfac2e5d --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/types.go @@ -0,0 +1,291 @@ +/* +Copyright 2017 The Kubernetes Authors. + +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 v1 + +import ( + core_v1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" +) + +const ( + // VolumeSnapshotDataResourcePlural is "volumesnapshotdatas" + VolumeSnapshotDataResourcePlural = "volumesnapshotdatas" + // VolumeSnapshotResourcePlural is "volumesnapshots" + VolumeSnapshotResourcePlural = "volumesnapshots" +) + +// VolumeSnapshotStatus is the status of the VolumeSnapshot +type VolumeSnapshotStatus struct { + // The time the snapshot was successfully created + // +optional + CreationTimestamp metav1.Time `json:"creationTimestamp" protobuf:"bytes,1,opt,name=creationTimestamp"` + + // Represent the latest available observations about the volume snapshot + Conditions []VolumeSnapshotCondition `json:"conditions" protobuf:"bytes,2,rep,name=conditions"` +} + +// VolumeSnapshotConditionType is the type of VolumeSnapshot conditions +type VolumeSnapshotConditionType string + +// These are valid conditions of a volume snapshot. +const ( + // VolumeSnapshotConditionPending means the snapshot is cut and the application + // can resume accessing data if core_v1.ConditionStatus is True. It corresponds + // to "Uploading" in GCE PD or "Pending" in AWS and core_v1.ConditionStatus is True. + // It also corresponds to "Creating" in OpenStack Cinder and core_v1.ConditionStatus + // is Unknown. + VolumeSnapshotConditionPending VolumeSnapshotConditionType = "Pending" + // VolumeSnapshotConditionReady is added when the snapshot has been successfully created and is ready to be used. + VolumeSnapshotConditionReady VolumeSnapshotConditionType = "Ready" + // VolumeSnapshotConditionError means an error occurred during snapshot creation. + VolumeSnapshotConditionError VolumeSnapshotConditionType = "Error" +) + +// VolumeSnapshotCondition describes the state of a volume snapshot at a certain point. +type VolumeSnapshotCondition struct { + // Type of replication controller condition. + Type VolumeSnapshotConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=VolumeSnapshotConditionType"` + // Status of the condition, one of True, False, Unknown. + Status core_v1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"` + // The last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime" protobuf:"bytes,3,opt,name=lastTransitionTime"` + // The reason for the condition's last transition. + // +optional + Reason string `json:"reason" protobuf:"bytes,4,opt,name=reason"` + // A human readable message indicating details about the transition. + // +optional + Message string `json:"message" protobuf:"bytes,5,opt,name=message"` +} + +// +genclient +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeSnapshot is the volume snapshot object accessible to the user. Upon succesful creation of the actual +// snapshot by the volume provider it is bound to the corresponding VolumeSnapshotData through +// the VolumeSnapshotSpec +type VolumeSnapshot struct { + metav1.TypeMeta `json:",inline"` + metav1.ObjectMeta `json:"metadata"` + + // Spec represents the desired state of the snapshot + // +optional + Spec VolumeSnapshotSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` + + // Status represents the latest observer state of the snapshot + // +optional + Status VolumeSnapshotStatus `json:"status" protobuf:"bytes,3,opt,name=status"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeSnapshotList is a list of VolumeSnapshot objects +type VolumeSnapshotList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + Items []VolumeSnapshot `json:"items"` +} + +// VolumeSnapshotSpec is the desired state of the volume snapshot +type VolumeSnapshotSpec struct { + // PersistentVolumeClaimName is the name of the PVC being snapshotted + // +optional + PersistentVolumeClaimName string `json:"persistentVolumeClaimName" protobuf:"bytes,1,opt,name=persistentVolumeClaimName"` + + // SnapshotDataName binds the VolumeSnapshot object with the VolumeSnapshotData + // +optional + SnapshotDataName string `json:"snapshotDataName" protobuf:"bytes,2,opt,name=snapshotDataName"` +} + +// VolumeSnapshotDataStatus is the actual state of the volume snapshot +type VolumeSnapshotDataStatus struct { + // The time the snapshot was successfully created + // +optional + CreationTimestamp metav1.Time `json:"creationTimestamp" protobuf:"bytes,1,opt,name=creationTimestamp"` + + // Representes the lates available observations about the volume snapshot + Conditions []VolumeSnapshotDataCondition `json:"conditions" protobuf:"bytes,2,rep,name=conditions"` +} + +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeSnapshotDataList is a list of VolumeSnapshotData objects +type VolumeSnapshotDataList struct { + metav1.TypeMeta `json:",inline"` + metav1.ListMeta `json:"metadata"` + Items []VolumeSnapshotData `json:"items"` +} + +// VolumeSnapshotDataConditionType is the type of the VolumeSnapshotData condition +type VolumeSnapshotDataConditionType string + +// These are valid conditions of a volume snapshot. +const ( + // VolumeSnapshotDataReady is added when the on-disk snapshot has been successfully created. + VolumeSnapshotDataConditionReady VolumeSnapshotDataConditionType = "Ready" + // VolumeSnapshotDataPending is added when the on-disk snapshot has been successfully created but is not available to use. + VolumeSnapshotDataConditionPending VolumeSnapshotDataConditionType = "Pending" + // VolumeSnapshotDataError is added but the on-disk snapshot is failed to created + VolumeSnapshotDataConditionError VolumeSnapshotDataConditionType = "Error" +) + +// VolumeSnapshotDataCondition describes the state of a volume snapshot at a certain point. +type VolumeSnapshotDataCondition struct { + // Type of volume snapshot condition. + Type VolumeSnapshotDataConditionType `json:"type" protobuf:"bytes,1,opt,name=type,casttype=VolumeSnapshotDataConditionType"` + // Status of the condition, one of True, False, Unknown. + Status core_v1.ConditionStatus `json:"status" protobuf:"bytes,2,opt,name=status,casttype=ConditionStatus"` + // The last time the condition transitioned from one status to another. + // +optional + LastTransitionTime metav1.Time `json:"lastTransitionTime" protobuf:"bytes,3,opt,name=lastTransitionTime"` + // The reason for the condition's last transition. + // +optional + Reason string `json:"reason" protobuf:"bytes,4,opt,name=reason"` + // A human readable message indicating details about the transition. + // +optional + Message string `json:"message" protobuf:"bytes,5,opt,name=message"` +} + +// +genclient +// +genclient:nonNamespaced +// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object + +// VolumeSnapshotData represents the actual "on-disk" snapshot object +type VolumeSnapshotData struct { + metav1.TypeMeta `json:",inline"` + // +optional + metav1.ObjectMeta `json:"metadata"` + + // Spec represents the desired state of the snapshot + // +optional + Spec VolumeSnapshotDataSpec `json:"spec" protobuf:"bytes,2,opt,name=spec"` + + // Status represents the latest observed state of the snapshot + // +optional + Status VolumeSnapshotDataStatus `json:"status" protobuf:"bytes,3,opt,name=status"` +} + +// VolumeSnapshotDataSpec is the spec of the volume snapshot data +type VolumeSnapshotDataSpec struct { + // Source represents the location and type of the volume snapshot + VolumeSnapshotDataSource `json:",inline" protobuf:"bytes,1,opt,name=volumeSnapshotDataSource"` + + // VolumeSnapshotRef is part of bi-directional binding between VolumeSnapshot + // and VolumeSnapshotData + // +optional + VolumeSnapshotRef *core_v1.ObjectReference `json:"volumeSnapshotRef" protobuf:"bytes,2,opt,name=volumeSnapshotRef"` + + // PersistentVolumeRef represents the PersistentVolume that the snapshot has been + // taken from + // +optional + PersistentVolumeRef *core_v1.ObjectReference `json:"persistentVolumeRef" protobuf:"bytes,3,opt,name=persistentVolumeRef"` +} + +// HostPathVolumeSnapshotSource is HostPath volume snapshot source +type HostPathVolumeSnapshotSource struct { + // Path represents a tar file that stores the HostPath volume source + Path string `json:"snapshot"` +} + +// GlusterVolumeSnapshotSource is Gluster volume snapshot source +type GlusterVolumeSnapshotSource struct { + // UniqueID represents a snapshot resource. + SnapshotID string `json:"snapshotId"` +} + +// AWSElasticBlockStoreVolumeSnapshotSource is AWS EBS volume snapshot source +type AWSElasticBlockStoreVolumeSnapshotSource struct { + // Unique id of the persistent disk snapshot resource. Used to identify the disk snapshot in AWS + SnapshotID string `json:"snapshotId"` +} + +// CinderVolumeSnapshotSource is Cinder volume snapshot source +type CinderVolumeSnapshotSource struct { + // Unique id of the cinder volume snapshot resource. Used to identify the snapshot in OpenStack + SnapshotID string `json:"snapshotId"` +} + +// GCEPersistentDiskSnapshotSource is GCE PD volume snapshot source +type GCEPersistentDiskSnapshotSource struct { + // Unique id of the persistent disk snapshot resource. Used to identify the disk snapshot in GCE + SnapshotName string `json:"snapshotId"` +} + +// VolumeSnapshotDataSource represents the actual location and type of the snapshot. Only one of its members may be specified. +type VolumeSnapshotDataSource struct { + // HostPath represents a directory on the host. + // Provisioned by a developer or tester. + // This is useful for single-node development and testing only! + // On-host storage is not supported in any way and WILL NOT WORK in a multi-node cluster. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#hostpath + // +optional + HostPath *HostPathVolumeSnapshotSource `json:"hostPath,omitempty"` + // AWSElasticBlockStore represents an AWS Disk resource that is attached to a + // kubelet's host machine and then exposed to the pod. + // More info: https://kubernetes.io/docs/concepts/storage/volumes#awselasticblockstore + // +optional + //GlusterSnapshotSource represents a gluster snapshot resource + GlusterSnapshotVolume *GlusterVolumeSnapshotSource `json:"glusterSnapshotVolume,omitempty"` + // +optional + AWSElasticBlockStore *AWSElasticBlockStoreVolumeSnapshotSource `json:"awsElasticBlockStore,omitempty"` + // GCEPersistentDiskSnapshotSource represents an GCE PD snapshot resource + // +optional + GCEPersistentDiskSnapshot *GCEPersistentDiskSnapshotSource `json:"gcePersistentDisk,omitempty"` + // CinderVolumeSnapshotSource represents Cinder snapshot resource + // +optional + CinderSnapshot *CinderVolumeSnapshotSource `json:"cinderVolume,omitempty"` +} + +// GetSupportedVolumeFromPVSpec gets supported volume from PV spec +func GetSupportedVolumeFromPVSpec(spec *core_v1.PersistentVolumeSpec) string { + if spec.HostPath != nil { + return "hostPath" + } + if spec.AWSElasticBlockStore != nil { + return "aws_ebs" + } + if spec.GCEPersistentDisk != nil { + return "gce-pd" + } + if spec.Cinder != nil { + return "cinder" + } + if spec.Glusterfs != nil { + return "glusterfs" + } + return "" +} + +// GetSupportedVolumeFromSnapshotDataSpec gets supported volume from snapshot data spec +func GetSupportedVolumeFromSnapshotDataSpec(spec *VolumeSnapshotDataSpec) string { + if spec.HostPath != nil { + return "hostPath" + } + if spec.AWSElasticBlockStore != nil { + return "aws_ebs" + } + if spec.GCEPersistentDiskSnapshot != nil { + return "gce-pd" + } + if spec.CinderSnapshot != nil { + return "cinder" + } + if spec.GlusterSnapshotVolume != nil { + return "glusterfs" + } + return "" +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/zz_generated.deepcopy.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/zz_generated.deepcopy.go new file mode 100644 index 0000000000..0a0daf455b --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1/zz_generated.deepcopy.go @@ -0,0 +1,421 @@ +// +build !ignore_autogenerated + +/* +Copyright 2018 The Kubernetes Authors. + +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 deepcopy-gen. DO NOT EDIT. + +package v1 + +import ( + core_v1 "k8s.io/api/core/v1" + runtime "k8s.io/apimachinery/pkg/runtime" +) + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *AWSElasticBlockStoreVolumeSnapshotSource) DeepCopyInto(out *AWSElasticBlockStoreVolumeSnapshotSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSElasticBlockStoreVolumeSnapshotSource. +func (in *AWSElasticBlockStoreVolumeSnapshotSource) DeepCopy() *AWSElasticBlockStoreVolumeSnapshotSource { + if in == nil { + return nil + } + out := new(AWSElasticBlockStoreVolumeSnapshotSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *CinderVolumeSnapshotSource) DeepCopyInto(out *CinderVolumeSnapshotSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CinderVolumeSnapshotSource. +func (in *CinderVolumeSnapshotSource) DeepCopy() *CinderVolumeSnapshotSource { + if in == nil { + return nil + } + out := new(CinderVolumeSnapshotSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GCEPersistentDiskSnapshotSource) DeepCopyInto(out *GCEPersistentDiskSnapshotSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GCEPersistentDiskSnapshotSource. +func (in *GCEPersistentDiskSnapshotSource) DeepCopy() *GCEPersistentDiskSnapshotSource { + if in == nil { + return nil + } + out := new(GCEPersistentDiskSnapshotSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *GlusterVolumeSnapshotSource) DeepCopyInto(out *GlusterVolumeSnapshotSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GlusterVolumeSnapshotSource. +func (in *GlusterVolumeSnapshotSource) DeepCopy() *GlusterVolumeSnapshotSource { + if in == nil { + return nil + } + out := new(GlusterVolumeSnapshotSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *HostPathVolumeSnapshotSource) DeepCopyInto(out *HostPathVolumeSnapshotSource) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HostPathVolumeSnapshotSource. +func (in *HostPathVolumeSnapshotSource) DeepCopy() *HostPathVolumeSnapshotSource { + if in == nil { + return nil + } + out := new(HostPathVolumeSnapshotSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshot) DeepCopyInto(out *VolumeSnapshot) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + out.Spec = in.Spec + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshot. +func (in *VolumeSnapshot) DeepCopy() *VolumeSnapshot { + if in == nil { + return nil + } + out := new(VolumeSnapshot) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeSnapshot) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotCondition) DeepCopyInto(out *VolumeSnapshotCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotCondition. +func (in *VolumeSnapshotCondition) DeepCopy() *VolumeSnapshotCondition { + if in == nil { + return nil + } + out := new(VolumeSnapshotCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotData) DeepCopyInto(out *VolumeSnapshotData) { + *out = *in + out.TypeMeta = in.TypeMeta + in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) + in.Spec.DeepCopyInto(&out.Spec) + in.Status.DeepCopyInto(&out.Status) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotData. +func (in *VolumeSnapshotData) DeepCopy() *VolumeSnapshotData { + if in == nil { + return nil + } + out := new(VolumeSnapshotData) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeSnapshotData) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotDataCondition) DeepCopyInto(out *VolumeSnapshotDataCondition) { + *out = *in + in.LastTransitionTime.DeepCopyInto(&out.LastTransitionTime) + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotDataCondition. +func (in *VolumeSnapshotDataCondition) DeepCopy() *VolumeSnapshotDataCondition { + if in == nil { + return nil + } + out := new(VolumeSnapshotDataCondition) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotDataList) DeepCopyInto(out *VolumeSnapshotDataList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VolumeSnapshotData, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotDataList. +func (in *VolumeSnapshotDataList) DeepCopy() *VolumeSnapshotDataList { + if in == nil { + return nil + } + out := new(VolumeSnapshotDataList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeSnapshotDataList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotDataSource) DeepCopyInto(out *VolumeSnapshotDataSource) { + *out = *in + if in.HostPath != nil { + in, out := &in.HostPath, &out.HostPath + if *in == nil { + *out = nil + } else { + *out = new(HostPathVolumeSnapshotSource) + **out = **in + } + } + if in.GlusterSnapshotVolume != nil { + in, out := &in.GlusterSnapshotVolume, &out.GlusterSnapshotVolume + if *in == nil { + *out = nil + } else { + *out = new(GlusterVolumeSnapshotSource) + **out = **in + } + } + if in.AWSElasticBlockStore != nil { + in, out := &in.AWSElasticBlockStore, &out.AWSElasticBlockStore + if *in == nil { + *out = nil + } else { + *out = new(AWSElasticBlockStoreVolumeSnapshotSource) + **out = **in + } + } + if in.GCEPersistentDiskSnapshot != nil { + in, out := &in.GCEPersistentDiskSnapshot, &out.GCEPersistentDiskSnapshot + if *in == nil { + *out = nil + } else { + *out = new(GCEPersistentDiskSnapshotSource) + **out = **in + } + } + if in.CinderSnapshot != nil { + in, out := &in.CinderSnapshot, &out.CinderSnapshot + if *in == nil { + *out = nil + } else { + *out = new(CinderVolumeSnapshotSource) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotDataSource. +func (in *VolumeSnapshotDataSource) DeepCopy() *VolumeSnapshotDataSource { + if in == nil { + return nil + } + out := new(VolumeSnapshotDataSource) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotDataSpec) DeepCopyInto(out *VolumeSnapshotDataSpec) { + *out = *in + in.VolumeSnapshotDataSource.DeepCopyInto(&out.VolumeSnapshotDataSource) + if in.VolumeSnapshotRef != nil { + in, out := &in.VolumeSnapshotRef, &out.VolumeSnapshotRef + if *in == nil { + *out = nil + } else { + *out = new(core_v1.ObjectReference) + **out = **in + } + } + if in.PersistentVolumeRef != nil { + in, out := &in.PersistentVolumeRef, &out.PersistentVolumeRef + if *in == nil { + *out = nil + } else { + *out = new(core_v1.ObjectReference) + **out = **in + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotDataSpec. +func (in *VolumeSnapshotDataSpec) DeepCopy() *VolumeSnapshotDataSpec { + if in == nil { + return nil + } + out := new(VolumeSnapshotDataSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotDataStatus) DeepCopyInto(out *VolumeSnapshotDataStatus) { + *out = *in + in.CreationTimestamp.DeepCopyInto(&out.CreationTimestamp) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]VolumeSnapshotDataCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotDataStatus. +func (in *VolumeSnapshotDataStatus) DeepCopy() *VolumeSnapshotDataStatus { + if in == nil { + return nil + } + out := new(VolumeSnapshotDataStatus) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotList) DeepCopyInto(out *VolumeSnapshotList) { + *out = *in + out.TypeMeta = in.TypeMeta + out.ListMeta = in.ListMeta + if in.Items != nil { + in, out := &in.Items, &out.Items + *out = make([]VolumeSnapshot, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotList. +func (in *VolumeSnapshotList) DeepCopy() *VolumeSnapshotList { + if in == nil { + return nil + } + out := new(VolumeSnapshotList) + in.DeepCopyInto(out) + return out +} + +// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object. +func (in *VolumeSnapshotList) DeepCopyObject() runtime.Object { + if c := in.DeepCopy(); c != nil { + return c + } + return nil +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotSpec) DeepCopyInto(out *VolumeSnapshotSpec) { + *out = *in + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotSpec. +func (in *VolumeSnapshotSpec) DeepCopy() *VolumeSnapshotSpec { + if in == nil { + return nil + } + out := new(VolumeSnapshotSpec) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *VolumeSnapshotStatus) DeepCopyInto(out *VolumeSnapshotStatus) { + *out = *in + in.CreationTimestamp.DeepCopyInto(&out.CreationTimestamp) + if in.Conditions != nil { + in, out := &in.Conditions, &out.Conditions + *out = make([]VolumeSnapshotCondition, len(*in)) + for i := range *in { + (*in)[i].DeepCopyInto(&(*out)[i]) + } + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VolumeSnapshotStatus. +func (in *VolumeSnapshotStatus) DeepCopy() *VolumeSnapshotStatus { + if in == nil { + return nil + } + out := new(VolumeSnapshotStatus) + in.DeepCopyInto(out) + return out +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/clientset.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/clientset.go new file mode 100644 index 0000000000..aa791fad4e --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/clientset.go @@ -0,0 +1,97 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package versioned + +import ( + volumesnapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1" + discovery "k8s.io/client-go/discovery" + rest "k8s.io/client-go/rest" + flowcontrol "k8s.io/client-go/util/flowcontrol" +) + +type Interface interface { + Discovery() discovery.DiscoveryInterface + VolumesnapshotV1() volumesnapshotv1.VolumesnapshotV1Interface + // Deprecated: please explicitly pick a version if possible. + Volumesnapshot() volumesnapshotv1.VolumesnapshotV1Interface +} + +// Clientset contains the clients for groups. Each group has exactly one +// version included in a Clientset. +type Clientset struct { + *discovery.DiscoveryClient + volumesnapshotV1 *volumesnapshotv1.VolumesnapshotV1Client +} + +// VolumesnapshotV1 retrieves the VolumesnapshotV1Client +func (c *Clientset) VolumesnapshotV1() volumesnapshotv1.VolumesnapshotV1Interface { + return c.volumesnapshotV1 +} + +// Deprecated: Volumesnapshot retrieves the default version of VolumesnapshotClient. +// Please explicitly pick a version. +func (c *Clientset) Volumesnapshot() volumesnapshotv1.VolumesnapshotV1Interface { + return c.volumesnapshotV1 +} + +// Discovery retrieves the DiscoveryClient +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + if c == nil { + return nil + } + return c.DiscoveryClient +} + +// NewForConfig creates a new Clientset for the given config. +func NewForConfig(c *rest.Config) (*Clientset, error) { + configShallowCopy := *c + if configShallowCopy.RateLimiter == nil && configShallowCopy.QPS > 0 { + configShallowCopy.RateLimiter = flowcontrol.NewTokenBucketRateLimiter(configShallowCopy.QPS, configShallowCopy.Burst) + } + var cs Clientset + var err error + cs.volumesnapshotV1, err = volumesnapshotv1.NewForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + + cs.DiscoveryClient, err = discovery.NewDiscoveryClientForConfig(&configShallowCopy) + if err != nil { + return nil, err + } + return &cs, nil +} + +// NewForConfigOrDie creates a new Clientset for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *Clientset { + var cs Clientset + cs.volumesnapshotV1 = volumesnapshotv1.NewForConfigOrDie(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClientForConfigOrDie(c) + return &cs +} + +// New creates a new Clientset for the given RESTClient. +func New(c rest.Interface) *Clientset { + var cs Clientset + cs.volumesnapshotV1 = volumesnapshotv1.New(c) + + cs.DiscoveryClient = discovery.NewDiscoveryClient(c) + return &cs +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/doc.go new file mode 100644 index 0000000000..f823c268ba --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +// This package has the automatically generated clientset. +package versioned diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/clientset_generated.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/clientset_generated.go new file mode 100644 index 0000000000..1d85c4d7ac --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/clientset_generated.go @@ -0,0 +1,81 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package fake + +import ( + clientset "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + volumesnapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1" + fakevolumesnapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake" + "k8s.io/apimachinery/pkg/runtime" + "k8s.io/apimachinery/pkg/watch" + "k8s.io/client-go/discovery" + fakediscovery "k8s.io/client-go/discovery/fake" + "k8s.io/client-go/testing" +) + +// NewSimpleClientset returns a clientset that will respond with the provided objects. +// It's backed by a very simple object tracker that processes creates, updates and deletions as-is, +// without applying any validations and/or defaults. It shouldn't be considered a replacement +// for a real clientset and is mostly useful in simple unit tests. +func NewSimpleClientset(objects ...runtime.Object) *Clientset { + o := testing.NewObjectTracker(scheme, codecs.UniversalDecoder()) + for _, obj := range objects { + if err := o.Add(obj); err != nil { + panic(err) + } + } + + cs := &Clientset{} + cs.discovery = &fakediscovery.FakeDiscovery{Fake: &cs.Fake} + cs.AddReactor("*", "*", testing.ObjectReaction(o)) + cs.AddWatchReactor("*", func(action testing.Action) (handled bool, ret watch.Interface, err error) { + gvr := action.GetResource() + ns := action.GetNamespace() + watch, err := o.Watch(gvr, ns) + if err != nil { + return false, nil, err + } + return true, watch, nil + }) + + return cs +} + +// Clientset implements clientset.Interface. Meant to be embedded into a +// struct to get a default implementation. This makes faking out just the method +// you want to test easier. +type Clientset struct { + testing.Fake + discovery *fakediscovery.FakeDiscovery +} + +func (c *Clientset) Discovery() discovery.DiscoveryInterface { + return c.discovery +} + +var _ clientset.Interface = &Clientset{} + +// VolumesnapshotV1 retrieves the VolumesnapshotV1Client +func (c *Clientset) VolumesnapshotV1() volumesnapshotv1.VolumesnapshotV1Interface { + return &fakevolumesnapshotv1.FakeVolumesnapshotV1{Fake: &c.Fake} +} + +// Volumesnapshot retrieves the VolumesnapshotV1Client +func (c *Clientset) Volumesnapshot() volumesnapshotv1.VolumesnapshotV1Interface { + return &fakevolumesnapshotv1.FakeVolumesnapshotV1{Fake: &c.Fake} +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/doc.go new file mode 100644 index 0000000000..ab8ee5649c --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +// This package has the automatically generated fake clientset. +package fake diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/register.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/register.go new file mode 100644 index 0000000000..d4782ae66d --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/fake/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package fake + +import ( + volumesnapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var scheme = runtime.NewScheme() +var codecs = serializer.NewCodecFactory(scheme) +var parameterCodec = runtime.NewParameterCodec(scheme) + +func init() { + v1.AddToGroupVersion(scheme, schema.GroupVersion{Version: "v1"}) + AddToScheme(scheme) +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +func AddToScheme(scheme *runtime.Scheme) { + volumesnapshotv1.AddToScheme(scheme) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/doc.go new file mode 100644 index 0000000000..bbf42d167e --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +// This package contains the scheme of the automatically generated clientset. +package scheme diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/register.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/register.go new file mode 100644 index 0000000000..cc970a5145 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme/register.go @@ -0,0 +1,53 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package scheme + +import ( + volumesnapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" +) + +var Scheme = runtime.NewScheme() +var Codecs = serializer.NewCodecFactory(Scheme) +var ParameterCodec = runtime.NewParameterCodec(Scheme) + +func init() { + v1.AddToGroupVersion(Scheme, schema.GroupVersion{Version: "v1"}) + AddToScheme(Scheme) +} + +// AddToScheme adds all types of this clientset into the given scheme. This allows composition +// of clientsets, like in: +// +// import ( +// "k8s.io/client-go/kubernetes" +// clientsetscheme "k8s.io/client-go/kubernetes/scheme" +// aggregatorclientsetscheme "k8s.io/kube-aggregator/pkg/client/clientset_generated/clientset/scheme" +// ) +// +// kclientset, _ := kubernetes.NewForConfig(c) +// aggregatorclientsetscheme.AddToScheme(clientsetscheme.Scheme) +// +// After this, RawExtensions in Kubernetes types will serialize kube-aggregator types +// correctly. +func AddToScheme(scheme *runtime.Scheme) { + volumesnapshotv1.AddToScheme(scheme) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/doc.go new file mode 100644 index 0000000000..4f6dd5b4ad --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +// This package has the automatically generated typed clients. +package v1 diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/doc.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/doc.go new file mode 100644 index 0000000000..e4301c97e0 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/doc.go @@ -0,0 +1,19 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +// Package fake has the automatically generated clients. +package fake diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot.go new file mode 100644 index 0000000000..212463ed7c --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot.go @@ -0,0 +1,139 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package fake + +import ( + volumesnapshot_v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeVolumeSnapshots implements VolumeSnapshotInterface +type FakeVolumeSnapshots struct { + Fake *FakeVolumesnapshotV1 + ns string +} + +var volumesnapshotsResource = schema.GroupVersionResource{Group: "volumesnapshot.external-storage.k8s.io", Version: "v1", Resource: "volumesnapshots"} + +var volumesnapshotsKind = schema.GroupVersionKind{Group: "volumesnapshot.external-storage.k8s.io", Version: "v1", Kind: "VolumeSnapshot"} + +// Get takes name of the volumeSnapshot, and returns the corresponding volumeSnapshot object, and an error if there is any. +func (c *FakeVolumeSnapshots) Get(name string, options v1.GetOptions) (result *volumesnapshot_v1.VolumeSnapshot, err error) { + obj, err := c.Fake. + Invokes(testing.NewGetAction(volumesnapshotsResource, c.ns, name), &volumesnapshot_v1.VolumeSnapshot{}) + + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshot), err +} + +// List takes label and field selectors, and returns the list of VolumeSnapshots that match those selectors. +func (c *FakeVolumeSnapshots) List(opts v1.ListOptions) (result *volumesnapshot_v1.VolumeSnapshotList, err error) { + obj, err := c.Fake. + Invokes(testing.NewListAction(volumesnapshotsResource, volumesnapshotsKind, c.ns, opts), &volumesnapshot_v1.VolumeSnapshotList{}) + + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &volumesnapshot_v1.VolumeSnapshotList{ListMeta: obj.(*volumesnapshot_v1.VolumeSnapshotList).ListMeta} + for _, item := range obj.(*volumesnapshot_v1.VolumeSnapshotList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested volumeSnapshots. +func (c *FakeVolumeSnapshots) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewWatchAction(volumesnapshotsResource, c.ns, opts)) + +} + +// Create takes the representation of a volumeSnapshot and creates it. Returns the server's representation of the volumeSnapshot, and an error, if there is any. +func (c *FakeVolumeSnapshots) Create(volumeSnapshot *volumesnapshot_v1.VolumeSnapshot) (result *volumesnapshot_v1.VolumeSnapshot, err error) { + obj, err := c.Fake. + Invokes(testing.NewCreateAction(volumesnapshotsResource, c.ns, volumeSnapshot), &volumesnapshot_v1.VolumeSnapshot{}) + + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshot), err +} + +// Update takes the representation of a volumeSnapshot and updates it. Returns the server's representation of the volumeSnapshot, and an error, if there is any. +func (c *FakeVolumeSnapshots) Update(volumeSnapshot *volumesnapshot_v1.VolumeSnapshot) (result *volumesnapshot_v1.VolumeSnapshot, err error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateAction(volumesnapshotsResource, c.ns, volumeSnapshot), &volumesnapshot_v1.VolumeSnapshot{}) + + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshot), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeVolumeSnapshots) UpdateStatus(volumeSnapshot *volumesnapshot_v1.VolumeSnapshot) (*volumesnapshot_v1.VolumeSnapshot, error) { + obj, err := c.Fake. + Invokes(testing.NewUpdateSubresourceAction(volumesnapshotsResource, "status", c.ns, volumeSnapshot), &volumesnapshot_v1.VolumeSnapshot{}) + + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshot), err +} + +// Delete takes name of the volumeSnapshot and deletes it. Returns an error if one occurs. +func (c *FakeVolumeSnapshots) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewDeleteAction(volumesnapshotsResource, c.ns, name), &volumesnapshot_v1.VolumeSnapshot{}) + + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVolumeSnapshots) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewDeleteCollectionAction(volumesnapshotsResource, c.ns, listOptions) + + _, err := c.Fake.Invokes(action, &volumesnapshot_v1.VolumeSnapshotList{}) + return err +} + +// Patch applies the patch and returns the patched volumeSnapshot. +func (c *FakeVolumeSnapshots) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *volumesnapshot_v1.VolumeSnapshot, err error) { + obj, err := c.Fake. + Invokes(testing.NewPatchSubresourceAction(volumesnapshotsResource, c.ns, name, data, subresources...), &volumesnapshot_v1.VolumeSnapshot{}) + + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshot), err +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot_client.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot_client.go new file mode 100644 index 0000000000..ec070357b0 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshot_client.go @@ -0,0 +1,43 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package fake + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1" + rest "k8s.io/client-go/rest" + testing "k8s.io/client-go/testing" +) + +type FakeVolumesnapshotV1 struct { + *testing.Fake +} + +func (c *FakeVolumesnapshotV1) VolumeSnapshots(namespace string) v1.VolumeSnapshotInterface { + return &FakeVolumeSnapshots{c, namespace} +} + +func (c *FakeVolumesnapshotV1) VolumeSnapshotDatas() v1.VolumeSnapshotDataInterface { + return &FakeVolumeSnapshotDatas{c} +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *FakeVolumesnapshotV1) RESTClient() rest.Interface { + var ret *rest.RESTClient + return ret +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshotdata.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshotdata.go new file mode 100644 index 0000000000..896d0ff4cd --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/fake/fake_volumesnapshotdata.go @@ -0,0 +1,130 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package fake + +import ( + volumesnapshot_v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + labels "k8s.io/apimachinery/pkg/labels" + schema "k8s.io/apimachinery/pkg/runtime/schema" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + testing "k8s.io/client-go/testing" +) + +// FakeVolumeSnapshotDatas implements VolumeSnapshotDataInterface +type FakeVolumeSnapshotDatas struct { + Fake *FakeVolumesnapshotV1 +} + +var volumesnapshotdatasResource = schema.GroupVersionResource{Group: "volumesnapshot.external-storage.k8s.io", Version: "v1", Resource: "volumesnapshotdatas"} + +var volumesnapshotdatasKind = schema.GroupVersionKind{Group: "volumesnapshot.external-storage.k8s.io", Version: "v1", Kind: "VolumeSnapshotData"} + +// Get takes name of the volumeSnapshotData, and returns the corresponding volumeSnapshotData object, and an error if there is any. +func (c *FakeVolumeSnapshotDatas) Get(name string, options v1.GetOptions) (result *volumesnapshot_v1.VolumeSnapshotData, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootGetAction(volumesnapshotdatasResource, name), &volumesnapshot_v1.VolumeSnapshotData{}) + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshotData), err +} + +// List takes label and field selectors, and returns the list of VolumeSnapshotDatas that match those selectors. +func (c *FakeVolumeSnapshotDatas) List(opts v1.ListOptions) (result *volumesnapshot_v1.VolumeSnapshotDataList, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootListAction(volumesnapshotdatasResource, volumesnapshotdatasKind, opts), &volumesnapshot_v1.VolumeSnapshotDataList{}) + if obj == nil { + return nil, err + } + + label, _, _ := testing.ExtractFromListOptions(opts) + if label == nil { + label = labels.Everything() + } + list := &volumesnapshot_v1.VolumeSnapshotDataList{ListMeta: obj.(*volumesnapshot_v1.VolumeSnapshotDataList).ListMeta} + for _, item := range obj.(*volumesnapshot_v1.VolumeSnapshotDataList).Items { + if label.Matches(labels.Set(item.Labels)) { + list.Items = append(list.Items, item) + } + } + return list, err +} + +// Watch returns a watch.Interface that watches the requested volumeSnapshotDatas. +func (c *FakeVolumeSnapshotDatas) Watch(opts v1.ListOptions) (watch.Interface, error) { + return c.Fake. + InvokesWatch(testing.NewRootWatchAction(volumesnapshotdatasResource, opts)) +} + +// Create takes the representation of a volumeSnapshotData and creates it. Returns the server's representation of the volumeSnapshotData, and an error, if there is any. +func (c *FakeVolumeSnapshotDatas) Create(volumeSnapshotData *volumesnapshot_v1.VolumeSnapshotData) (result *volumesnapshot_v1.VolumeSnapshotData, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootCreateAction(volumesnapshotdatasResource, volumeSnapshotData), &volumesnapshot_v1.VolumeSnapshotData{}) + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshotData), err +} + +// Update takes the representation of a volumeSnapshotData and updates it. Returns the server's representation of the volumeSnapshotData, and an error, if there is any. +func (c *FakeVolumeSnapshotDatas) Update(volumeSnapshotData *volumesnapshot_v1.VolumeSnapshotData) (result *volumesnapshot_v1.VolumeSnapshotData, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateAction(volumesnapshotdatasResource, volumeSnapshotData), &volumesnapshot_v1.VolumeSnapshotData{}) + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshotData), err +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). +func (c *FakeVolumeSnapshotDatas) UpdateStatus(volumeSnapshotData *volumesnapshot_v1.VolumeSnapshotData) (*volumesnapshot_v1.VolumeSnapshotData, error) { + obj, err := c.Fake. + Invokes(testing.NewRootUpdateSubresourceAction(volumesnapshotdatasResource, "status", volumeSnapshotData), &volumesnapshot_v1.VolumeSnapshotData{}) + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshotData), err +} + +// Delete takes name of the volumeSnapshotData and deletes it. Returns an error if one occurs. +func (c *FakeVolumeSnapshotDatas) Delete(name string, options *v1.DeleteOptions) error { + _, err := c.Fake. + Invokes(testing.NewRootDeleteAction(volumesnapshotdatasResource, name), &volumesnapshot_v1.VolumeSnapshotData{}) + return err +} + +// DeleteCollection deletes a collection of objects. +func (c *FakeVolumeSnapshotDatas) DeleteCollection(options *v1.DeleteOptions, listOptions v1.ListOptions) error { + action := testing.NewRootDeleteCollectionAction(volumesnapshotdatasResource, listOptions) + + _, err := c.Fake.Invokes(action, &volumesnapshot_v1.VolumeSnapshotDataList{}) + return err +} + +// Patch applies the patch and returns the patched volumeSnapshotData. +func (c *FakeVolumeSnapshotDatas) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *volumesnapshot_v1.VolumeSnapshotData, err error) { + obj, err := c.Fake. + Invokes(testing.NewRootPatchSubresourceAction(volumesnapshotdatasResource, name, data, subresources...), &volumesnapshot_v1.VolumeSnapshotData{}) + if obj == nil { + return nil, err + } + return obj.(*volumesnapshot_v1.VolumeSnapshotData), err +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/generated_expansion.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/generated_expansion.go new file mode 100644 index 0000000000..bb5847dfd6 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/generated_expansion.go @@ -0,0 +1,22 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package v1 + +type VolumeSnapshotExpansion interface{} + +type VolumeSnapshotDataExpansion interface{} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot.go new file mode 100644 index 0000000000..6b32bc34fe --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot.go @@ -0,0 +1,173 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + scheme "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// VolumeSnapshotsGetter has a method to return a VolumeSnapshotInterface. +// A group's client should implement this interface. +type VolumeSnapshotsGetter interface { + VolumeSnapshots(namespace string) VolumeSnapshotInterface +} + +// VolumeSnapshotInterface has methods to work with VolumeSnapshot resources. +type VolumeSnapshotInterface interface { + Create(*v1.VolumeSnapshot) (*v1.VolumeSnapshot, error) + Update(*v1.VolumeSnapshot) (*v1.VolumeSnapshot, error) + UpdateStatus(*v1.VolumeSnapshot) (*v1.VolumeSnapshot, error) + Delete(name string, options *meta_v1.DeleteOptions) error + DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error + Get(name string, options meta_v1.GetOptions) (*v1.VolumeSnapshot, error) + List(opts meta_v1.ListOptions) (*v1.VolumeSnapshotList, error) + Watch(opts meta_v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VolumeSnapshot, err error) + VolumeSnapshotExpansion +} + +// volumeSnapshots implements VolumeSnapshotInterface +type volumeSnapshots struct { + client rest.Interface + ns string +} + +// newVolumeSnapshots returns a VolumeSnapshots +func newVolumeSnapshots(c *VolumesnapshotV1Client, namespace string) *volumeSnapshots { + return &volumeSnapshots{ + client: c.RESTClient(), + ns: namespace, + } +} + +// Get takes name of the volumeSnapshot, and returns the corresponding volumeSnapshot object, and an error if there is any. +func (c *volumeSnapshots) Get(name string, options meta_v1.GetOptions) (result *v1.VolumeSnapshot, err error) { + result = &v1.VolumeSnapshot{} + err = c.client.Get(). + Namespace(c.ns). + Resource("volumesnapshots"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of VolumeSnapshots that match those selectors. +func (c *volumeSnapshots) List(opts meta_v1.ListOptions) (result *v1.VolumeSnapshotList, err error) { + result = &v1.VolumeSnapshotList{} + err = c.client.Get(). + Namespace(c.ns). + Resource("volumesnapshots"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested volumeSnapshots. +func (c *volumeSnapshots) Watch(opts meta_v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Namespace(c.ns). + Resource("volumesnapshots"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a volumeSnapshot and creates it. Returns the server's representation of the volumeSnapshot, and an error, if there is any. +func (c *volumeSnapshots) Create(volumeSnapshot *v1.VolumeSnapshot) (result *v1.VolumeSnapshot, err error) { + result = &v1.VolumeSnapshot{} + err = c.client.Post(). + Namespace(c.ns). + Resource("volumesnapshots"). + Body(volumeSnapshot). + Do(). + Into(result) + return +} + +// Update takes the representation of a volumeSnapshot and updates it. Returns the server's representation of the volumeSnapshot, and an error, if there is any. +func (c *volumeSnapshots) Update(volumeSnapshot *v1.VolumeSnapshot) (result *v1.VolumeSnapshot, err error) { + result = &v1.VolumeSnapshot{} + err = c.client.Put(). + Namespace(c.ns). + Resource("volumesnapshots"). + Name(volumeSnapshot.Name). + Body(volumeSnapshot). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *volumeSnapshots) UpdateStatus(volumeSnapshot *v1.VolumeSnapshot) (result *v1.VolumeSnapshot, err error) { + result = &v1.VolumeSnapshot{} + err = c.client.Put(). + Namespace(c.ns). + Resource("volumesnapshots"). + Name(volumeSnapshot.Name). + SubResource("status"). + Body(volumeSnapshot). + Do(). + Into(result) + return +} + +// Delete takes name of the volumeSnapshot and deletes it. Returns an error if one occurs. +func (c *volumeSnapshots) Delete(name string, options *meta_v1.DeleteOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("volumesnapshots"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *volumeSnapshots) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error { + return c.client.Delete(). + Namespace(c.ns). + Resource("volumesnapshots"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched volumeSnapshot. +func (c *volumeSnapshots) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VolumeSnapshot, err error) { + result = &v1.VolumeSnapshot{} + err = c.client.Patch(pt). + Namespace(c.ns). + Resource("volumesnapshots"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot_client.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot_client.go new file mode 100644 index 0000000000..4b4f132465 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshot_client.go @@ -0,0 +1,94 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme" + serializer "k8s.io/apimachinery/pkg/runtime/serializer" + rest "k8s.io/client-go/rest" +) + +type VolumesnapshotV1Interface interface { + RESTClient() rest.Interface + VolumeSnapshotsGetter + VolumeSnapshotDatasGetter +} + +// VolumesnapshotV1Client is used to interact with features provided by the volumesnapshot.external-storage.k8s.io group. +type VolumesnapshotV1Client struct { + restClient rest.Interface +} + +func (c *VolumesnapshotV1Client) VolumeSnapshots(namespace string) VolumeSnapshotInterface { + return newVolumeSnapshots(c, namespace) +} + +func (c *VolumesnapshotV1Client) VolumeSnapshotDatas() VolumeSnapshotDataInterface { + return newVolumeSnapshotDatas(c) +} + +// NewForConfig creates a new VolumesnapshotV1Client for the given config. +func NewForConfig(c *rest.Config) (*VolumesnapshotV1Client, error) { + config := *c + if err := setConfigDefaults(&config); err != nil { + return nil, err + } + client, err := rest.RESTClientFor(&config) + if err != nil { + return nil, err + } + return &VolumesnapshotV1Client{client}, nil +} + +// NewForConfigOrDie creates a new VolumesnapshotV1Client for the given config and +// panics if there is an error in the config. +func NewForConfigOrDie(c *rest.Config) *VolumesnapshotV1Client { + client, err := NewForConfig(c) + if err != nil { + panic(err) + } + return client +} + +// New creates a new VolumesnapshotV1Client for the given RESTClient. +func New(c rest.Interface) *VolumesnapshotV1Client { + return &VolumesnapshotV1Client{c} +} + +func setConfigDefaults(config *rest.Config) error { + gv := v1.SchemeGroupVersion + config.GroupVersion = &gv + config.APIPath = "/apis" + config.NegotiatedSerializer = serializer.DirectCodecFactory{CodecFactory: scheme.Codecs} + + if config.UserAgent == "" { + config.UserAgent = rest.DefaultKubernetesUserAgent() + } + + return nil +} + +// RESTClient returns a RESTClient that is used to communicate +// with API server by this client implementation. +func (c *VolumesnapshotV1Client) RESTClient() rest.Interface { + if c == nil { + return nil + } + return c.restClient +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshotdata.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshotdata.go new file mode 100644 index 0000000000..73a841a6c2 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/typed/volumesnapshot/v1/volumesnapshotdata.go @@ -0,0 +1,162 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 client-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + scheme "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned/scheme" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + types "k8s.io/apimachinery/pkg/types" + watch "k8s.io/apimachinery/pkg/watch" + rest "k8s.io/client-go/rest" +) + +// VolumeSnapshotDatasGetter has a method to return a VolumeSnapshotDataInterface. +// A group's client should implement this interface. +type VolumeSnapshotDatasGetter interface { + VolumeSnapshotDatas() VolumeSnapshotDataInterface +} + +// VolumeSnapshotDataInterface has methods to work with VolumeSnapshotData resources. +type VolumeSnapshotDataInterface interface { + Create(*v1.VolumeSnapshotData) (*v1.VolumeSnapshotData, error) + Update(*v1.VolumeSnapshotData) (*v1.VolumeSnapshotData, error) + UpdateStatus(*v1.VolumeSnapshotData) (*v1.VolumeSnapshotData, error) + Delete(name string, options *meta_v1.DeleteOptions) error + DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error + Get(name string, options meta_v1.GetOptions) (*v1.VolumeSnapshotData, error) + List(opts meta_v1.ListOptions) (*v1.VolumeSnapshotDataList, error) + Watch(opts meta_v1.ListOptions) (watch.Interface, error) + Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VolumeSnapshotData, err error) + VolumeSnapshotDataExpansion +} + +// volumeSnapshotDatas implements VolumeSnapshotDataInterface +type volumeSnapshotDatas struct { + client rest.Interface +} + +// newVolumeSnapshotDatas returns a VolumeSnapshotDatas +func newVolumeSnapshotDatas(c *VolumesnapshotV1Client) *volumeSnapshotDatas { + return &volumeSnapshotDatas{ + client: c.RESTClient(), + } +} + +// Get takes name of the volumeSnapshotData, and returns the corresponding volumeSnapshotData object, and an error if there is any. +func (c *volumeSnapshotDatas) Get(name string, options meta_v1.GetOptions) (result *v1.VolumeSnapshotData, err error) { + result = &v1.VolumeSnapshotData{} + err = c.client.Get(). + Resource("volumesnapshotdatas"). + Name(name). + VersionedParams(&options, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// List takes label and field selectors, and returns the list of VolumeSnapshotDatas that match those selectors. +func (c *volumeSnapshotDatas) List(opts meta_v1.ListOptions) (result *v1.VolumeSnapshotDataList, err error) { + result = &v1.VolumeSnapshotDataList{} + err = c.client.Get(). + Resource("volumesnapshotdatas"). + VersionedParams(&opts, scheme.ParameterCodec). + Do(). + Into(result) + return +} + +// Watch returns a watch.Interface that watches the requested volumeSnapshotDatas. +func (c *volumeSnapshotDatas) Watch(opts meta_v1.ListOptions) (watch.Interface, error) { + opts.Watch = true + return c.client.Get(). + Resource("volumesnapshotdatas"). + VersionedParams(&opts, scheme.ParameterCodec). + Watch() +} + +// Create takes the representation of a volumeSnapshotData and creates it. Returns the server's representation of the volumeSnapshotData, and an error, if there is any. +func (c *volumeSnapshotDatas) Create(volumeSnapshotData *v1.VolumeSnapshotData) (result *v1.VolumeSnapshotData, err error) { + result = &v1.VolumeSnapshotData{} + err = c.client.Post(). + Resource("volumesnapshotdatas"). + Body(volumeSnapshotData). + Do(). + Into(result) + return +} + +// Update takes the representation of a volumeSnapshotData and updates it. Returns the server's representation of the volumeSnapshotData, and an error, if there is any. +func (c *volumeSnapshotDatas) Update(volumeSnapshotData *v1.VolumeSnapshotData) (result *v1.VolumeSnapshotData, err error) { + result = &v1.VolumeSnapshotData{} + err = c.client.Put(). + Resource("volumesnapshotdatas"). + Name(volumeSnapshotData.Name). + Body(volumeSnapshotData). + Do(). + Into(result) + return +} + +// UpdateStatus was generated because the type contains a Status member. +// Add a +genclient:noStatus comment above the type to avoid generating UpdateStatus(). + +func (c *volumeSnapshotDatas) UpdateStatus(volumeSnapshotData *v1.VolumeSnapshotData) (result *v1.VolumeSnapshotData, err error) { + result = &v1.VolumeSnapshotData{} + err = c.client.Put(). + Resource("volumesnapshotdatas"). + Name(volumeSnapshotData.Name). + SubResource("status"). + Body(volumeSnapshotData). + Do(). + Into(result) + return +} + +// Delete takes name of the volumeSnapshotData and deletes it. Returns an error if one occurs. +func (c *volumeSnapshotDatas) Delete(name string, options *meta_v1.DeleteOptions) error { + return c.client.Delete(). + Resource("volumesnapshotdatas"). + Name(name). + Body(options). + Do(). + Error() +} + +// DeleteCollection deletes a collection of objects. +func (c *volumeSnapshotDatas) DeleteCollection(options *meta_v1.DeleteOptions, listOptions meta_v1.ListOptions) error { + return c.client.Delete(). + Resource("volumesnapshotdatas"). + VersionedParams(&listOptions, scheme.ParameterCodec). + Body(options). + Do(). + Error() +} + +// Patch applies the patch and returns the patched volumeSnapshotData. +func (c *volumeSnapshotDatas) Patch(name string, pt types.PatchType, data []byte, subresources ...string) (result *v1.VolumeSnapshotData, err error) { + result = &v1.VolumeSnapshotData{} + err = c.client.Patch(pt). + Resource("volumesnapshotdatas"). + SubResource(subresources...). + Name(name). + Body(data). + Do(). + Into(result) + return +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/factory.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/factory.go new file mode 100644 index 0000000000..44f6a2df94 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/factory.go @@ -0,0 +1,179 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package externalversions + +import ( + reflect "reflect" + sync "sync" + time "time" + + versioned "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + internalinterfaces "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces" + volumesnapshot "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// SharedInformerOption defines the functional option type for SharedInformerFactory. +type SharedInformerOption func(*sharedInformerFactory) *sharedInformerFactory + +type sharedInformerFactory struct { + client versioned.Interface + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc + lock sync.Mutex + defaultResync time.Duration + customResync map[reflect.Type]time.Duration + + informers map[reflect.Type]cache.SharedIndexInformer + // startedInformers is used for tracking which informers have been started. + // This allows Start() to be called multiple times safely. + startedInformers map[reflect.Type]bool +} + +// WithCustomResyncConfig sets a custom resync period for the specified informer types. +func WithCustomResyncConfig(resyncConfig map[v1.Object]time.Duration) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + for k, v := range resyncConfig { + factory.customResync[reflect.TypeOf(k)] = v + } + return factory + } +} + +// WithTweakListOptions sets a custom filter on all listers of the configured SharedInformerFactory. +func WithTweakListOptions(tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.tweakListOptions = tweakListOptions + return factory + } +} + +// WithNamespace limits the SharedInformerFactory to the specified namespace. +func WithNamespace(namespace string) SharedInformerOption { + return func(factory *sharedInformerFactory) *sharedInformerFactory { + factory.namespace = namespace + return factory + } +} + +// NewSharedInformerFactory constructs a new instance of sharedInformerFactory for all namespaces. +func NewSharedInformerFactory(client versioned.Interface, defaultResync time.Duration) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync) +} + +// NewFilteredSharedInformerFactory constructs a new instance of sharedInformerFactory. +// Listers obtained via this SharedInformerFactory will be subject to the same filters +// as specified here. +// Deprecated: Please use NewSharedInformerFactoryWithOptions instead +func NewFilteredSharedInformerFactory(client versioned.Interface, defaultResync time.Duration, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) SharedInformerFactory { + return NewSharedInformerFactoryWithOptions(client, defaultResync, WithNamespace(namespace), WithTweakListOptions(tweakListOptions)) +} + +// NewSharedInformerFactoryWithOptions constructs a new instance of a SharedInformerFactory with additional options. +func NewSharedInformerFactoryWithOptions(client versioned.Interface, defaultResync time.Duration, options ...SharedInformerOption) SharedInformerFactory { + factory := &sharedInformerFactory{ + client: client, + namespace: v1.NamespaceAll, + defaultResync: defaultResync, + informers: make(map[reflect.Type]cache.SharedIndexInformer), + startedInformers: make(map[reflect.Type]bool), + customResync: make(map[reflect.Type]time.Duration), + } + + // Apply all options + for _, opt := range options { + factory = opt(factory) + } + + return factory +} + +// Start initializes all requested informers. +func (f *sharedInformerFactory) Start(stopCh <-chan struct{}) { + f.lock.Lock() + defer f.lock.Unlock() + + for informerType, informer := range f.informers { + if !f.startedInformers[informerType] { + go informer.Run(stopCh) + f.startedInformers[informerType] = true + } + } +} + +// WaitForCacheSync waits for all started informers' cache were synced. +func (f *sharedInformerFactory) WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool { + informers := func() map[reflect.Type]cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informers := map[reflect.Type]cache.SharedIndexInformer{} + for informerType, informer := range f.informers { + if f.startedInformers[informerType] { + informers[informerType] = informer + } + } + return informers + }() + + res := map[reflect.Type]bool{} + for informType, informer := range informers { + res[informType] = cache.WaitForCacheSync(stopCh, informer.HasSynced) + } + return res +} + +// InternalInformerFor returns the SharedIndexInformer for obj using an internal +// client. +func (f *sharedInformerFactory) InformerFor(obj runtime.Object, newFunc internalinterfaces.NewInformerFunc) cache.SharedIndexInformer { + f.lock.Lock() + defer f.lock.Unlock() + + informerType := reflect.TypeOf(obj) + informer, exists := f.informers[informerType] + if exists { + return informer + } + + resyncPeriod, exists := f.customResync[informerType] + if !exists { + resyncPeriod = f.defaultResync + } + + informer = newFunc(f.client, resyncPeriod) + f.informers[informerType] = informer + + return informer +} + +// SharedInformerFactory provides shared informers for resources in all known +// API group versions. +type SharedInformerFactory interface { + internalinterfaces.SharedInformerFactory + ForResource(resource schema.GroupVersionResource) (GenericInformer, error) + WaitForCacheSync(stopCh <-chan struct{}) map[reflect.Type]bool + + Volumesnapshot() volumesnapshot.Interface +} + +func (f *sharedInformerFactory) Volumesnapshot() volumesnapshot.Interface { + return volumesnapshot.New(f, f.namespace, f.tweakListOptions) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/generic.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/generic.go new file mode 100644 index 0000000000..ec54d45dcf --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/generic.go @@ -0,0 +1,63 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package externalversions + +import ( + "fmt" + + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + schema "k8s.io/apimachinery/pkg/runtime/schema" + cache "k8s.io/client-go/tools/cache" +) + +// GenericInformer is type of SharedIndexInformer which will locate and delegate to other +// sharedInformers based on type +type GenericInformer interface { + Informer() cache.SharedIndexInformer + Lister() cache.GenericLister +} + +type genericInformer struct { + informer cache.SharedIndexInformer + resource schema.GroupResource +} + +// Informer returns the SharedIndexInformer. +func (f *genericInformer) Informer() cache.SharedIndexInformer { + return f.informer +} + +// Lister returns the GenericLister. +func (f *genericInformer) Lister() cache.GenericLister { + return cache.NewGenericLister(f.Informer().GetIndexer(), f.resource) +} + +// ForResource gives generic access to a shared informer of the matching type +// TODO extend this to unknown resources with a client pool +func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { + switch resource { + // Group=volumesnapshot.external-storage.k8s.io, Version=v1 + case v1.SchemeGroupVersion.WithResource("volumesnapshots"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Volumesnapshot().V1().VolumeSnapshots().Informer()}, nil + case v1.SchemeGroupVersion.WithResource("volumesnapshotdatas"): + return &genericInformer{resource: resource.GroupResource(), informer: f.Volumesnapshot().V1().VolumeSnapshotDatas().Informer()}, nil + + } + + return nil, fmt.Errorf("no informer found for %v", resource) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go new file mode 100644 index 0000000000..b268774211 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces/factory_interfaces.go @@ -0,0 +1,37 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package internalinterfaces + +import ( + time "time" + + versioned "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + cache "k8s.io/client-go/tools/cache" +) + +type NewInformerFunc func(versioned.Interface, time.Duration) cache.SharedIndexInformer + +// SharedInformerFactory a small interface to allow for adding an informer without an import cycle +type SharedInformerFactory interface { + Start(stopCh <-chan struct{}) + InformerFor(obj runtime.Object, newFunc NewInformerFunc) cache.SharedIndexInformer +} + +type TweakListOptionsFunc func(*v1.ListOptions) diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/interface.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/interface.go new file mode 100644 index 0000000000..190144e563 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/interface.go @@ -0,0 +1,45 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package volumesnapshot + +import ( + internalinterfaces "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1" +) + +// Interface provides access to each of this group's versions. +type Interface interface { + // V1 provides access to shared informers for resources in V1. + V1() v1.Interface +} + +type group struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &group{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// V1 returns a new v1.Interface. +func (g *group) V1() v1.Interface { + return v1.New(g.factory, g.namespace, g.tweakListOptions) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/interface.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/interface.go new file mode 100644 index 0000000000..51fec6ff61 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/interface.go @@ -0,0 +1,51 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + internalinterfaces "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces" +) + +// Interface provides access to all the informers in this group version. +type Interface interface { + // VolumeSnapshots returns a VolumeSnapshotInformer. + VolumeSnapshots() VolumeSnapshotInformer + // VolumeSnapshotDatas returns a VolumeSnapshotDataInformer. + VolumeSnapshotDatas() VolumeSnapshotDataInformer +} + +type version struct { + factory internalinterfaces.SharedInformerFactory + namespace string + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// New returns a new Interface. +func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakListOptions internalinterfaces.TweakListOptionsFunc) Interface { + return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} +} + +// VolumeSnapshots returns a VolumeSnapshotInformer. +func (v *version) VolumeSnapshots() VolumeSnapshotInformer { + return &volumeSnapshotInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} +} + +// VolumeSnapshotDatas returns a VolumeSnapshotDataInformer. +func (v *version) VolumeSnapshotDatas() VolumeSnapshotDataInformer { + return &volumeSnapshotDataInformer{factory: v.factory, tweakListOptions: v.tweakListOptions} +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshot.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshot.go new file mode 100644 index 0000000000..c922e34cae --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshot.go @@ -0,0 +1,88 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + volumesnapshot_v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + versioned "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + internalinterfaces "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VolumeSnapshotInformer provides access to a shared informer and lister for +// VolumeSnapshots. +type VolumeSnapshotInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.VolumeSnapshotLister +} + +type volumeSnapshotInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc + namespace string +} + +// NewVolumeSnapshotInformer constructs a new informer for VolumeSnapshot type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVolumeSnapshotInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVolumeSnapshotInformer(client, namespace, resyncPeriod, indexers, nil) +} + +// NewFilteredVolumeSnapshotInformer constructs a new informer for VolumeSnapshot type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVolumeSnapshotInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VolumesnapshotV1().VolumeSnapshots(namespace).List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VolumesnapshotV1().VolumeSnapshots(namespace).Watch(options) + }, + }, + &volumesnapshot_v1.VolumeSnapshot{}, + resyncPeriod, + indexers, + ) +} + +func (f *volumeSnapshotInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVolumeSnapshotInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *volumeSnapshotInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&volumesnapshot_v1.VolumeSnapshot{}, f.defaultInformer) +} + +func (f *volumeSnapshotInformer) Lister() v1.VolumeSnapshotLister { + return v1.NewVolumeSnapshotLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshotdata.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshotdata.go new file mode 100644 index 0000000000..abc8cbbdba --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/volumesnapshot/v1/volumesnapshotdata.go @@ -0,0 +1,87 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 informer-gen. DO NOT EDIT. + +package v1 + +import ( + time "time" + + volumesnapshot_v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + versioned "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + internalinterfaces "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/informers/externalversions/internalinterfaces" + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1" + meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + runtime "k8s.io/apimachinery/pkg/runtime" + watch "k8s.io/apimachinery/pkg/watch" + cache "k8s.io/client-go/tools/cache" +) + +// VolumeSnapshotDataInformer provides access to a shared informer and lister for +// VolumeSnapshotDatas. +type VolumeSnapshotDataInformer interface { + Informer() cache.SharedIndexInformer + Lister() v1.VolumeSnapshotDataLister +} + +type volumeSnapshotDataInformer struct { + factory internalinterfaces.SharedInformerFactory + tweakListOptions internalinterfaces.TweakListOptionsFunc +} + +// NewVolumeSnapshotDataInformer constructs a new informer for VolumeSnapshotData type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewVolumeSnapshotDataInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer { + return NewFilteredVolumeSnapshotDataInformer(client, resyncPeriod, indexers, nil) +} + +// NewFilteredVolumeSnapshotDataInformer constructs a new informer for VolumeSnapshotData type. +// Always prefer using an informer factory to get a shared informer instead of getting an independent +// one. This reduces memory footprint and number of connections to the server. +func NewFilteredVolumeSnapshotDataInformer(client versioned.Interface, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer { + return cache.NewSharedIndexInformer( + &cache.ListWatch{ + ListFunc: func(options meta_v1.ListOptions) (runtime.Object, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VolumesnapshotV1().VolumeSnapshotDatas().List(options) + }, + WatchFunc: func(options meta_v1.ListOptions) (watch.Interface, error) { + if tweakListOptions != nil { + tweakListOptions(&options) + } + return client.VolumesnapshotV1().VolumeSnapshotDatas().Watch(options) + }, + }, + &volumesnapshot_v1.VolumeSnapshotData{}, + resyncPeriod, + indexers, + ) +} + +func (f *volumeSnapshotDataInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer { + return NewFilteredVolumeSnapshotDataInformer(client, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions) +} + +func (f *volumeSnapshotDataInformer) Informer() cache.SharedIndexInformer { + return f.factory.InformerFor(&volumesnapshot_v1.VolumeSnapshotData{}, f.defaultInformer) +} + +func (f *volumeSnapshotDataInformer) Lister() v1.VolumeSnapshotDataLister { + return v1.NewVolumeSnapshotDataLister(f.Informer().GetIndexer()) +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/expansion_generated.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/expansion_generated.go new file mode 100644 index 0000000000..aad5ad5d58 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/expansion_generated.go @@ -0,0 +1,30 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 lister-gen. DO NOT EDIT. + +package v1 + +// VolumeSnapshotListerExpansion allows custom methods to be added to +// VolumeSnapshotLister. +type VolumeSnapshotListerExpansion interface{} + +// VolumeSnapshotNamespaceListerExpansion allows custom methods to be added to +// VolumeSnapshotNamespaceLister. +type VolumeSnapshotNamespaceListerExpansion interface{} + +// VolumeSnapshotDataListerExpansion allows custom methods to be added to +// VolumeSnapshotDataLister. +type VolumeSnapshotDataListerExpansion interface{} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshot.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshot.go new file mode 100644 index 0000000000..e977248fc8 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshot.go @@ -0,0 +1,93 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// VolumeSnapshotLister helps list VolumeSnapshots. +type VolumeSnapshotLister interface { + // List lists all VolumeSnapshots in the indexer. + List(selector labels.Selector) (ret []*v1.VolumeSnapshot, err error) + // VolumeSnapshots returns an object that can list and get VolumeSnapshots. + VolumeSnapshots(namespace string) VolumeSnapshotNamespaceLister + VolumeSnapshotListerExpansion +} + +// volumeSnapshotLister implements the VolumeSnapshotLister interface. +type volumeSnapshotLister struct { + indexer cache.Indexer +} + +// NewVolumeSnapshotLister returns a new VolumeSnapshotLister. +func NewVolumeSnapshotLister(indexer cache.Indexer) VolumeSnapshotLister { + return &volumeSnapshotLister{indexer: indexer} +} + +// List lists all VolumeSnapshots in the indexer. +func (s *volumeSnapshotLister) List(selector labels.Selector) (ret []*v1.VolumeSnapshot, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VolumeSnapshot)) + }) + return ret, err +} + +// VolumeSnapshots returns an object that can list and get VolumeSnapshots. +func (s *volumeSnapshotLister) VolumeSnapshots(namespace string) VolumeSnapshotNamespaceLister { + return volumeSnapshotNamespaceLister{indexer: s.indexer, namespace: namespace} +} + +// VolumeSnapshotNamespaceLister helps list and get VolumeSnapshots. +type VolumeSnapshotNamespaceLister interface { + // List lists all VolumeSnapshots in the indexer for a given namespace. + List(selector labels.Selector) (ret []*v1.VolumeSnapshot, err error) + // Get retrieves the VolumeSnapshot from the indexer for a given namespace and name. + Get(name string) (*v1.VolumeSnapshot, error) + VolumeSnapshotNamespaceListerExpansion +} + +// volumeSnapshotNamespaceLister implements the VolumeSnapshotNamespaceLister +// interface. +type volumeSnapshotNamespaceLister struct { + indexer cache.Indexer + namespace string +} + +// List lists all VolumeSnapshots in the indexer for a given namespace. +func (s volumeSnapshotNamespaceLister) List(selector labels.Selector) (ret []*v1.VolumeSnapshot, err error) { + err = cache.ListAllByNamespace(s.indexer, s.namespace, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VolumeSnapshot)) + }) + return ret, err +} + +// Get retrieves the VolumeSnapshot from the indexer for a given namespace and name. +func (s volumeSnapshotNamespaceLister) Get(name string) (*v1.VolumeSnapshot, error) { + obj, exists, err := s.indexer.GetByKey(s.namespace + "/" + name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("volumesnapshot"), name) + } + return obj.(*v1.VolumeSnapshot), nil +} diff --git a/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshotdata.go b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshotdata.go new file mode 100644 index 0000000000..a0d0092a04 --- /dev/null +++ b/vendor/github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/listers/volumesnapshot/v1/volumesnapshotdata.go @@ -0,0 +1,64 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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 lister-gen. DO NOT EDIT. + +package v1 + +import ( + v1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/labels" + "k8s.io/client-go/tools/cache" +) + +// VolumeSnapshotDataLister helps list VolumeSnapshotDatas. +type VolumeSnapshotDataLister interface { + // List lists all VolumeSnapshotDatas in the indexer. + List(selector labels.Selector) (ret []*v1.VolumeSnapshotData, err error) + // Get retrieves the VolumeSnapshotData from the index for a given name. + Get(name string) (*v1.VolumeSnapshotData, error) + VolumeSnapshotDataListerExpansion +} + +// volumeSnapshotDataLister implements the VolumeSnapshotDataLister interface. +type volumeSnapshotDataLister struct { + indexer cache.Indexer +} + +// NewVolumeSnapshotDataLister returns a new VolumeSnapshotDataLister. +func NewVolumeSnapshotDataLister(indexer cache.Indexer) VolumeSnapshotDataLister { + return &volumeSnapshotDataLister{indexer: indexer} +} + +// List lists all VolumeSnapshotDatas in the indexer. +func (s *volumeSnapshotDataLister) List(selector labels.Selector) (ret []*v1.VolumeSnapshotData, err error) { + err = cache.ListAll(s.indexer, selector, func(m interface{}) { + ret = append(ret, m.(*v1.VolumeSnapshotData)) + }) + return ret, err +} + +// Get retrieves the VolumeSnapshotData from the index for a given name. +func (s *volumeSnapshotDataLister) Get(name string) (*v1.VolumeSnapshotData, error) { + obj, exists, err := s.indexer.GetByKey(name) + if err != nil { + return nil, err + } + if !exists { + return nil, errors.NewNotFound(v1.Resource("volumesnapshotdata"), name) + } + return obj.(*v1.VolumeSnapshotData), nil +} diff --git a/vendor/manifest b/vendor/manifest index a100a25a84..31130f2843 100644 --- a/vendor/manifest +++ b/vendor/manifest @@ -1650,6 +1650,14 @@ "path": "vendor/golang.org/x/sys/windows", "notests": true }, + { + "importpath": "github.com/openebs/k8s-snapshot-client", + "repository": "https://github.com/openebs/k8s-snapshot-client", + "vcs": "git", + "revision": "a6506305fb16b003487392c8199452b01161866e", + "branch": "master", + "notests": true + }, { "importpath": "github.com/opentracing-contrib/go-stdlib/nethttp", "repository": "https://github.com/opentracing-contrib/go-stdlib", From 81a682893f5e8cdd55933803edddc3664451288c Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Tue, 25 Sep 2018 20:40:08 +0530 Subject: [PATCH 20/25] Add kubernetes volume snapshot support - Add a new client in probe/kubernetes/client.go which will be used to fetch details of Snapshot CRD - Visualize VolumeSnapshot and VolumeSnapshotData - Add adjacency between PV and VolumeSnapshot - Add adjacency between VolumeSnapshot and VolumeSnapshotData - Add snapshot filter to hide and show snapshots Signed-off-by: Akash Srivastava --- app/api_topologies.go | 11 +++++- client/app/scripts/charts/edge.js | 6 +-- probe/kubernetes/client.go | 43 ++++++++++++++++++++- probe/kubernetes/reporter.go | 51 +++++++++++++++++++++++++ probe/kubernetes/reporter_test.go | 6 +++ probe/kubernetes/volumesnapshot.go | 39 +++++++++++++++++++ probe/kubernetes/volumesnapshotdata.go | 33 ++++++++++++++++ render/detailed/node.go | 14 +++++++ render/detailed/summary.go | 14 +++++++ render/expected/expected.go | 22 ++++++++++- render/filters.go | 8 ++++ render/persistentvolume.go | 53 +++++++++++++++++++++++++- render/selectors.go | 2 + report/id.go | 12 ++++++ report/map_keys.go | 4 ++ report/report.go | 24 ++++++++++++ test/fixture/report_fixture.go | 32 ++++++++++++++++ 17 files changed, 363 insertions(+), 11 deletions(-) create mode 100644 probe/kubernetes/volumesnapshot.go create mode 100644 probe/kubernetes/volumesnapshotdata.go diff --git a/app/api_topologies.go b/app/api_topologies.go index 6b286a57f1..7298542b4f 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -10,6 +10,7 @@ import ( "time" "context" + "github.com/gorilla/mux" log "github.com/sirupsen/logrus" @@ -55,6 +56,14 @@ var ( {Value: "hide", Label: "Hide storage", filter: render.IsPodComponent, filterPseudo: false}, }, } + snapshotFilter = APITopologyOptionGroup{ + ID: "snapshot", + Default: "hide", + Options: []APITopologyOption{ + {Value: "show", Label: "Show snapshots", filter: nil, filterPseudo: false}, + {Value: "hide", Label: "Hide snapshots", filter: render.IsNonSnapshotComponent, filterPseudo: false}, + }, + } ) // namespaceFilters generates a namespace selector option group based on the given namespaces @@ -237,7 +246,7 @@ func MakeRegistry() *Registry { renderer: render.PodRenderer, Name: "Pods", Rank: 3, - Options: []APITopologyOptionGroup{storageFilter, unmanagedFilter}, + Options: []APITopologyOptionGroup{snapshotFilter, storageFilter, unmanagedFilter}, HideIfEmpty: true, }, APITopologyDesc{ diff --git a/client/app/scripts/charts/edge.js b/client/app/scripts/charts/edge.js index c4f9d6b98d..d6d35e7b75 100644 --- a/client/app/scripts/charts/edge.js +++ b/client/app/scripts/charts/edge.js @@ -6,10 +6,8 @@ import { enterEdge, leaveEdge } from '../actions/app-actions'; import { encodeIdAttribute, decodeIdAttribute } from '../utils/dom-utils'; function isStorageComponent(id) { - if (id === '' || id === '' || id === '') { - return true; - } - return false; + const storageComponents = ['', '', '', '', '']; + return storageComponents.includes(id); } // getAdjacencyClass takes id which contains information about edge as a topology diff --git a/probe/kubernetes/client.go b/probe/kubernetes/client.go index edaa0a5a68..54d07d78b5 100644 --- a/probe/kubernetes/client.go +++ b/probe/kubernetes/client.go @@ -8,6 +8,8 @@ import ( "github.com/weaveworks/common/backoff" + snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + snapshot "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" log "github.com/sirupsen/logrus" apiappsv1beta1 "k8s.io/api/apps/v1beta1" apibatchv1 "k8s.io/api/batch/v1" @@ -41,6 +43,8 @@ type Client interface { WalkPersistentVolumes(f func(PersistentVolume) error) error WalkPersistentVolumeClaims(f func(PersistentVolumeClaim) error) error WalkStorageClasses(f func(StorageClass) error) error + WalkVolumeSnapshots(f func(VolumeSnapshot) error) error + WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error WatchPods(f func(Event, Pod)) @@ -53,6 +57,7 @@ type Client interface { type client struct { quit chan struct{} client *kubernetes.Clientset + snapshotClient *snapshot.Clientset podStore cache.Store serviceStore cache.Store deploymentStore cache.Store @@ -65,6 +70,8 @@ type client struct { persistentVolumeStore cache.Store persistentVolumeClaimStore cache.Store storageClassStore cache.Store + volumeSnapshotStore cache.Store + volumeSnapshotDataStore cache.Store podWatchesMutex sync.Mutex podWatches []func(Event, Pod) @@ -133,9 +140,15 @@ func NewClient(config ClientConfig) (Client, error) { return nil, err } + sc, err := snapshot.NewForConfig(restConfig) + if err != nil { + return nil, err + } + result := &client{ - quit: make(chan struct{}), - client: c, + quit: make(chan struct{}), + client: c, + snapshotClient: sc, } result.podStore = NewEventStore(result.triggerPodWatches, cache.MetaNamespaceKeyFunc) @@ -152,6 +165,8 @@ func NewClient(config ClientConfig) (Client, error) { result.persistentVolumeStore = result.setupStore("persistentvolumes") result.persistentVolumeClaimStore = result.setupStore("persistentvolumeclaims") result.storageClassStore = result.setupStore("storageclasses") + result.volumeSnapshotStore = result.setupStore("volumesnapshots") + result.volumeSnapshotDataStore = result.setupStore("volumesnapshotdatas") return result, nil } @@ -204,6 +219,10 @@ func (c *client) clientAndType(resource string) (rest.Interface, interface{}, er return c.client.BatchV1().RESTClient(), &apibatchv1.Job{}, nil case "statefulsets": return c.client.AppsV1beta1().RESTClient(), &apiappsv1beta1.StatefulSet{}, nil + case "volumesnapshots": + return c.snapshotClient.VolumesnapshotV1().RESTClient(), &snapshotv1.VolumeSnapshot{}, nil + case "volumesnapshotdatas": + return c.snapshotClient.VolumesnapshotV1().RESTClient(), &snapshotv1.VolumeSnapshotData{}, nil case "cronjobs": ok, err := c.isResourceSupported(c.client.BatchV1beta1().RESTClient().APIVersion(), resource) if err != nil { @@ -388,6 +407,26 @@ func (c *client) WalkNamespaces(f func(NamespaceResource) error) error { return nil } +func (c *client) WalkVolumeSnapshots(f func(VolumeSnapshot) error) error { + for _, m := range c.volumeSnapshotStore.List() { + volumeSnapshot := m.(*snapshotv1.VolumeSnapshot) + if err := f(NewVolumeSnapshot(volumeSnapshot)); err != nil { + return err + } + } + return nil +} + +func (c *client) WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error { + for _, m := range c.volumeSnapshotDataStore.List() { + volumeSnapshotData := m.(*snapshotv1.VolumeSnapshotData) + if err := f(NewVolumeSnapshotData(volumeSnapshotData)); err != nil { + return err + } + } + return nil +} + func (c *client) GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) { readClosersWithLabel := map[io.ReadCloser]string{} for _, container := range containerNames { diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index 3dfa8c7939..23a72a83cd 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -34,6 +34,8 @@ const ( VolumeName = report.KubernetesVolumeName Provisioner = report.KubernetesProvisioner StorageDriver = report.KubernetesStorageDriver + VolumeSnapshotName = report.KubernetesVolumeSnapshotName + SnapshotData = report.KubernetesSnapshotData ) // Exposed for testing @@ -130,6 +132,19 @@ var ( Provisioner: {ID: Provisioner, Label: "Provisioner", From: report.FromLatest, Priority: 3}, } + VolumeSnapshotMetadataTemplates = report.MetadataTemplates{ + NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1}, + Namespace: {ID: Namespace, Label: "Name", From: report.FromLatest, Priority: 2}, + VolumeClaim: {ID: VolumeClaim, Label: "Persistent volume claim", From: report.FromLatest, Priority: 3}, + SnapshotData: {ID: SnapshotData, Label: "Volume snapshot data", From: report.FromLatest, Priority: 4}, + } + + VolumeSnapshotDataMetadataTemplates = report.MetadataTemplates{ + NodeType: {ID: NodeType, Label: "Type", From: report.FromLatest, Priority: 1}, + VolumeName: {ID: VolumeName, Label: "Persistent volume", From: report.FromLatest, Priority: 2}, + VolumeSnapshotName: {ID: VolumeSnapshotName, Label: "Volume snapshot", From: report.FromLatest, Priority: 3}, + } + TableTemplates = report.TableTemplates{ LabelPrefix: { ID: LabelPrefix, @@ -300,6 +315,14 @@ func (r *Reporter) Report() (report.Report, error) { if err != nil { return result, err } + volumeSnapshotTopology, _, err := r.volumeSnapshotTopology() + if err != nil { + return result, err + } + volumeSnapshotDataTopology, _, err := r.volumeSnapshotDataTopology() + if err != nil { + return result, err + } result.Pod = result.Pod.Merge(podTopology) result.Service = result.Service.Merge(serviceTopology) result.Host = result.Host.Merge(hostTopology) @@ -311,6 +334,8 @@ func (r *Reporter) Report() (report.Report, error) { result.PersistentVolume = result.PersistentVolume.Merge(persistentVolumeTopology) result.PersistentVolumeClaim = result.PersistentVolumeClaim.Merge(persistentVolumeClaimTopology) result.StorageClass = result.StorageClass.Merge(storageClassTopology) + result.VolumeSnapshot = result.VolumeSnapshot.Merge(volumeSnapshotTopology) + result.VolumeSnapshotData = result.VolumeSnapshotData.Merge(volumeSnapshotDataTopology) return result, nil } @@ -459,6 +484,32 @@ func (r *Reporter) storageClassTopology() (report.Topology, []StorageClass, erro return result, storageClasses, err } +func (r *Reporter) volumeSnapshotTopology() (report.Topology, []VolumeSnapshot, error) { + volumeSnapshots := []VolumeSnapshot{} + result := report.MakeTopology(). + WithMetadataTemplates(VolumeSnapshotMetadataTemplates). + WithTableTemplates(TableTemplates) + err := r.client.WalkVolumeSnapshots(func(p VolumeSnapshot) error { + result.AddNode(p.GetNode(r.probeID)) + volumeSnapshots = append(volumeSnapshots, p) + return nil + }) + return result, volumeSnapshots, err +} + +func (r *Reporter) volumeSnapshotDataTopology() (report.Topology, []VolumeSnapshotData, error) { + volumeSnapshotData := []VolumeSnapshotData{} + result := report.MakeTopology(). + WithMetadataTemplates(VolumeSnapshotDataMetadataTemplates). + WithTableTemplates(TableTemplates) + err := r.client.WalkVolumeSnapshotData(func(p VolumeSnapshotData) error { + result.AddNode(p.GetNode(r.probeID)) + volumeSnapshotData = append(volumeSnapshotData, p) + return nil + }) + return result, volumeSnapshotData, err +} + type labelledChild interface { Labels() map[string]string AddParent(string, string) diff --git a/probe/kubernetes/reporter_test.go b/probe/kubernetes/reporter_test.go index 70e083b3a6..dea19c64cd 100644 --- a/probe/kubernetes/reporter_test.go +++ b/probe/kubernetes/reporter_test.go @@ -164,6 +164,12 @@ func (c *mockClient) WalkPersistentVolumeClaims(f func(kubernetes.PersistentVolu func (c *mockClient) WalkStorageClasses(f func(kubernetes.StorageClass) error) error { return nil } +func (c *mockClient) WalkVolumeSnapshots(f func(kubernetes.VolumeSnapshot) error) error { + return nil +} +func (c *mockClient) WalkVolumeSnapshotData(f func(kubernetes.VolumeSnapshotData) error) error { + return nil +} func (*mockClient) WatchPods(func(kubernetes.Event, kubernetes.Pod)) {} func (c *mockClient) GetLogs(namespaceID, podName string, _ []string) (io.ReadCloser, error) { r, ok := c.logs[namespaceID+";"+podName] diff --git a/probe/kubernetes/volumesnapshot.go b/probe/kubernetes/volumesnapshot.go new file mode 100644 index 0000000000..153bf23c29 --- /dev/null +++ b/probe/kubernetes/volumesnapshot.go @@ -0,0 +1,39 @@ +package kubernetes + +import ( + snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + "github.com/weaveworks/scope/report" +) + +// SnapshotPVName is the label key which provides PV name +const ( + SnapshotPVName = "SnapshotMetadata-PVName" +) + +// VolumeSnapshot represent kubernetes VolumeSnapshot interface +type VolumeSnapshot interface { + Meta + GetNode(probeID string) report.Node +} + +// volumeSnapshot represents kubernetes volume snapshots +type volumeSnapshot struct { + *snapshotv1.VolumeSnapshot + Meta +} + +// NewVolumeSnapshot returns new Volume Snapshot type +func NewVolumeSnapshot(p *snapshotv1.VolumeSnapshot) VolumeSnapshot { + return &volumeSnapshot{VolumeSnapshot: p, Meta: meta{p.ObjectMeta}} +} + +// GetNode returns VolumeSnapshot as Node +func (p *volumeSnapshot) GetNode(probeID string) report.Node { + return p.MetaNode(report.MakeVolumeSnapshotNodeID(p.UID())).WithLatests(map[string]string{ + report.ControlProbeID: probeID, + NodeType: "Volume Snapshot", + VolumeClaim: p.Spec.PersistentVolumeClaimName, + SnapshotData: p.Spec.SnapshotDataName, + VolumeName: p.GetLabels()[SnapshotPVName], + }) +} diff --git a/probe/kubernetes/volumesnapshotdata.go b/probe/kubernetes/volumesnapshotdata.go new file mode 100644 index 0000000000..0516bf6ec0 --- /dev/null +++ b/probe/kubernetes/volumesnapshotdata.go @@ -0,0 +1,33 @@ +package kubernetes + +import ( + snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" + "github.com/weaveworks/scope/report" +) + +// VolumeSnapshotData represent kubernetes VolumeSnapshotData interface +type VolumeSnapshotData interface { + Meta + GetNode(probeID string) report.Node +} + +// volumeSnapshotData represents kubernetes volume snapshot data +type volumeSnapshotData struct { + *snapshotv1.VolumeSnapshotData + Meta +} + +// NewVolumeSnapshotData returns new Volume Snapshot Data type +func NewVolumeSnapshotData(p *snapshotv1.VolumeSnapshotData) VolumeSnapshotData { + return &volumeSnapshotData{VolumeSnapshotData: p, Meta: meta{p.ObjectMeta}} +} + +// GetNode returns VolumeSnapshotData as Node +func (p *volumeSnapshotData) GetNode(probeID string) report.Node { + return p.MetaNode(report.MakeVolumeSnapshotDataNodeID(p.UID())).WithLatests(map[string]string{ + report.ControlProbeID: probeID, + NodeType: "Volume Snapshot Data", + VolumeName: p.Spec.PersistentVolumeRef.Name, + VolumeSnapshotName: p.Spec.VolumeSnapshotRef.Name, + }) +} diff --git a/render/detailed/node.go b/render/detailed/node.go index f7bdeef2ed..459cc593f0 100644 --- a/render/detailed/node.go +++ b/render/detailed/node.go @@ -206,6 +206,20 @@ var nodeSummaryGroupSpecs = []struct { Columns: []Column{}, }, }, + { + topologyID: report.VolumeSnapshot, + NodeSummaryGroup: NodeSummaryGroup{ + Label: "Volume Snapshots", + Columns: []Column{}, + }, + }, + { + topologyID: report.VolumeSnapshotData, + NodeSummaryGroup: NodeSummaryGroup{ + Label: "Volume Snapshot Data", + Columns: []Column{}, + }, + }, } func children(rc RenderContext, n report.Node) []NodeSummaryGroup { diff --git a/render/detailed/summary.go b/render/detailed/summary.go index e43ad19db4..d50417eb62 100644 --- a/render/detailed/summary.go +++ b/render/detailed/summary.go @@ -84,6 +84,8 @@ var renderers = map[string]func(BasicNodeSummary, report.Node) BasicNodeSummary{ report.PersistentVolume: persistentVolumeNodeSummary, report.PersistentVolumeClaim: persistentVolumeClaimNodeSummary, report.StorageClass: storageClassNodeSummary, + report.VolumeSnapshot: volumeSnapshotNodeSummary, + report.VolumeSnapshotData: volumeSnapshotDataNodeSummary, } // For each report.Topology, map to a 'primary' API topology. This can then be used in a variety of places. @@ -104,6 +106,8 @@ var primaryAPITopology = map[string]string{ report.PersistentVolume: "pods", report.PersistentVolumeClaim: "pods", report.StorageClass: "pods", + report.VolumeSnapshot: "pods", + report.VolumeSnapshotData: "pods", } // MakeBasicNodeSummary returns a basic summary of a node, if @@ -394,6 +398,16 @@ func storageClassNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSumm return base } +func volumeSnapshotNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSummary { + base = addKubernetesLabelAndRank(base, n) + return base +} + +func volumeSnapshotDataNodeSummary(base BasicNodeSummary, n report.Node) BasicNodeSummary { + base = addKubernetesLabelAndRank(base, n) + return base +} + // groupNodeSummary renders the summary for a group node. n.Topology is // expected to be of the form: group:container:hostname func groupNodeSummary(base BasicNodeSummary, r report.Report, n report.Node) BasicNodeSummary { diff --git a/render/expected/expected.go b/render/expected/expected.go index f3171c7255..adac162bb9 100644 --- a/render/expected/expected.go +++ b/render/expected/expected.go @@ -44,6 +44,8 @@ var ( persistentVolume = node(report.PersistentVolume) persistentVolumeClaim = node(report.PersistentVolumeClaim) StorageClass = node(report.StorageClass) + volumeSnapshot = node(report.VolumeSnapshot) + volumeSnapshotData = node(report.VolumeSnapshotData) UnknownPseudoNode1ID = render.MakePseudoNodeID(fixture.UnknownClient1IP) UnknownPseudoNode2ID = render.MakePseudoNodeID(fixture.UnknownClient3IP) @@ -282,7 +284,7 @@ var ( kubernetes.StorageClassName: "standard", }).WithChild(report.MakeNode(fixture.PersistentVolumeNodeID).WithTopology(report.PersistentVolume)), - fixture.PersistentVolumeNodeID: persistentVolume(fixture.PersistentVolumeNodeID). + fixture.PersistentVolumeNodeID: persistentVolume(fixture.PersistentVolumeNodeID, fixture.VolumeSnapshotNodeID). WithLatests(map[string]string{ kubernetes.Name: "pongvolume", kubernetes.Namespace: "ping", @@ -291,7 +293,7 @@ var ( kubernetes.AccessModes: "ReadWriteOnce", kubernetes.StorageClassName: "standard", kubernetes.StorageDriver: "iSCSI", - }), + }).WithChild(report.MakeNode(fixture.VolumeSnapshotNodeID).WithTopology(report.VolumeSnapshot)), fixture.StorageClassNodeID: StorageClass(fixture.StorageClassNodeID, fixture.PersistentVolumeClaimNodeID). WithLatests(map[string]string{ @@ -299,6 +301,22 @@ var ( kubernetes.Provisioner: "pong", }).WithChild(report.MakeNode(fixture.PersistentVolumeClaimNodeID).WithTopology(report.PersistentVolumeClaim)), + fixture.VolumeSnapshotNodeID: volumeSnapshot(fixture.VolumeSnapshotNodeID, fixture.VolumeSnapshotDataNodeID). + WithLatests(map[string]string{ + kubernetes.Name: "vs-1234", + kubernetes.Namespace: "ping", + kubernetes.VolumeClaim: "pvc-6124", + kubernetes.SnapshotData: "vsd-1234", + kubernetes.VolumeName: "pongvolume", + }).WithChild(report.MakeNode(fixture.VolumeSnapshotDataNodeID).WithTopology(report.VolumeSnapshotData)), + + fixture.VolumeSnapshotDataNodeID: volumeSnapshotData(fixture.VolumeSnapshotDataNodeID). + WithLatests(map[string]string{ + kubernetes.Name: "vsd-1234", + kubernetes.VolumeName: "pongvolume", + kubernetes.VolumeSnapshotName: "vs-1234", + }), + UnmanagedServerID: unmanagedServerNode, render.IncomingInternetID: theIncomingInternetNode(fixture.ServerPodNodeID), render.OutgoingInternetID: theOutgoingInternetNode, diff --git a/render/filters.go b/render/filters.go index 208bbd64a6..8d02a5918f 100644 --- a/render/filters.go +++ b/render/filters.go @@ -138,6 +138,14 @@ func IsPodComponent(node report.Node) bool { return ok } +// IsNonSnapshotComponent checks whether given node is everything but Volume Snapshot, Volume Snapshot Data +func IsNonSnapshotComponent(node report.Node) bool { + if node.Topology == "volume_snapshot" || node.Topology == "volume_snapshot_data" { + return false + } + return true +} + // connected returns the node ids of nodes which have edges to/from // them, excluding edges to/from themselves. func connected(nodes report.Nodes) map[string]struct{} { diff --git a/render/persistentvolume.go b/render/persistentvolume.go index 98197473ff..573c43c82b 100644 --- a/render/persistentvolume.go +++ b/render/persistentvolume.go @@ -11,6 +11,8 @@ var KubernetesVolumesRenderer = MakeReduce( VolumesRenderer, PodToVolumeRenderer, PVCToStorageClassRenderer, + PVToSnapshotRenderer, + VolumeSnapshotRenderer, ) // VolumesRenderer is a Renderer which produces a renderable kubernetes PV & PVC @@ -25,13 +27,12 @@ func (v volumesRenderer) Render(rpt report.Report) Nodes { nodes := make(report.Nodes) for id, n := range rpt.PersistentVolumeClaim.Nodes { volume, _ := n.Latest.Lookup(kubernetes.VolumeName) - for pvNodeID, p := range rpt.PersistentVolume.Nodes { + for _, p := range rpt.PersistentVolume.Nodes { volumeName, _ := p.Latest.Lookup(kubernetes.Name) if volume == volumeName { n.Adjacency = n.Adjacency.Add(p.ID) n.Children = n.Children.Add(p) } - nodes[pvNodeID] = p } nodes[id] = n } @@ -86,3 +87,51 @@ func (v pvcToStorageClassRenderer) Render(rpt report.Report) Nodes { } return Nodes{Nodes: nodes} } + +//PVToSnapshotRenderer is a Renderer which produces a renderable kubernetes PV +var PVToSnapshotRenderer = pvToSnapshotRenderer{} + +//pvToSnapshotRenderer is a Renderer to render PV & Snapshot. +type pvToSnapshotRenderer struct{} + +//Render renders the PV & Snapshot nodes with adjacency. +func (v pvToSnapshotRenderer) Render(rpt report.Report) Nodes { + nodes := make(report.Nodes) + for pvNodeID, p := range rpt.PersistentVolume.Nodes { + volumeName, _ := p.Latest.Lookup(kubernetes.Name) + for _, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes { + snapshotPVName, _ := volumeSnapshotNode.Latest.Lookup(kubernetes.VolumeName) + if volumeName == snapshotPVName { + p.Adjacency = p.Adjacency.Add(volumeSnapshotNode.ID) + p.Children = p.Children.Add(volumeSnapshotNode) + } + } + nodes[pvNodeID] = p + } + return Nodes{Nodes: nodes} +} + +// VolumeSnapshotRenderer is a renderer which produces a renderable Kubernetes Volume Snapshot and Volume Snapshot Data +var VolumeSnapshotRenderer = volumeSnapshotRenderer{} + +// volumeSnapshotRenderer is a render to volume snapshot & volume snapshot data +type volumeSnapshotRenderer struct{} + +// Render renders the volumeSnapshots & volumeSnapshotData with adjacency +// It checks for the volumeSnapshotData name in volumeSnapshot, adjacency is created by matching the volumeSnapshotData name. +func (v volumeSnapshotRenderer) Render(rpt report.Report) Nodes { + nodes := make(report.Nodes) + for volumeSnapshotID, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes { + snapshotData, _ := volumeSnapshotNode.Latest.Lookup(kubernetes.SnapshotData) + for volumeSnapshotDataID, volumeSnapshotDataNode := range rpt.VolumeSnapshotData.Nodes { + snapshotDataName, _ := volumeSnapshotDataNode.Latest.Lookup(kubernetes.Name) + if snapshotDataName == snapshotData { + volumeSnapshotNode.Adjacency = volumeSnapshotNode.Adjacency.Add(volumeSnapshotDataNode.ID) + volumeSnapshotNode.Children = volumeSnapshotNode.Children.Add(volumeSnapshotDataNode) + } + nodes[volumeSnapshotDataID] = volumeSnapshotDataNode + } + nodes[volumeSnapshotID] = volumeSnapshotNode + } + return Nodes{Nodes: nodes} +} diff --git a/render/selectors.go b/render/selectors.go index 036f10720a..0b995c38df 100644 --- a/render/selectors.go +++ b/render/selectors.go @@ -35,4 +35,6 @@ var ( SelectPersistentVolume = TopologySelector(report.PersistentVolume) SelectPersistentVolumeClaim = TopologySelector(report.PersistentVolumeClaim) SelectStorageClass = TopologySelector(report.StorageClass) + SelectVolumeSnapshot = TopologySelector(report.VolumeSnapshot) + SelectVolumeSnapshotData = TopologySelector(report.VolumeSnapshotData) ) diff --git a/report/id.go b/report/id.go index d6731f35b7..be893a2146 100644 --- a/report/id.go +++ b/report/id.go @@ -175,6 +175,18 @@ var ( // ParseStorageClassNodeID parses a storage class node ID ParseStorageClassNodeID = parseSingleComponentID("storage_class") + + // MakeVolumeSnapshotNodeID produces a volume snapshot node ID from its composite parts. + MakeVolumeSnapshotNodeID = makeSingleComponentID("volume_snapshot") + + // ParseVolumeSnapshotNodeID parses a volume snapshot node ID + ParseVolumeSnapshotNodeID = parseSingleComponentID("volume_snapshot") + + // MakeVolumeSnapshotDataNodeID produces a volume snapshot data node ID from its composite parts. + MakeVolumeSnapshotDataNodeID = makeSingleComponentID("volume_snapshot_data") + + // ParseVolumeSnapshotDataNodeID parses a volume snapshot data node ID + ParseVolumeSnapshotDataNodeID = parseSingleComponentID("volume_snapshot_data") ) // makeSingleComponentID makes a single-component node id encoder diff --git a/report/map_keys.go b/report/map_keys.go index fa5bea5032..e6d39c810d 100644 --- a/report/map_keys.go +++ b/report/map_keys.go @@ -81,6 +81,8 @@ const ( KubernetesVolumeName = "kubernetes_volume_name" KubernetesProvisioner = "kubernetes_provisioner" KubernetesStorageDriver = "kubernetes_storage_driver" + KubernetesVolumeSnapshotName = "kubernetes_volume_snapshot_name" + KubernetesSnapshotData = "kuberneets_snapshot_data" // probe/awsecs ECSCluster = "ecs_cluster" ECSCreatedAt = "ecs_created_at" @@ -116,6 +118,8 @@ var commonKeys = map[string]string{ PersistentVolume: PersistentVolume, PersistentVolumeClaim: PersistentVolumeClaim, StorageClass: StorageClass, + VolumeSnapshot: VolumeSnapshot, + VolumeSnapshotData: VolumeSnapshotData, HostNodeID: HostNodeID, ControlProbeID: ControlProbeID, diff --git a/report/report.go b/report/report.go index 0ae6703d39..32a28f4b98 100644 --- a/report/report.go +++ b/report/report.go @@ -31,6 +31,8 @@ const ( PersistentVolume = "persistent_volume" PersistentVolumeClaim = "persistent_volume_claim" StorageClass = "storage_class" + VolumeSnapshot = "volume_snapshot" + VolumeSnapshotData = "volume_snapshot_data" // Shapes used for different nodes Circle = "circle" @@ -72,6 +74,8 @@ var topologyNames = []string{ PersistentVolume, PersistentVolumeClaim, StorageClass, + VolumeSnapshot, + VolumeSnapshotData, } // Report is the core data type. It's produced by probes, and consumed and @@ -172,6 +176,12 @@ type Report struct { // Metadata is limited for now, more to come later. StorageClass Topology + // VolumeSnapshot represent all Kubernetes Volume Snapshots on hosts running probes. + VolumeSnapshot Topology + + // VolumeSnapshotData represent all Kubernetes Volume Snapshot Data on hosts running probes. + VolumeSnapshotData Topology + DNS DNSRecords // Sampling data for this report. @@ -277,6 +287,16 @@ func MakeReport() Report { WithShape(StorageSheet). WithLabel("storage class", "storage classes"), + VolumeSnapshot: MakeTopology(). + WithShape(DottedCylinder). + WithTag(Camera). + WithLabel("volume snapshot", "volume snapshots"), + + VolumeSnapshotData: MakeTopology(). + WithShape(Cylinder). + WithTag(Camera). + WithLabel("volume snapshot data", "volume snapshot data"), + DNS: DNSRecords{}, Sampling: Sampling{}, @@ -389,6 +409,10 @@ func (r *Report) topology(name string) *Topology { return &r.PersistentVolumeClaim case StorageClass: return &r.StorageClass + case VolumeSnapshot: + return &r.VolumeSnapshot + case VolumeSnapshotData: + return &r.VolumeSnapshotData } return nil } diff --git a/test/fixture/report_fixture.go b/test/fixture/report_fixture.go index f914077f2f..2ea0608bb7 100644 --- a/test/fixture/report_fixture.go +++ b/test/fixture/report_fixture.go @@ -107,6 +107,10 @@ var ( PersistentVolumeClaimNodeID = report.MakePersistentVolumeClaimNodeID(PersistentVolumeClaimUID) StorageClassUID = "sc1234" StorageClassNodeID = report.MakeStorageClassNodeID(StorageClassUID) + VolumeSnapshotUID = "vs1234" + VolumeSnapshotNodeID = report.MakeVolumeSnapshotNodeID(VolumeSnapshotUID) + VolumeSnapshotDataUID = "vsd1234" + VolumeSnapshotDataNodeID = report.MakeVolumeSnapshotDataNodeID(VolumeSnapshotDataUID) ClientProcess1CPUMetric = report.MakeSingletonMetric(Now.Add(-1*time.Second), 0.01) ClientProcess1MemoryMetric = report.MakeSingletonMetric(Now.Add(-2*time.Second), 0.02) @@ -396,6 +400,34 @@ var ( WithTopology(report.StorageClass), }, }.WithShape(report.StorageSheet).WithLabel("storage class", "storage classes"), + VolumeSnapshot: report.Topology{ + Nodes: report.Nodes{ + VolumeSnapshotNodeID: report.MakeNodeWith( + + VolumeSnapshotNodeID, map[string]string{ + kubernetes.Name: "vs-1234", + kubernetes.Namespace: "ping", + kubernetes.VolumeClaim: "pvc-6124", + kubernetes.SnapshotData: "vsd-1234", + kubernetes.VolumeName: "pongvolume", + }). + WithTopology(report.VolumeSnapshot), + }, + }.WithShape(report.DottedCylinder).WithLabel("volume snapshot", "volume snapshots"). + WithTag(report.Camera), + VolumeSnapshotData: report.Topology{ + Nodes: report.Nodes{ + VolumeSnapshotDataNodeID: report.MakeNodeWith( + + VolumeSnapshotDataNodeID, map[string]string{ + kubernetes.Name: "vsd-1234", + kubernetes.VolumeName: "pongvolume", + kubernetes.VolumeSnapshotName: "vs-1234", + }). + WithTopology(report.VolumeSnapshotData), + }, + }.WithShape(report.Cylinder).WithLabel("volume snapshot data", "volume snapshot data"). + WithTag(report.Camera), Sampling: report.Sampling{ Count: 1024, Total: 4096, From 8692a4d57d5236c80a365af25e665901df10a9c8 Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Wed, 26 Sep 2018 11:48:04 +0530 Subject: [PATCH 21/25] Add control on PVC to take volume snapshot Signed-off-by: Akash Srivastava --- probe/kubernetes/client.go | 24 +++++++++++ probe/kubernetes/controls.go | 49 +++++++++++++++++++---- probe/kubernetes/persistentvolumeclaim.go | 35 ++++++++++++---- probe/kubernetes/reporter.go | 10 ++++- probe/kubernetes/reporter_test.go | 3 ++ report/map_keys.go | 2 + 6 files changed, 106 insertions(+), 17 deletions(-) diff --git a/probe/kubernetes/client.go b/probe/kubernetes/client.go index 54d07d78b5..cbc0fa8d59 100644 --- a/probe/kubernetes/client.go +++ b/probe/kubernetes/client.go @@ -3,6 +3,7 @@ package kubernetes import ( "fmt" "io" + "strings" "sync" "time" @@ -10,6 +11,7 @@ import ( snapshotv1 "github.com/openebs/k8s-snapshot-client/snapshot/pkg/apis/volumesnapshot/v1" snapshot "github.com/openebs/k8s-snapshot-client/snapshot/pkg/client/clientset/versioned" + "github.com/pborman/uuid" log "github.com/sirupsen/logrus" apiappsv1beta1 "k8s.io/api/apps/v1beta1" apibatchv1 "k8s.io/api/batch/v1" @@ -48,6 +50,7 @@ type Client interface { WatchPods(f func(Event, Pod)) + CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) DeletePod(namespaceID, podID string) error ScaleUp(resource, namespaceID, id string) error @@ -427,6 +430,27 @@ func (c *client) WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error return nil } +func (c *client) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error { + UID := strings.Split(uuid.New(), "-") + volumeSnapshot := &snapshotv1.VolumeSnapshot{ + ObjectMeta: metav1.ObjectMeta{ + Name: "snapshot-" + time.Now().Format("20060102150405") + "-" + UID[1], + Namespace: namespaceID, + Annotations: map[string]string{ + "capacity": capacity, + }, + }, + Spec: snapshotv1.VolumeSnapshotSpec{ + PersistentVolumeClaimName: persistentVolumeClaimID, + }, + } + _, err := c.snapshotClient.VolumesnapshotV1().VolumeSnapshots(namespaceID).Create(volumeSnapshot) + if err != nil { + return err + } + return nil +} + func (c *client) GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) { readClosersWithLabel := map[io.ReadCloser]string{} for _, container := range containerNames { diff --git a/probe/kubernetes/controls.go b/probe/kubernetes/controls.go index ce55b24d9e..797f571f1a 100644 --- a/probe/kubernetes/controls.go +++ b/probe/kubernetes/controls.go @@ -11,10 +11,11 @@ import ( // Control IDs used by the kubernetes integration. const ( - GetLogs = report.KubernetesGetLogs - DeletePod = report.KubernetesDeletePod - ScaleUp = report.KubernetesScaleUp - ScaleDown = report.KubernetesScaleDown + CreateVolumeSnapshot = report.KubernetesCreateVolumeSnapshot + GetLogs = report.KubernetesGetLogs + DeletePod = report.KubernetesDeletePod + ScaleUp = report.KubernetesScaleUp + ScaleDown = report.KubernetesScaleDown ) // GetLogs is the control to get the logs for a kubernetes pod @@ -43,6 +44,14 @@ func (r *Reporter) GetLogs(req xfer.Request, namespaceID, podID string, containe } } +func (r *Reporter) createVolumeSnapshot(req xfer.Request, namespaceID, persistentVolumeClaimID, capacity string) xfer.Response { + err := r.client.CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity) + if err != nil { + return xfer.ResponseError(err) + } + return xfer.Response{} +} + func (r *Reporter) deletePod(req xfer.Request, namespaceID, podID string, _ []string) xfer.Response { if err := r.client.DeletePod(namespaceID, podID); err != nil { return xfer.ResponseError(err) @@ -95,6 +104,28 @@ func (r *Reporter) CaptureDeployment(f func(xfer.Request, string, string) xfer.R } } +// CapturePersistentVolumeClaim will return name, namespace and capacity of PVC +func (r *Reporter) CapturePersistentVolumeClaim(f func(xfer.Request, string, string, string) xfer.Response) func(xfer.Request) xfer.Response { + return func(req xfer.Request) xfer.Response { + uid, ok := report.ParsePersistentVolumeClaimNodeID(req.NodeID) + if !ok { + return xfer.ResponseErrorf("Invalid ID: %s", req.NodeID) + } + // find persistentVolumeClaim by UID + var persistentVolumeClaim PersistentVolumeClaim + r.client.WalkPersistentVolumeClaims(func(p PersistentVolumeClaim) error { + if p.UID() == uid { + persistentVolumeClaim = p + } + return nil + }) + if persistentVolumeClaim == nil { + return xfer.ResponseErrorf("Persistent volume claim not found: %s", uid) + } + return f(req, persistentVolumeClaim.Namespace(), persistentVolumeClaim.Name(), persistentVolumeClaim.GetCapacity()) + } +} + // ScaleUp is the control to scale up a deployment func (r *Reporter) ScaleUp(req xfer.Request, namespace, id string) xfer.Response { return xfer.ResponseError(r.client.ScaleUp(report.Deployment, namespace, id)) @@ -107,16 +138,18 @@ func (r *Reporter) ScaleDown(req xfer.Request, namespace, id string) xfer.Respon func (r *Reporter) registerControls() { controls := map[string]xfer.ControlHandlerFunc{ - GetLogs: r.CapturePod(r.GetLogs), - DeletePod: r.CapturePod(r.deletePod), - ScaleUp: r.CaptureDeployment(r.ScaleUp), - ScaleDown: r.CaptureDeployment(r.ScaleDown), + CreateVolumeSnapshot: r.CapturePersistentVolumeClaim(r.createVolumeSnapshot), + GetLogs: r.CapturePod(r.GetLogs), + DeletePod: r.CapturePod(r.deletePod), + ScaleUp: r.CaptureDeployment(r.ScaleUp), + ScaleDown: r.CaptureDeployment(r.ScaleDown), } r.handlerRegistry.Batch(nil, controls) } func (r *Reporter) deregisterControls() { controls := []string{ + CreateVolumeSnapshot, GetLogs, DeletePod, ScaleUp, diff --git a/probe/kubernetes/persistentvolumeclaim.go b/probe/kubernetes/persistentvolumeclaim.go index 665ef44041..6237acc57b 100644 --- a/probe/kubernetes/persistentvolumeclaim.go +++ b/probe/kubernetes/persistentvolumeclaim.go @@ -17,8 +17,9 @@ const ( type PersistentVolumeClaim interface { Meta Selector() (labels.Selector, error) - GetNode() report.Node + GetNode(string) report.Node GetStorageClass() string + GetCapacity() string } // persistentVolumeClaim represents kubernetes Persistent Volume Claims @@ -47,14 +48,32 @@ func (p *persistentVolumeClaim) GetStorageClass() string { return storageClassName } +// GetCapacity returns the storage size of PVC +func (p *persistentVolumeClaim) GetCapacity() string { + capacity := p.Spec.Resources.Requests[apiv1.ResourceStorage] + if capacity.String() != "" { + return capacity.String() + } + return "" +} + // GetNode returns Persistent Volume Claim as Node -func (p *persistentVolumeClaim) GetNode() report.Node { - return p.MetaNode(report.MakePersistentVolumeClaimNodeID(p.UID())).WithLatests(map[string]string{ - NodeType: "Persistent Volume Claim", - Status: string(p.Status.Phase), - VolumeName: p.Spec.VolumeName, - StorageClassName: p.GetStorageClass(), - }) +func (p *persistentVolumeClaim) GetNode(probeID string) report.Node { + latests := map[string]string{ + NodeType: "Persistent Volume Claim", + Status: string(p.Status.Phase), + VolumeName: p.Spec.VolumeName, + StorageClassName: p.GetStorageClass(), + report.ControlProbeID: probeID, + } + + if p.GetCapacity() != "" { + latests[VolumeCapacity] = p.GetCapacity() + } + + return p.MetaNode(report.MakePersistentVolumeClaimNodeID(p.UID())). + WithLatests(latests). + WithLatestActiveControls(CreateVolumeSnapshot) } // Selector returns all Persistent Volume Claim selector diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index 23a72a83cd..fc243ec4e5 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -36,6 +36,7 @@ const ( StorageDriver = report.KubernetesStorageDriver VolumeSnapshotName = report.KubernetesVolumeSnapshotName SnapshotData = report.KubernetesSnapshotData + VolumeCapacity = report.KubernetesVolumeCapacity ) // Exposed for testing @@ -124,6 +125,7 @@ var ( Status: {ID: Status, Label: "Status", From: report.FromLatest, Priority: 3}, VolumeName: {ID: VolumeName, Label: "Volume", From: report.FromLatest, Priority: 4}, StorageClassName: {ID: StorageClassName, Label: "Storage class", From: report.FromLatest, Priority: 5}, + VolumeCapacity: {ID: VolumeCapacity, Label: "Capacity", From: report.FromLatest, Priority: 6}, } StorageClassMetadataTemplates = report.MetadataTemplates{ @@ -463,8 +465,14 @@ func (r *Reporter) persistentVolumeClaimTopology() (report.Topology, []Persisten result := report.MakeTopology(). WithMetadataTemplates(PersistentVolumeClaimMetadataTemplates). WithTableTemplates(TableTemplates) + result.Controls.AddControl(report.Control{ + ID: CreateVolumeSnapshot, + Human: "Create snapshot", + Icon: "fa-camera", + Rank: 0, + }) err := r.client.WalkPersistentVolumeClaims(func(p PersistentVolumeClaim) error { - result.AddNode(p.GetNode()) + result.AddNode(p.GetNode(r.probeID)) persistentVolumeClaims = append(persistentVolumeClaims, p) return nil }) diff --git a/probe/kubernetes/reporter_test.go b/probe/kubernetes/reporter_test.go index dea19c64cd..9c2aec31f7 100644 --- a/probe/kubernetes/reporter_test.go +++ b/probe/kubernetes/reporter_test.go @@ -187,6 +187,9 @@ func (c *mockClient) ScaleUp(resource, namespaceID, id string) error { func (c *mockClient) ScaleDown(resource, namespaceID, id string) error { return nil } +func (c *mockClient) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error { + return nil +} type mockPipeClient map[string]xfer.Pipe diff --git a/report/map_keys.go b/report/map_keys.go index e6d39c810d..97a7a49ef9 100644 --- a/report/map_keys.go +++ b/report/map_keys.go @@ -83,6 +83,8 @@ const ( KubernetesStorageDriver = "kubernetes_storage_driver" KubernetesVolumeSnapshotName = "kubernetes_volume_snapshot_name" KubernetesSnapshotData = "kuberneets_snapshot_data" + KubernetesCreateVolumeSnapshot = "kubernetes_create_volume_snapshot" + KubernetesVolumeCapacity = "kubernetes_volume_capacity" // probe/awsecs ECSCluster = "ecs_cluster" ECSCreatedAt = "ecs_created_at" From 4701c61969ebe20a281f48a523c290c16dda38cf Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Wed, 26 Sep 2018 13:59:23 +0530 Subject: [PATCH 22/25] Add clone support for volume snapshot - Add control on volume snapshot to take clone - Add control on volume snapshot to delete it Signed-off-by: Akash Srivastava --- probe/kubernetes/client.go | 70 ++++++++++++++++++++++++++++++ probe/kubernetes/controls.go | 45 +++++++++++++++++++ probe/kubernetes/reporter.go | 12 +++++ probe/kubernetes/reporter_test.go | 6 +++ probe/kubernetes/volumesnapshot.go | 25 ++++++++++- report/map_keys.go | 2 + 6 files changed, 158 insertions(+), 2 deletions(-) diff --git a/probe/kubernetes/client.go b/probe/kubernetes/client.go index cbc0fa8d59..e10557fd17 100644 --- a/probe/kubernetes/client.go +++ b/probe/kubernetes/client.go @@ -1,6 +1,7 @@ package kubernetes import ( + "errors" "fmt" "io" "strings" @@ -21,6 +22,7 @@ import ( apiextensionsv1beta1 "k8s.io/api/extensions/v1beta1" storagev1 "k8s.io/api/storage/v1" apierrors "k8s.io/apimachinery/pkg/api/errors" + "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/fields" "k8s.io/apimachinery/pkg/runtime/schema" @@ -50,9 +52,11 @@ type Client interface { WatchPods(f func(Event, Pod)) + CloneVolumeSnapshot(namespaceID, volumeSnapshotID, persistentVolumeClaimID, capacity string) error CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error GetLogs(namespaceID, podID string, containerNames []string) (io.ReadCloser, error) DeletePod(namespaceID, podID string) error + DeleteVolumeSnapshot(namespaceID, volumeSnapshotID string) error ScaleUp(resource, namespaceID, id string) error ScaleDown(resource, namespaceID, id string) error } @@ -430,6 +434,68 @@ func (c *client) WalkVolumeSnapshotData(f func(VolumeSnapshotData) error) error return nil } +func (c *client) CloneVolumeSnapshot(namespaceID, volumeSnapshotID, persistentVolumeClaimID, capacity string) error { + var scName string + var claimSize string + UID := strings.Split(uuid.New(), "-") + scProvisionerName := "volumesnapshot.external-storage.k8s.io/snapshot-promoter" + scList, err := c.client.StorageV1().StorageClasses().List(metav1.ListOptions{}) + if err != nil { + return err + } + // Retrieve the first snapshot-promoter storage class + for _, sc := range scList.Items { + if sc.Provisioner == scProvisionerName { + scName = sc.Name + break + } + } + if scName == "" { + return errors.New("snapshot-promoter storage class is not present") + } + volumeSnapshot, _ := c.snapshotClient.VolumesnapshotV1().VolumeSnapshots(namespaceID).Get(volumeSnapshotID, metav1.GetOptions{}) + if volumeSnapshot.Spec.PersistentVolumeClaimName != "" { + persistentVolumeClaim, err := c.client.CoreV1().PersistentVolumeClaims(namespaceID).Get(volumeSnapshot.Spec.PersistentVolumeClaimName, metav1.GetOptions{}) + if err == nil { + storage := persistentVolumeClaim.Spec.Resources.Requests[apiv1.ResourceStorage] + if storage.String() != "" { + claimSize = storage.String() + } + } + } + // Set default volume size to the one stored in volume snapshot annotation, + // if unable to get PVC size. + if claimSize == "" { + claimSize = capacity + } + + persistentVolumeClaim := &apiv1.PersistentVolumeClaim{ + ObjectMeta: metav1.ObjectMeta{ + Name: "clone-" + persistentVolumeClaimID + "-" + UID[1], + Namespace: namespaceID, + Annotations: map[string]string{ + "snapshot.alpha.kubernetes.io/snapshot": volumeSnapshotID, + }, + }, + Spec: apiv1.PersistentVolumeClaimSpec{ + StorageClassName: &scName, + AccessModes: []apiv1.PersistentVolumeAccessMode{ + apiv1.ReadWriteOnce, + }, + Resources: apiv1.ResourceRequirements{ + Requests: apiv1.ResourceList{ + apiv1.ResourceName(apiv1.ResourceStorage): resource.MustParse(claimSize), + }, + }, + }, + } + _, err = c.client.CoreV1().PersistentVolumeClaims(namespaceID).Create(persistentVolumeClaim) + if err != nil { + return err + } + return nil +} + func (c *client) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error { UID := strings.Split(uuid.New(), "-") volumeSnapshot := &snapshotv1.VolumeSnapshot{ @@ -479,6 +545,10 @@ func (c *client) DeletePod(namespaceID, podID string) error { return c.client.CoreV1().Pods(namespaceID).Delete(podID, &metav1.DeleteOptions{}) } +func (c *client) DeleteVolumeSnapshot(namespaceID, volumeSnapshotID string) error { + return c.snapshotClient.VolumesnapshotV1().VolumeSnapshots(namespaceID).Delete(volumeSnapshotID, &metav1.DeleteOptions{}) +} + func (c *client) ScaleUp(resource, namespaceID, id string) error { return c.modifyScale(resource, namespaceID, id, func(scale *apiextensionsv1beta1.Scale) { scale.Spec.Replicas++ diff --git a/probe/kubernetes/controls.go b/probe/kubernetes/controls.go index 797f571f1a..191f79dafd 100644 --- a/probe/kubernetes/controls.go +++ b/probe/kubernetes/controls.go @@ -11,9 +11,11 @@ import ( // Control IDs used by the kubernetes integration. const ( + CloneVolumeSnapshot = report.KubernetesCloneVolumeSnapshot CreateVolumeSnapshot = report.KubernetesCreateVolumeSnapshot GetLogs = report.KubernetesGetLogs DeletePod = report.KubernetesDeletePod + DeleteVolumeSnapshot = report.KubernetesDeleteVolumeSnapshot ScaleUp = report.KubernetesScaleUp ScaleDown = report.KubernetesScaleDown ) @@ -44,6 +46,14 @@ func (r *Reporter) GetLogs(req xfer.Request, namespaceID, podID string, containe } } +func (r *Reporter) cloneVolumeSnapshot(req xfer.Request, namespaceID, volumeSnapshotID, persistentVolumeClaimID, capacity string) xfer.Response { + err := r.client.CloneVolumeSnapshot(namespaceID, volumeSnapshotID, persistentVolumeClaimID, capacity) + if err != nil { + return xfer.ResponseError(err) + } + return xfer.Response{} +} + func (r *Reporter) createVolumeSnapshot(req xfer.Request, namespaceID, persistentVolumeClaimID, capacity string) xfer.Response { err := r.client.CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity) if err != nil { @@ -61,6 +71,15 @@ func (r *Reporter) deletePod(req xfer.Request, namespaceID, podID string, _ []st } } +func (r *Reporter) deleteVolumeSnapshot(req xfer.Request, namespaceID, volumeSnapshotID, _, _ string) xfer.Response { + if err := r.client.DeleteVolumeSnapshot(namespaceID, volumeSnapshotID); err != nil { + return xfer.ResponseError(err) + } + return xfer.Response{ + RemovedNode: req.NodeID, + } +} + // CapturePod is exported for testing func (r *Reporter) CapturePod(f func(xfer.Request, string, string, []string) xfer.Response) func(xfer.Request) xfer.Response { return func(req xfer.Request) xfer.Response { @@ -126,6 +145,28 @@ func (r *Reporter) CapturePersistentVolumeClaim(f func(xfer.Request, string, str } } +// CaptureVolumeSnapshot will return name, pvc name, namespace and capacity of volume snapshot +func (r *Reporter) CaptureVolumeSnapshot(f func(xfer.Request, string, string, string, string) xfer.Response) func(xfer.Request) xfer.Response { + return func(req xfer.Request) xfer.Response { + uid, ok := report.ParseVolumeSnapshotNodeID(req.NodeID) + if !ok { + return xfer.ResponseErrorf("Invalid ID: %s", req.NodeID) + } + // find volume snapshot by UID + var volumeSnapshot VolumeSnapshot + r.client.WalkVolumeSnapshots(func(p VolumeSnapshot) error { + if p.UID() == uid { + volumeSnapshot = p + } + return nil + }) + if volumeSnapshot == nil { + return xfer.ResponseErrorf("Volume snapshot not found: %s", uid) + } + return f(req, volumeSnapshot.Namespace(), volumeSnapshot.Name(), volumeSnapshot.GetVolumeName(), volumeSnapshot.GetCapacity()) + } +} + // ScaleUp is the control to scale up a deployment func (r *Reporter) ScaleUp(req xfer.Request, namespace, id string) xfer.Response { return xfer.ResponseError(r.client.ScaleUp(report.Deployment, namespace, id)) @@ -138,9 +179,11 @@ func (r *Reporter) ScaleDown(req xfer.Request, namespace, id string) xfer.Respon func (r *Reporter) registerControls() { controls := map[string]xfer.ControlHandlerFunc{ + CloneVolumeSnapshot: r.CaptureVolumeSnapshot(r.cloneVolumeSnapshot), CreateVolumeSnapshot: r.CapturePersistentVolumeClaim(r.createVolumeSnapshot), GetLogs: r.CapturePod(r.GetLogs), DeletePod: r.CapturePod(r.deletePod), + DeleteVolumeSnapshot: r.CaptureVolumeSnapshot(r.deleteVolumeSnapshot), ScaleUp: r.CaptureDeployment(r.ScaleUp), ScaleDown: r.CaptureDeployment(r.ScaleDown), } @@ -149,9 +192,11 @@ func (r *Reporter) registerControls() { func (r *Reporter) deregisterControls() { controls := []string{ + CloneVolumeSnapshot, CreateVolumeSnapshot, GetLogs, DeletePod, + DeleteVolumeSnapshot, ScaleUp, ScaleDown, } diff --git a/probe/kubernetes/reporter.go b/probe/kubernetes/reporter.go index fc243ec4e5..3bc120cd48 100644 --- a/probe/kubernetes/reporter.go +++ b/probe/kubernetes/reporter.go @@ -497,6 +497,18 @@ func (r *Reporter) volumeSnapshotTopology() (report.Topology, []VolumeSnapshot, result := report.MakeTopology(). WithMetadataTemplates(VolumeSnapshotMetadataTemplates). WithTableTemplates(TableTemplates) + result.Controls.AddControl(report.Control{ + ID: CloneVolumeSnapshot, + Human: "Clone snapshot", + Icon: "fa-clone", + Rank: 0, + }) + result.Controls.AddControl(report.Control{ + ID: DeleteVolumeSnapshot, + Human: "Delete", + Icon: "fa-trash-o", + Rank: 1, + }) err := r.client.WalkVolumeSnapshots(func(p VolumeSnapshot) error { result.AddNode(p.GetNode(r.probeID)) volumeSnapshots = append(volumeSnapshots, p) diff --git a/probe/kubernetes/reporter_test.go b/probe/kubernetes/reporter_test.go index 9c2aec31f7..bc11746cf9 100644 --- a/probe/kubernetes/reporter_test.go +++ b/probe/kubernetes/reporter_test.go @@ -187,9 +187,15 @@ func (c *mockClient) ScaleUp(resource, namespaceID, id string) error { func (c *mockClient) ScaleDown(resource, namespaceID, id string) error { return nil } +func (c *mockClient) CloneVolumeSnapshot(namespaceID, VolumeSnapshotID, persistentVolumeClaimID, capacity string) error { + return nil +} func (c *mockClient) CreateVolumeSnapshot(namespaceID, persistentVolumeClaimID, capacity string) error { return nil } +func (c *mockClient) DeleteVolumeSnapshot(namespaceID, VolumeSnapshotID string) error { + return nil +} type mockPipeClient map[string]xfer.Pipe diff --git a/probe/kubernetes/volumesnapshot.go b/probe/kubernetes/volumesnapshot.go index 153bf23c29..96f1d1b402 100644 --- a/probe/kubernetes/volumesnapshot.go +++ b/probe/kubernetes/volumesnapshot.go @@ -10,10 +10,17 @@ const ( SnapshotPVName = "SnapshotMetadata-PVName" ) +// Capacity is the annotation key which provides the storage size +const ( + Capacity = "capacity" +) + // VolumeSnapshot represent kubernetes VolumeSnapshot interface type VolumeSnapshot interface { Meta GetNode(probeID string) report.Node + GetVolumeName() string + GetCapacity() string } // volumeSnapshot represents kubernetes volume snapshots @@ -27,13 +34,27 @@ func NewVolumeSnapshot(p *snapshotv1.VolumeSnapshot) VolumeSnapshot { return &volumeSnapshot{VolumeSnapshot: p, Meta: meta{p.ObjectMeta}} } +// GetVolumeName returns the PVC name for volume snapshot +func (p *volumeSnapshot) GetVolumeName() string { + return p.Spec.PersistentVolumeClaimName +} + +// GetCapacity returns the capacity of the source PVC stored in annotation +func (p *volumeSnapshot) GetCapacity() string { + capacity := p.GetAnnotations()[Capacity] + if capacity != "" { + return capacity + } + return "" +} + // GetNode returns VolumeSnapshot as Node func (p *volumeSnapshot) GetNode(probeID string) report.Node { return p.MetaNode(report.MakeVolumeSnapshotNodeID(p.UID())).WithLatests(map[string]string{ report.ControlProbeID: probeID, NodeType: "Volume Snapshot", - VolumeClaim: p.Spec.PersistentVolumeClaimName, + VolumeClaim: p.GetVolumeName(), SnapshotData: p.Spec.SnapshotDataName, VolumeName: p.GetLabels()[SnapshotPVName], - }) + }).WithLatestActiveControls(CloneVolumeSnapshot, DeleteVolumeSnapshot) } diff --git a/report/map_keys.go b/report/map_keys.go index 97a7a49ef9..dc72f6cc58 100644 --- a/report/map_keys.go +++ b/report/map_keys.go @@ -85,6 +85,8 @@ const ( KubernetesSnapshotData = "kuberneets_snapshot_data" KubernetesCreateVolumeSnapshot = "kubernetes_create_volume_snapshot" KubernetesVolumeCapacity = "kubernetes_volume_capacity" + KubernetesCloneVolumeSnapshot = "kubernetes_clone_volume_snapshot" + KubernetesDeleteVolumeSnapshot = "kubernetes_delete_volume_snapshot" // probe/awsecs ECSCluster = "ecs_cluster" ECSCreatedAt = "ecs_created_at" From bc550e8e1d8c445345c3f347832fc4f3c00646ef Mon Sep 17 00:00:00 2001 From: Akash Srivastava Date: Wed, 17 Oct 2018 17:53:47 +0530 Subject: [PATCH 23/25] Add rules in clusterrole for k8s snapshot components This will add rules to cluster role for k8s snapshot components. These RBAC permissions are required for scope to fetch details about volumesnapshots and volumesnapshotdata resources. Signed-off-by: Akash Srivastava --- examples/k8s/cluster-role.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/examples/k8s/cluster-role.yaml b/examples/k8s/cluster-role.yaml index f51d9a7bda..5f70075ef1 100644 --- a/examples/k8s/cluster-role.yaml +++ b/examples/k8s/cluster-role.yaml @@ -51,3 +51,11 @@ rules: verbs: - list - watch +- apiGroups: + - volumesnapshot.external-storage.k8s.io + resources: + - volumesnapshots + - volumesnapshotdatas + verbs: + - list + - watch From 9523295cfa29c9d026ba856750c8e999f54b79e2 Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 11 Oct 2018 08:37:21 +0000 Subject: [PATCH 24/25] Pass Go context down to Renderers This is useful for cancellation or tracing. --- app/api_topologies.go | 15 +++++++-------- app/api_topologies_test.go | 8 +++++--- app/api_topology.go | 6 +++--- app/benchmark_internal_test.go | 8 +++++--- render/benchmark_test.go | 3 ++- render/container.go | 13 +++++++------ render/container_test.go | 13 +++++++------ render/detailed/node_test.go | 9 +++++---- render/detailed/parents_test.go | 12 +++++++----- render/detailed/summary.go | 4 ++-- render/detailed/summary_test.go | 5 +++-- render/endpoint.go | 8 +++++--- render/filters.go | 9 +++++---- render/filters_test.go | 14 ++++++++------ render/host_test.go | 3 ++- render/memoise.go | 5 +++-- render/memoise_test.go | 16 +++++++++------- render/metrics.go | 6 ++++-- render/metrics_test.go | 3 ++- render/persistentvolume.go | 12 +++++++----- render/pod.go | 5 +++-- render/pod_test.go | 9 +++++---- render/process.go | 8 +++++--- render/process_test.go | 7 ++++--- render/render.go | 20 +++++++++++--------- render/render_test.go | 11 ++++++----- render/selectors.go | 4 +++- render/short_lived_connections_test.go | 5 +++-- 28 files changed, 138 insertions(+), 103 deletions(-) diff --git a/app/api_topologies.go b/app/api_topologies.go index 7298542b4f..7503771977 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -1,6 +1,7 @@ package app import ( + "context" "fmt" "net/http" "net/url" @@ -9,8 +10,6 @@ import ( "sync" "time" - "context" - "github.com/gorilla/mux" log "github.com/sirupsen/logrus" @@ -479,32 +478,32 @@ func (r *Registry) makeTopologyList(rep Reporter) CtxHandlerFunc { respondWith(w, http.StatusInternalServerError, err) return } - respondWith(w, http.StatusOK, r.renderTopologies(report, req)) + respondWith(w, http.StatusOK, r.renderTopologies(ctx, report, req)) } } -func (r *Registry) renderTopologies(rpt report.Report, req *http.Request) []APITopologyDesc { +func (r *Registry) renderTopologies(ctx context.Context, rpt report.Report, req *http.Request) []APITopologyDesc { topologies := []APITopologyDesc{} req.ParseForm() r.walk(func(desc APITopologyDesc) { renderer, filter, _ := r.RendererForTopology(desc.id, req.Form, rpt) - desc.Stats = computeStats(rpt, renderer, filter) + desc.Stats = computeStats(ctx, rpt, renderer, filter) for i, sub := range desc.SubTopologies { renderer, filter, _ := r.RendererForTopology(sub.id, req.Form, rpt) - desc.SubTopologies[i].Stats = computeStats(rpt, renderer, filter) + desc.SubTopologies[i].Stats = computeStats(ctx, rpt, renderer, filter) } topologies = append(topologies, desc) }) return updateFilters(rpt, topologies) } -func computeStats(rpt report.Report, renderer render.Renderer, transformer render.Transformer) topologyStats { +func computeStats(ctx context.Context, rpt report.Report, renderer render.Renderer, transformer render.Transformer) topologyStats { var ( nodes int realNodes int edges int ) - r := render.Render(rpt, renderer, transformer) + r := render.Render(ctx, rpt, renderer, transformer) for _, n := range r.Nodes { nodes++ if n.Topology != render.Pseudo { diff --git a/app/api_topologies_test.go b/app/api_topologies_test.go index c8d117914c..7c8511534f 100644 --- a/app/api_topologies_test.go +++ b/app/api_topologies_test.go @@ -2,6 +2,7 @@ package app_test import ( "bytes" + "context" "net/http/httptest" "net/url" "testing" @@ -118,7 +119,7 @@ func TestRendererForTopologyWithFiltering(t *testing.T) { input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{ docker.LabelPrefix + "works.weave.role": "system", }) - have := utils.Prune(render.Render(input, renderer, filter).Nodes) + have := utils.Prune(render.Render(context.Background(), input, renderer, filter).Nodes) want := utils.Prune(expected.RenderedContainers.Copy()) delete(want, fixture.ClientContainerNodeID) delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID)) @@ -149,7 +150,7 @@ func TestRendererForTopologyNoFiltering(t *testing.T) { input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{ docker.LabelPrefix + "works.weave.role": "system", }) - have := utils.Prune(render.Render(input, renderer, filter).Nodes) + have := utils.Prune(render.Render(context.Background(), input, renderer, filter).Nodes) want := utils.Prune(expected.RenderedContainers.Copy()) delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID)) delete(want, render.OutgoingInternetID) @@ -183,7 +184,8 @@ func getTestContainerLabelFilterTopologySummary(t *testing.T, exclude bool) (det return nil, err } - return detailed.Summaries(detailed.RenderContext{Report: fixture.Report}, render.Render(fixture.Report, renderer, filter).Nodes), nil + ctx := context.Background() + return detailed.Summaries(ctx, detailed.RenderContext{Report: fixture.Report}, render.Render(ctx, fixture.Report, renderer, filter).Nodes), nil } func TestAPITopologyAddsKubernetes(t *testing.T) { diff --git a/app/api_topology.go b/app/api_topology.go index d00824526b..9f2357af23 100644 --- a/app/api_topology.go +++ b/app/api_topology.go @@ -42,7 +42,7 @@ type rendererHandler func(context.Context, render.Renderer, render.Transformer, // Full topology. func handleTopology(ctx context.Context, renderer render.Renderer, transformer render.Transformer, rc detailed.RenderContext, w http.ResponseWriter, r *http.Request) { respondWith(w, http.StatusOK, APITopology{ - Nodes: detailed.Summaries(rc, render.Render(rc.Report, renderer, transformer).Nodes), + Nodes: detailed.Summaries(ctx, rc, render.Render(ctx, rc.Report, renderer, transformer).Nodes), }) } @@ -58,7 +58,7 @@ func handleNode(ctx context.Context, renderer render.Renderer, transformer rende // filtering, which gives us the node (if it exists at all), and // then (2) applying the filter separately to that result. If the // node is lost in the second step, we simply put it back. - nodes := renderer.Render(rc.Report) + nodes := renderer.Render(ctx, rc.Report) node, ok := nodes.Nodes[nodeID] if !ok { http.NotFound(w, r) @@ -145,7 +145,7 @@ func handleWebsocket( log.Errorf("Error generating report: %v", err) return } - newTopo := detailed.Summaries(RenderContextForReporter(rep, re), render.Render(re, renderer, filter).Nodes) + newTopo := detailed.Summaries(ctx, RenderContextForReporter(rep, re), render.Render(ctx, re, renderer, filter).Nodes) diff := detailed.TopoDiff(previousTopo, newTopo) previousTopo = newTopo diff --git a/app/benchmark_internal_test.go b/app/benchmark_internal_test.go index 9164ffe064..18e79fdd9c 100644 --- a/app/benchmark_internal_test.go +++ b/app/benchmark_internal_test.go @@ -1,6 +1,7 @@ package app import ( + "context" "flag" "math/rand" "net/http" @@ -100,7 +101,7 @@ func renderForTopology(b *testing.B, topologyID string, report report.Report) re if err != nil { b.Fatal(err) } - return render.Render(report, renderer, filter).Nodes + return render.Render(context.Background(), report, renderer, filter).Nodes } func benchmarkRenderTopology(b *testing.B, topologyID string) { @@ -111,7 +112,7 @@ func benchmarkRenderTopology(b *testing.B, topologyID string) { func BenchmarkRenderList(b *testing.B) { benchmarkRender(b, func(report report.Report) { - topologyRegistry.renderTopologies(report, &http.Request{Form: url.Values{}}) + topologyRegistry.renderTopologies(context.Background(), report, &http.Request{Form: url.Values{}}) }) } @@ -140,12 +141,13 @@ func BenchmarkRenderProcessNames(b *testing.B) { } func benchmarkSummarizeTopology(b *testing.B, topologyID string) { + ctx := context.Background() r := getReport(b) rc := detailed.RenderContext{Report: r} nodes := renderForTopology(b, topologyID, r) b.ResetTimer() for i := 0; i < b.N; i++ { - detailed.Summaries(rc, nodes) + detailed.Summaries(ctx, rc, nodes) } } diff --git a/render/benchmark_test.go b/render/benchmark_test.go index 1c6b5aeacc..962f83a4a8 100644 --- a/render/benchmark_test.go +++ b/render/benchmark_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "flag" "io/ioutil" "testing" @@ -51,7 +52,7 @@ func benchmarkRender(b *testing.B, r render.Renderer) { b.StopTimer() render.ResetCache() b.StartTimer() - benchmarkRenderResult = r.Render(report) + benchmarkRenderResult = r.Render(context.Background(), report) if len(benchmarkRenderResult.Nodes) == 0 { b.Errorf("Rendered topology contained no nodes") } diff --git a/render/container.go b/render/container.go index df78553d85..9dca12d64d 100644 --- a/render/container.go +++ b/render/container.go @@ -1,6 +1,7 @@ package render import ( + "context" "regexp" "github.com/weaveworks/scope/probe/docker" @@ -53,8 +54,8 @@ type connectionJoin struct { topology string } -func (c connectionJoin) Render(rpt report.Report) Nodes { - inputNodes := TopologySelector(c.topology).Render(rpt).Nodes +func (c connectionJoin) Render(ctx context.Context, rpt report.Report) Nodes { + inputNodes := TopologySelector(c.topology).Render(ctx, rpt).Nodes // Collect all the IPs we are trying to map to, and which ID they map from var ipNodes = map[string]string{} for _, n := range inputNodes { @@ -92,7 +93,7 @@ func (c connectionJoin) Render(rpt report.Report) Nodes { // from ipNodes, which is populated from c.topology, which // is where MapEndpoints will look. return id - }, c.topology).Render(rpt) + }, c.topology).Render(ctx, rpt) } // FilterEmpty is a Renderer which filters out nodes which have no children @@ -121,9 +122,9 @@ type containerWithImageNameRenderer struct { // Render produces a container graph where the the latest metadata contains the // container image name, if found. -func (r containerWithImageNameRenderer) Render(rpt report.Report) Nodes { - containers := r.Renderer.Render(rpt) - images := SelectContainerImage.Render(rpt) +func (r containerWithImageNameRenderer) Render(ctx context.Context, rpt report.Report) Nodes { + containers := r.Renderer.Render(ctx, rpt) + images := SelectContainerImage.Render(ctx, rpt) outputs := make(report.Nodes, len(containers.Nodes)) for id, c := range containers.Nodes { diff --git a/render/container_test.go b/render/container_test.go index f9565b9978..f86035d133 100644 --- a/render/container_test.go +++ b/render/container_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "fmt" "testing" @@ -53,7 +54,7 @@ func testMap(t *testing.T, f render.MapFunc, input testcase) { } func TestContainerRenderer(t *testing.T) { - have := utils.Prune(render.ContainerWithImageNameRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.ContainerWithImageNameRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedContainers) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -67,7 +68,7 @@ func TestContainerFilterRenderer(t *testing.T) { input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{ docker.LabelPrefix + "works.weave.role": "system", }) - have := utils.Prune(render.Render(input, render.ContainerWithImageNameRenderer, filterApplication).Nodes) + have := utils.Prune(render.Render(context.Background(), input, render.ContainerWithImageNameRenderer, filterApplication).Nodes) want := utils.Prune(expected.RenderedContainers.Copy()) delete(want, fixture.ClientContainerNodeID) if !reflect.DeepEqual(want, have) { @@ -76,7 +77,7 @@ func TestContainerFilterRenderer(t *testing.T) { } func TestContainerHostnameRenderer(t *testing.T) { - have := utils.Prune(render.Render(fixture.Report, render.ContainerHostnameRenderer, render.Transformers(nil)).Nodes) + have := utils.Prune(render.Render(context.Background(), fixture.Report, render.ContainerHostnameRenderer, render.Transformers(nil)).Nodes) want := utils.Prune(expected.RenderedContainerHostnames) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -84,7 +85,7 @@ func TestContainerHostnameRenderer(t *testing.T) { } func TestContainerHostnameFilterRenderer(t *testing.T) { - have := utils.Prune(render.Render(fixture.Report, render.ContainerHostnameRenderer, filterSystem).Nodes) + have := utils.Prune(render.Render(context.Background(), fixture.Report, render.ContainerHostnameRenderer, filterSystem).Nodes) want := utils.Prune(expected.RenderedContainerHostnames.Copy()) delete(want, fixture.ClientContainerHostname) delete(want, fixture.ServerContainerHostname) @@ -95,7 +96,7 @@ func TestContainerHostnameFilterRenderer(t *testing.T) { } func TestContainerImageRenderer(t *testing.T) { - have := utils.Prune(render.Render(fixture.Report, render.ContainerImageRenderer, render.Transformers(nil)).Nodes) + have := utils.Prune(render.Render(context.Background(), fixture.Report, render.ContainerImageRenderer, render.Transformers(nil)).Nodes) want := utils.Prune(expected.RenderedContainerImages) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -103,7 +104,7 @@ func TestContainerImageRenderer(t *testing.T) { } func TestContainerImageFilterRenderer(t *testing.T) { - have := utils.Prune(render.Render(fixture.Report, render.ContainerImageRenderer, filterSystem).Nodes) + have := utils.Prune(render.Render(context.Background(), fixture.Report, render.ContainerImageRenderer, filterSystem).Nodes) want := utils.Prune(expected.RenderedContainerHostnames.Copy()) delete(want, fixture.ClientContainerHostname) delete(want, fixture.ServerContainerHostname) diff --git a/render/detailed/node_test.go b/render/detailed/node_test.go index b22ff40233..5e5f9e635f 100644 --- a/render/detailed/node_test.go +++ b/render/detailed/node_test.go @@ -1,6 +1,7 @@ package detailed_test import ( + "context" "fmt" "testing" @@ -18,7 +19,7 @@ import ( ) func child(t *testing.T, r render.Renderer, id string) detailed.NodeSummary { - s, ok := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, r.Render(fixture.Report).Nodes[id]) + s, ok := detailed.MakeNodeSummary(detailed.RenderContext{Report: fixture.Report}, r.Render(context.Background(), fixture.Report).Nodes[id]) if !ok { t.Fatalf("Expected node %s to be summarizable, but wasn't", id) } @@ -30,7 +31,7 @@ func connectionID(nodeID string, addr string) string { } func TestMakeDetailedHostNode(t *testing.T) { - renderableNodes := render.HostRenderer.Render(fixture.Report).Nodes + renderableNodes := render.HostRenderer.Render(context.Background(), fixture.Report).Nodes renderableNode := renderableNodes[fixture.ClientHostNodeID] have := detailed.MakeNode("hosts", detailed.RenderContext{Report: fixture.Report}, renderableNodes, renderableNode) @@ -177,7 +178,7 @@ func TestMakeDetailedHostNode(t *testing.T) { func TestMakeDetailedContainerNode(t *testing.T) { id := fixture.ServerContainerNodeID - renderableNodes := render.ContainerWithImageNameRenderer.Render(fixture.Report).Nodes + renderableNodes := render.ContainerWithImageNameRenderer.Render(context.Background(), fixture.Report).Nodes renderableNode, ok := renderableNodes[id] if !ok { t.Fatalf("Node not found: %s", id) @@ -306,7 +307,7 @@ func TestMakeDetailedContainerNode(t *testing.T) { func TestMakeDetailedPodNode(t *testing.T) { id := fixture.ServerPodNodeID - renderableNodes := render.PodRenderer.Render(fixture.Report).Nodes + renderableNodes := render.PodRenderer.Render(context.Background(), fixture.Report).Nodes renderableNode, ok := renderableNodes[id] if !ok { t.Fatalf("Node not found: %s", id) diff --git a/render/detailed/parents_test.go b/render/detailed/parents_test.go index 3332d651da..d719595e44 100644 --- a/render/detailed/parents_test.go +++ b/render/detailed/parents_test.go @@ -1,6 +1,7 @@ package detailed_test import ( + "context" "fmt" "testing" @@ -14,6 +15,7 @@ import ( ) func TestParents(t *testing.T) { + ctx := context.Background() for _, c := range []struct { name string node report.Node @@ -21,25 +23,25 @@ func TestParents(t *testing.T) { }{ { name: "Node accidentally tagged with itself", - node: render.HostRenderer.Render(fixture.Report).Nodes[fixture.ClientHostNodeID].WithParents( + node: render.HostRenderer.Render(ctx, fixture.Report).Nodes[fixture.ClientHostNodeID].WithParents( report.MakeSets().Add(report.Host, report.MakeStringSet(fixture.ClientHostNodeID)), ), want: nil, }, { - node: render.HostRenderer.Render(fixture.Report).Nodes[fixture.ClientHostNodeID], + node: render.HostRenderer.Render(ctx, fixture.Report).Nodes[fixture.ClientHostNodeID], want: nil, }, { name: "Container image", - node: render.ContainerImageRenderer.Render(fixture.Report).Nodes[expected.ClientContainerImageNodeID], + node: render.ContainerImageRenderer.Render(ctx, fixture.Report).Nodes[expected.ClientContainerImageNodeID], want: []detailed.Parent{ {ID: fixture.ClientHostNodeID, Label: "client", TopologyID: "hosts"}, }, }, { name: "Container", - node: render.ContainerWithImageNameRenderer.Render(fixture.Report).Nodes[fixture.ClientContainerNodeID], + node: render.ContainerWithImageNameRenderer.Render(ctx, fixture.Report).Nodes[fixture.ClientContainerNodeID], want: []detailed.Parent{ {ID: expected.ClientContainerImageNodeID, Label: fixture.ClientContainerImageName, TopologyID: "containers-by-image"}, {ID: fixture.ClientPodNodeID, Label: "pong-a", TopologyID: "pods"}, @@ -47,7 +49,7 @@ func TestParents(t *testing.T) { }, }, { - node: render.ProcessRenderer.Render(fixture.Report).Nodes[fixture.ClientProcess1NodeID], + node: render.ProcessRenderer.Render(ctx, fixture.Report).Nodes[fixture.ClientProcess1NodeID], want: []detailed.Parent{ {ID: fixture.ClientContainerNodeID, Label: fixture.ClientContainerName, TopologyID: "containers"}, {ID: fixture.ClientHostNodeID, Label: "client", TopologyID: "hosts"}, diff --git a/render/detailed/summary.go b/render/detailed/summary.go index d50417eb62..b20123400e 100644 --- a/render/detailed/summary.go +++ b/render/detailed/summary.go @@ -1,6 +1,7 @@ package detailed import ( + "context" "fmt" "strings" @@ -446,8 +447,7 @@ func (s nodeSummariesByID) Less(i, j int) bool { return s[i].ID < s[j].ID } type NodeSummaries map[string]NodeSummary // Summaries converts RenderableNodes into a set of NodeSummaries -func Summaries(rc RenderContext, rns report.Nodes) NodeSummaries { - +func Summaries(ctx context.Context, rc RenderContext, rns report.Nodes) NodeSummaries { result := NodeSummaries{} for id, node := range rns { if summary, ok := MakeNodeSummary(rc, node); ok { diff --git a/render/detailed/summary_test.go b/render/detailed/summary_test.go index 07ba5e7a4c..8145978807 100644 --- a/render/detailed/summary_test.go +++ b/render/detailed/summary_test.go @@ -1,6 +1,7 @@ package detailed_test import ( + "context" "sort" "testing" "time" @@ -21,7 +22,7 @@ import ( func TestSummaries(t *testing.T) { { // Just a convenient source of some rendered nodes - have := detailed.Summaries(detailed.RenderContext{Report: fixture.Report}, render.ProcessRenderer.Render(fixture.Report).Nodes) + have := detailed.Summaries(context.Background(), detailed.RenderContext{Report: fixture.Report}, render.ProcessRenderer.Render(context.Background(), fixture.Report).Nodes) // The ids of the processes rendered above expectedIDs := []string{ fixture.ClientProcess1NodeID, @@ -53,7 +54,7 @@ func TestSummaries(t *testing.T) { processNode.Metrics = processNode.Metrics.Copy() processNode.Metrics[process.CPUUsage] = metric input.Process.Nodes[fixture.ClientProcess1NodeID] = processNode - have := detailed.Summaries(detailed.RenderContext{Report: input}, render.ProcessRenderer.Render(input).Nodes) + have := detailed.Summaries(context.Background(), detailed.RenderContext{Report: input}, render.ProcessRenderer.Render(context.Background(), input).Nodes) node, ok := have[fixture.ClientProcess1NodeID] if !ok { diff --git a/render/endpoint.go b/render/endpoint.go index 2e610b1f83..c645bb995e 100644 --- a/render/endpoint.go +++ b/render/endpoint.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/report" ) @@ -27,10 +29,10 @@ func MapEndpoints(f endpointMapFunc, topology string) Renderer { return mapEndpoints{f: f, topology: topology} } -func (e mapEndpoints) Render(rpt report.Report) Nodes { +func (e mapEndpoints) Render(ctx context.Context, rpt report.Report) Nodes { local := LocalNetworks(rpt) - endpoints := SelectEndpoint.Render(rpt) - ret := newJoinResults(TopologySelector(e.topology).Render(rpt).Nodes) + endpoints := SelectEndpoint.Render(ctx, rpt) + ret := newJoinResults(TopologySelector(e.topology).Render(ctx, rpt).Nodes) for _, n := range endpoints.Nodes { // Nodes without a hostid are mapped to pseudo nodes, if diff --git a/render/filters.go b/render/filters.go index 8d02a5918f..c586c77dc2 100644 --- a/render/filters.go +++ b/render/filters.go @@ -1,6 +1,7 @@ package render import ( + "context" "strings" "github.com/weaveworks/common/mtime" @@ -23,8 +24,8 @@ type CustomRenderer struct { } // Render implements Renderer -func (c CustomRenderer) Render(rpt report.Report) Nodes { - return c.RenderFunc(c.Renderer.Render(rpt)) +func (c CustomRenderer) Render(ctx context.Context, rpt report.Report) Nodes { + return c.RenderFunc(c.Renderer.Render(ctx, rpt)) } // FilterFunc is the function type used by Filters @@ -112,8 +113,8 @@ func MakeFilterPseudo(f FilterFunc, r Renderer) Renderer { } // Render implements Renderer -func (f Filter) Render(rpt report.Report) Nodes { - return f.FilterFunc.Transform(f.Renderer.Render(rpt)) +func (f Filter) Render(ctx context.Context, rpt report.Report) Nodes { + return f.FilterFunc.Transform(f.Renderer.Render(ctx, rpt)) } // IsConnectedMark is the key added to Node.Metadata by diff --git a/render/filters_test.go b/render/filters_test.go index b31dfc1fb2..9ec5c3ecb3 100644 --- a/render/filters_test.go +++ b/render/filters_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "github.com/weaveworks/common/test" @@ -23,7 +24,7 @@ func TestFilterRender(t *testing.T) { "baz": report.MakeNode("baz"), }} have := report.MakeIDList() - for id := range render.Render(report.MakeReport(), render.ColorConnected(renderer), render.FilterFunc(render.IsConnected)).Nodes { + for id := range render.Render(context.Background(), report.MakeReport(), render.ColorConnected(renderer), render.FilterFunc(render.IsConnected)).Nodes { have = have.Add(id) } want := report.MakeIDList("foo", "bar") @@ -39,13 +40,14 @@ func TestFilterRender2(t *testing.T) { "bar": report.MakeNode("bar").WithAdjacent("foo"), "baz": report.MakeNode("baz"), }} - have := render.Render(report.MakeReport(), renderer, filterBar).Nodes + have := render.Render(context.Background(), report.MakeReport(), renderer, filterBar).Nodes if have["foo"].Adjacency.Contains("bar") { t.Error("adjacencies for removed nodes should have been removed") } } func TestFilterUnconnectedPseudoNodes(t *testing.T) { + ctx := context.Background() // Test pseudo nodes that are made unconnected by filtering // are also removed. { @@ -56,7 +58,7 @@ func TestFilterUnconnectedPseudoNodes(t *testing.T) { } renderer := mockRenderer{Nodes: nodes} want := nodes - have := render.Render(report.MakeReport(), renderer, render.Transformers(nil)).Nodes + have := render.Render(ctx, report.MakeReport(), renderer, render.Transformers(nil)).Nodes if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } @@ -67,7 +69,7 @@ func TestFilterUnconnectedPseudoNodes(t *testing.T) { "bar": report.MakeNode("bar").WithAdjacent("baz"), "baz": report.MakeNode("baz").WithTopology(render.Pseudo), }} - have := render.Render(report.MakeReport(), renderer, filterBar).Nodes + have := render.Render(ctx, report.MakeReport(), renderer, filterBar).Nodes if _, ok := have["baz"]; ok { t.Error("expected the unconnected pseudonode baz to have been removed") } @@ -78,7 +80,7 @@ func TestFilterUnconnectedPseudoNodes(t *testing.T) { "bar": report.MakeNode("bar").WithAdjacent("foo"), "baz": report.MakeNode("baz").WithTopology(render.Pseudo).WithAdjacent("bar"), }} - have := render.Render(report.MakeReport(), renderer, filterBar).Nodes + have := render.Render(ctx, report.MakeReport(), renderer, filterBar).Nodes if _, ok := have["baz"]; ok { t.Error("expected the unconnected pseudonode baz to have been removed") } @@ -92,7 +94,7 @@ func TestFilterUnconnectedSelf(t *testing.T) { "foo": report.MakeNode("foo").WithAdjacent("foo"), } renderer := mockRenderer{Nodes: nodes} - have := render.Render(report.MakeReport(), render.ColorConnected(renderer), render.FilterFunc(render.IsConnected)).Nodes + have := render.Render(context.Background(), report.MakeReport(), render.ColorConnected(renderer), render.FilterFunc(render.IsConnected)).Nodes if len(have) > 0 { t.Error("expected node only connected to self to be removed") } diff --git a/render/host_test.go b/render/host_test.go index 3f30188e61..a1a2b606ff 100644 --- a/render/host_test.go +++ b/render/host_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "github.com/weaveworks/common/test" @@ -12,7 +13,7 @@ import ( ) func TestHostRenderer(t *testing.T) { - have := utils.Prune(render.HostRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.HostRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedHosts) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) diff --git a/render/memoise.go b/render/memoise.go index 93859327d8..69dcaee277 100644 --- a/render/memoise.go +++ b/render/memoise.go @@ -1,6 +1,7 @@ package render import ( + "context" "fmt" "math/rand" "sync" @@ -40,7 +41,7 @@ func Memoise(r Renderer) Renderer { // retrieves a promise from the cache and returns its value, otherwise // it stores a new promise and fulfils it by calling through to // m.Renderer. -func (m *memoise) Render(rpt report.Report) Nodes { +func (m *memoise) Render(ctx context.Context, rpt report.Report) Nodes { key := fmt.Sprintf("%s-%s", rpt.ID, m.id) m.Lock() @@ -53,7 +54,7 @@ func (m *memoise) Render(rpt report.Report) Nodes { renderCache.Set(key, promise) m.Unlock() - output := m.Renderer.Render(rpt) + output := m.Renderer.Render(ctx, rpt) promise.Set(output) diff --git a/render/memoise_test.go b/render/memoise_test.go index 79c779a362..d59d281f91 100644 --- a/render/memoise_test.go +++ b/render/memoise_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "github.com/weaveworks/common/test" @@ -9,13 +10,13 @@ import ( "github.com/weaveworks/scope/test/reflect" ) -type renderFunc func(r report.Report) render.Nodes +type renderFunc func(ctx context.Context, r report.Report) render.Nodes -func (f renderFunc) Render(r report.Report) render.Nodes { return f(r) } +func (f renderFunc) Render(ctx context.Context, r report.Report) render.Nodes { return f(ctx, r) } func TestMemoise(t *testing.T) { calls := 0 - r := renderFunc(func(rpt report.Report) render.Nodes { + r := renderFunc(func(ctx context.Context, rpt report.Report) render.Nodes { calls++ return render.Nodes{Nodes: report.Nodes{rpt.ID: report.MakeNode(rpt.ID)}} }) @@ -27,7 +28,8 @@ func TestMemoise(t *testing.T) { rpt1 := report.MakeReport() - result1 := m.Render(rpt1) + ctx := context.Background() + result1 := m.Render(ctx, rpt1) // it should have rendered it. if _, ok := result1.Nodes[rpt1.ID]; !ok { t.Errorf("Expected rendered report to contain a node, but got: %v", result1) @@ -36,7 +38,7 @@ func TestMemoise(t *testing.T) { t.Errorf("Expected renderer to have been called the first time") } - result2 := m.Render(rpt1) + result2 := m.Render(ctx, rpt1) if !reflect.DeepEqual(result1, result2) { t.Errorf("Expected memoised result to be returned: %s", test.Diff(result1, result2)) } @@ -45,7 +47,7 @@ func TestMemoise(t *testing.T) { } rpt2 := report.MakeReport() - result3 := m.Render(rpt2) + result3 := m.Render(ctx, rpt2) if reflect.DeepEqual(result1, result3) { t.Errorf("Expected different result for different report, but were the same") } @@ -54,7 +56,7 @@ func TestMemoise(t *testing.T) { } render.ResetCache() - result4 := m.Render(rpt1) + result4 := m.Render(ctx, rpt1) if !reflect.DeepEqual(result1, result4) { t.Errorf("Expected original result to be returned: %s", test.Diff(result1, result4)) } diff --git a/render/metrics.go b/render/metrics.go index 92566519b2..2658cdd44a 100644 --- a/render/metrics.go +++ b/render/metrics.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/report" ) @@ -17,8 +19,8 @@ type propagateSingleMetrics struct { r Renderer } -func (p propagateSingleMetrics) Render(rpt report.Report) Nodes { - nodes := p.r.Render(rpt) +func (p propagateSingleMetrics) Render(ctx context.Context, rpt report.Report) Nodes { + nodes := p.r.Render(ctx, rpt) outputs := make(report.Nodes, len(nodes.Nodes)) for id, n := range nodes.Nodes { var first report.Node diff --git a/render/metrics_test.go b/render/metrics_test.go index f604d2fabd..5e6f74e31e 100644 --- a/render/metrics_test.go +++ b/render/metrics_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "time" @@ -159,7 +160,7 @@ func TestPropagateSingleMetrics(t *testing.T) { }, }, } { - got := render.PropagateSingleMetrics(c.topology, mockRenderer{report.Nodes{c.input.ID: c.input}}).Render(report.Report{}).Nodes + got := render.PropagateSingleMetrics(c.topology, mockRenderer{report.Nodes{c.input.ID: c.input}}).Render(context.Background(), report.Report{}).Nodes if !reflect.DeepEqual(got, c.output) { t.Errorf("[%s] Diff: %s", c.name, test.Diff(c.output, got)) } diff --git a/render/persistentvolume.go b/render/persistentvolume.go index 573c43c82b..946ace8ada 100644 --- a/render/persistentvolume.go +++ b/render/persistentvolume.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/probe/kubernetes" "github.com/weaveworks/scope/report" ) @@ -23,7 +25,7 @@ var VolumesRenderer = volumesRenderer{} type volumesRenderer struct{} // Render renders PV & PVC nodes along with adjacency -func (v volumesRenderer) Render(rpt report.Report) Nodes { +func (v volumesRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for id, n := range rpt.PersistentVolumeClaim.Nodes { volume, _ := n.Latest.Lookup(kubernetes.VolumeName) @@ -48,7 +50,7 @@ var PodToVolumeRenderer = podToVolumesRenderer{} type podToVolumesRenderer struct{} // Render renders the Pod nodes having volumes adjacency. -func (v podToVolumesRenderer) Render(rpt report.Report) Nodes { +func (v podToVolumesRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for podID, podNode := range rpt.Pod.Nodes { ClaimName, _ := podNode.Latest.Lookup(kubernetes.VolumeClaim) @@ -72,7 +74,7 @@ var PVCToStorageClassRenderer = pvcToStorageClassRenderer{} type pvcToStorageClassRenderer struct{} // Render renders the PVC & Storage Class nodes with adjacency. -func (v pvcToStorageClassRenderer) Render(rpt report.Report) Nodes { +func (v pvcToStorageClassRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for scID, scNode := range rpt.StorageClass.Nodes { storageClass, _ := scNode.Latest.Lookup(kubernetes.Name) @@ -95,7 +97,7 @@ var PVToSnapshotRenderer = pvToSnapshotRenderer{} type pvToSnapshotRenderer struct{} //Render renders the PV & Snapshot nodes with adjacency. -func (v pvToSnapshotRenderer) Render(rpt report.Report) Nodes { +func (v pvToSnapshotRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for pvNodeID, p := range rpt.PersistentVolume.Nodes { volumeName, _ := p.Latest.Lookup(kubernetes.Name) @@ -119,7 +121,7 @@ type volumeSnapshotRenderer struct{} // Render renders the volumeSnapshots & volumeSnapshotData with adjacency // It checks for the volumeSnapshotData name in volumeSnapshot, adjacency is created by matching the volumeSnapshotData name. -func (v volumeSnapshotRenderer) Render(rpt report.Report) Nodes { +func (v volumeSnapshotRenderer) Render(ctx context.Context, rpt report.Report) Nodes { nodes := make(report.Nodes) for volumeSnapshotID, volumeSnapshotNode := range rpt.VolumeSnapshot.Nodes { snapshotData, _ := volumeSnapshotNode.Latest.Lookup(kubernetes.SnapshotData) diff --git a/render/pod.go b/render/pod.go index 49b97be876..7d8e489a29 100644 --- a/render/pod.go +++ b/render/pod.go @@ -1,6 +1,7 @@ package render import ( + "context" "strings" "github.com/weaveworks/scope/probe/docker" @@ -162,8 +163,8 @@ type Map2Parent struct { } // Render implements Renderer -func (m Map2Parent) Render(rpt report.Report) Nodes { - input := m.chainRenderer.Render(rpt) +func (m Map2Parent) Render(ctx context.Context, rpt report.Report) Nodes { + input := m.chainRenderer.Render(ctx, rpt) ret := newJoinResults(nil) for _, n := range input.Nodes { diff --git a/render/pod_test.go b/render/pod_test.go index d707110d39..c6dcd6c9a8 100644 --- a/render/pod_test.go +++ b/render/pod_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "github.com/weaveworks/common/test" @@ -13,7 +14,7 @@ import ( ) func TestPodRenderer(t *testing.T) { - have := utils.Prune(render.PodRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.PodRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedPods) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -33,7 +34,7 @@ func TestPodFilterRenderer(t *testing.T) { kubernetes.Namespace: "kube-system", }) - have := utils.Prune(render.Render(input, render.PodRenderer, filterNonKubeSystem).Nodes) + have := utils.Prune(render.Render(context.Background(), input, render.PodRenderer, filterNonKubeSystem).Nodes) want := utils.Prune(expected.RenderedPods.Copy()) delete(want, fixture.ClientPodNodeID) if !reflect.DeepEqual(want, have) { @@ -42,7 +43,7 @@ func TestPodFilterRenderer(t *testing.T) { } func TestPodServiceRenderer(t *testing.T) { - have := utils.Prune(render.PodServiceRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.PodServiceRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedPodServices) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -57,7 +58,7 @@ func TestPodServiceFilterRenderer(t *testing.T) { kubernetes.Namespace: "kube-system", }) - have := utils.Prune(render.Render(input, render.PodServiceRenderer, filterNonKubeSystem).Nodes) + have := utils.Prune(render.Render(context.Background(), input, render.PodServiceRenderer, filterNonKubeSystem).Nodes) want := utils.Prune(expected.RenderedPodServices.Copy()) delete(want, fixture.ServiceNodeID) delete(want, render.IncomingInternetID) diff --git a/render/process.go b/render/process.go index 37e994133d..b3a841f347 100644 --- a/render/process.go +++ b/render/process.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/probe/endpoint" "github.com/weaveworks/scope/probe/process" "github.com/weaveworks/scope/report" @@ -43,11 +45,11 @@ var ProcessNameRenderer = ColorConnected(CustomRenderer{RenderFunc: processes2Na type endpoints2Processes struct { } -func (e endpoints2Processes) Render(rpt report.Report) Nodes { +func (e endpoints2Processes) Render(ctx context.Context, rpt report.Report) Nodes { if len(rpt.Process.Nodes) == 0 { return Nodes{} } - endpoints := SelectEndpoint.Render(rpt).Nodes + endpoints := SelectEndpoint.Render(ctx, rpt).Nodes return MapEndpoints( func(n report.Node) string { pid, ok := n.Latest.Lookup(process.PID) @@ -62,7 +64,7 @@ func (e endpoints2Processes) Render(rpt report.Report) Nodes { return "" } return report.MakeProcessNodeID(hostID, pid) - }, report.Process).Render(rpt) + }, report.Process).Render(ctx, rpt) } // When there is more than one connection originating from a source diff --git a/render/process_test.go b/render/process_test.go index cdef54a15c..eb515c9f5d 100644 --- a/render/process_test.go +++ b/render/process_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "testing" "github.com/weaveworks/common/test" @@ -12,7 +13,7 @@ import ( ) func TestEndpointRenderer(t *testing.T) { - have := utils.Prune(render.EndpointRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.EndpointRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedEndpoints) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -20,7 +21,7 @@ func TestEndpointRenderer(t *testing.T) { } func TestProcessRenderer(t *testing.T) { - have := utils.Prune(render.ProcessRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.ProcessRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedProcesses) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) @@ -28,7 +29,7 @@ func TestProcessRenderer(t *testing.T) { } func TestProcessNameRenderer(t *testing.T) { - have := utils.Prune(render.ProcessNameRenderer.Render(fixture.Report).Nodes) + have := utils.Prune(render.ProcessNameRenderer.Render(context.Background(), fixture.Report).Nodes) want := utils.Prune(expected.RenderedProcessNames) if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) diff --git a/render/render.go b/render/render.go index ee2429d61b..6b1955a7c5 100644 --- a/render/render.go +++ b/render/render.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/report" ) @@ -13,7 +15,7 @@ type MapFunc func(report.Node) report.Node // Renderer is something that can render a report to a set of Nodes. type Renderer interface { - Render(report.Report) Nodes + Render(context.Context, report.Report) Nodes } // Nodes is the result of Rendering @@ -48,8 +50,8 @@ func (ts Transformers) Transform(nodes Nodes) Nodes { } // Render renders the report and then transforms it -func Render(rpt report.Report, renderer Renderer, transformer Transformer) Nodes { - return transformer.Transform(renderer.Render(rpt)) +func Render(ctx context.Context, rpt report.Report, renderer Renderer, transformer Transformer) Nodes { + return transformer.Transform(renderer.Render(ctx, rpt)) } // Reduce renderer is a Renderer which merges together the output of several @@ -62,7 +64,7 @@ func MakeReduce(renderers ...Renderer) Renderer { } // Render produces a set of Nodes given a Report. -func (r Reduce) Render(rpt report.Report) Nodes { +func (r Reduce) Render(ctx context.Context, rpt report.Report) Nodes { l := len(r) switch l { case 0: @@ -72,7 +74,7 @@ func (r Reduce) Render(rpt report.Report) Nodes { for _, renderer := range r { renderer := renderer // Pike!! go func() { - c <- renderer.Render(rpt) + c <- renderer.Render(ctx, rpt) }() } for ; l > 1; l-- { @@ -98,9 +100,9 @@ func MakeMap(f MapFunc, r Renderer) Renderer { // Render transforms a set of Nodes produces by another Renderer. // using a map function -func (m Map) Render(rpt report.Report) Nodes { +func (m Map) Render(ctx context.Context, rpt report.Report) Nodes { var ( - input = m.Renderer.Render(rpt) + input = m.Renderer.Render(ctx, rpt) output = newJoinResults(nil) ) @@ -129,9 +131,9 @@ func ConditionalRenderer(c Condition, r Renderer) Renderer { return conditionalRenderer{c, r} } -func (cr conditionalRenderer) Render(rpt report.Report) Nodes { +func (cr conditionalRenderer) Render(ctx context.Context, rpt report.Report) Nodes { if cr.Condition(rpt) { - return cr.Renderer.Render(rpt) + return cr.Renderer.Render(ctx, rpt) } return Nodes{} } diff --git a/render/render_test.go b/render/render_test.go index faf24e419d..34be8ace3f 100644 --- a/render/render_test.go +++ b/render/render_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "reflect" "testing" @@ -13,7 +14,7 @@ type mockRenderer struct { report.Nodes } -func (m mockRenderer) Render(rpt report.Report) render.Nodes { +func (m mockRenderer) Render(_ context.Context, rpt report.Report) render.Nodes { return render.Nodes{Nodes: m.Nodes} } @@ -27,7 +28,7 @@ func TestReduceRender(t *testing.T) { "foo": report.MakeNode("foo"), "bar": report.MakeNode("bar"), } - have := renderer.Render(report.MakeReport()).Nodes + have := renderer.Render(context.Background(), report.MakeReport()).Nodes if !reflect.DeepEqual(want, have) { t.Errorf("want %+v, have %+v", want, have) } @@ -44,7 +45,7 @@ func TestMapRender1(t *testing.T) { }}, } want := report.Nodes{} - have := mapper.Render(report.MakeReport()).Nodes + have := mapper.Render(context.Background(), report.MakeReport()).Nodes if !reflect.DeepEqual(want, have) { t.Errorf("want %+v, have %+v", want, have) } @@ -64,7 +65,7 @@ func TestMapRender2(t *testing.T) { want := report.Nodes{ "bar": report.MakeNode("bar"), } - have := mapper.Render(report.MakeReport()).Nodes + have := mapper.Render(context.Background(), report.MakeReport()).Nodes if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } @@ -86,7 +87,7 @@ func TestMapRender3(t *testing.T) { "_foo": report.MakeNode("_foo").WithAdjacent("_baz"), "_baz": report.MakeNode("_baz").WithAdjacent("_foo"), } - have := mapper.Render(report.MakeReport()).Nodes + have := mapper.Render(context.Background(), report.MakeReport()).Nodes if !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } diff --git a/render/selectors.go b/render/selectors.go index 0b995c38df..22856fdfd8 100644 --- a/render/selectors.go +++ b/render/selectors.go @@ -1,6 +1,8 @@ package render import ( + "context" + "github.com/weaveworks/scope/report" ) @@ -9,7 +11,7 @@ import ( type TopologySelector string // Render implements Renderer -func (t TopologySelector) Render(r report.Report) Nodes { +func (t TopologySelector) Render(ctx context.Context, r report.Report) Nodes { topology, _ := r.Topology(string(t)) return Nodes{Nodes: topology.Nodes} } diff --git a/render/short_lived_connections_test.go b/render/short_lived_connections_test.go index 214344f3f3..673fdc5dd3 100644 --- a/render/short_lived_connections_test.go +++ b/render/short_lived_connections_test.go @@ -1,6 +1,7 @@ package render_test import ( + "context" "fmt" "testing" @@ -109,7 +110,7 @@ var ( ) func TestShortLivedInternetNodeConnections(t *testing.T) { - have := utils.Prune(render.ContainerWithImageNameRenderer.Render(rpt).Nodes) + have := utils.Prune(render.ContainerWithImageNameRenderer.Render(context.Background(), rpt).Nodes) // Conntracked-only connections from the internet should be assigned to the internet pseudonode internet, ok := have[render.IncomingInternetID] @@ -123,7 +124,7 @@ func TestShortLivedInternetNodeConnections(t *testing.T) { } func TestPauseContainerDiscarded(t *testing.T) { - have := utils.Prune(render.ContainerWithImageNameRenderer.Render(rpt).Nodes) + have := utils.Prune(render.ContainerWithImageNameRenderer.Render(context.Background(), rpt).Nodes) // There should only be a connection from container1 and the destination should be container2 container1, ok := have[container1NodeID] if !ok { From 73de143ea02f7437057a2a3c0e76b3b05453d72f Mon Sep 17 00:00:00 2001 From: Bryan Boreham Date: Thu, 11 Oct 2018 08:52:05 +0000 Subject: [PATCH 25/25] Add tracing spans to app Also log things like number of nodes in Map, total number of reports. --- app/api_topologies.go | 5 +++++ app/multitenant/aws_collector.go | 5 +++++ app/multitenant/memcache_client.go | 5 +++++ render/detailed/summary.go | 5 +++++ render/func_name.go | 17 +++++++++++++++++ render/render.go | 13 +++++++++++++ 6 files changed, 50 insertions(+) create mode 100644 render/func_name.go diff --git a/app/api_topologies.go b/app/api_topologies.go index 7503771977..136d6960f6 100644 --- a/app/api_topologies.go +++ b/app/api_topologies.go @@ -11,6 +11,7 @@ import ( "time" "github.com/gorilla/mux" + opentracing "github.com/opentracing/opentracing-go" log "github.com/sirupsen/logrus" "github.com/weaveworks/scope/probe/docker" @@ -483,6 +484,8 @@ func (r *Registry) makeTopologyList(rep Reporter) CtxHandlerFunc { } func (r *Registry) renderTopologies(ctx context.Context, rpt report.Report, req *http.Request) []APITopologyDesc { + span, ctx := opentracing.StartSpanFromContext(ctx, "app.renderTopologies") + defer span.Finish() topologies := []APITopologyDesc{} req.ParseForm() r.walk(func(desc APITopologyDesc) { @@ -498,6 +501,8 @@ func (r *Registry) renderTopologies(ctx context.Context, rpt report.Report, req } func computeStats(ctx context.Context, rpt report.Report, renderer render.Renderer, transformer render.Transformer) topologyStats { + span, ctx := opentracing.StartSpanFromContext(ctx, "app.computeStats") + defer span.Finish() var ( nodes int realNodes int diff --git a/app/multitenant/aws_collector.go b/app/multitenant/aws_collector.go index 4bb404c8a7..4d77a016cd 100644 --- a/app/multitenant/aws_collector.go +++ b/app/multitenant/aws_collector.go @@ -15,6 +15,8 @@ import ( "github.com/aws/aws-sdk-go/service/dynamodb" "github.com/bluele/gcache" "github.com/nats-io/nats" + opentracing "github.com/opentracing/opentracing-go" + otlog "github.com/opentracing/opentracing-go/log" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -336,10 +338,13 @@ func (c *awsCollector) getReports(ctx context.Context, reportKeys []string) ([]r } func (c *awsCollector) Report(ctx context.Context, timestamp time.Time) (report.Report, error) { + span, ctx := opentracing.StartSpanFromContext(ctx, "awsCollector.Report") + defer span.Finish() reportKeys, err := c.getReportKeys(ctx, timestamp) if err != nil { return report.MakeReport(), err } + span.LogFields(otlog.Int("keys", len(reportKeys)), otlog.String("timestamp", timestamp.String())) log.Debugf("Fetching %d reports to %v", len(reportKeys), timestamp) reports, err := c.getReports(ctx, reportKeys) if err != nil { diff --git a/app/multitenant/memcache_client.go b/app/multitenant/memcache_client.go index acb8c4f8e8..5393c3141d 100644 --- a/app/multitenant/memcache_client.go +++ b/app/multitenant/memcache_client.go @@ -9,6 +9,8 @@ import ( "context" "github.com/bradfitz/gomemcache/memcache" + opentracing "github.com/opentracing/opentracing-go" + otlog "github.com/opentracing/opentracing-go/log" "github.com/prometheus/client_golang/prometheus" log "github.com/sirupsen/logrus" @@ -150,6 +152,8 @@ func memcacheStatusCode(err error) string { // FetchReports gets reports from memcache. func (c *MemcacheClient) FetchReports(ctx context.Context, keys []string) (map[string]report.Report, []string, error) { + span, ctx := opentracing.StartSpanFromContext(ctx, "Memcache.FetchReports") + defer span.Finish() defer memcacheRequests.Add(float64(len(keys))) var found map[string]*memcache.Item err := instrument.TimeRequestHistogramStatus(ctx, "Memcache.GetMulti", memcacheRequestDuration, memcacheStatusCode, func(_ context.Context) error { @@ -157,6 +161,7 @@ func (c *MemcacheClient) FetchReports(ctx context.Context, keys []string) (map[s found, err = c.client.GetMulti(keys) return err }) + span.LogFields(otlog.Int("keys", len(keys)), otlog.Int("hits", len(found))) if err != nil { return nil, keys, err } diff --git a/render/detailed/summary.go b/render/detailed/summary.go index b20123400e..a6c24c95dd 100644 --- a/render/detailed/summary.go +++ b/render/detailed/summary.go @@ -5,6 +5,8 @@ import ( "fmt" "strings" + opentracing "github.com/opentracing/opentracing-go" + "github.com/weaveworks/scope/probe/awsecs" "github.com/weaveworks/scope/probe/docker" "github.com/weaveworks/scope/probe/kubernetes" @@ -448,6 +450,9 @@ type NodeSummaries map[string]NodeSummary // Summaries converts RenderableNodes into a set of NodeSummaries func Summaries(ctx context.Context, rc RenderContext, rns report.Nodes) NodeSummaries { + span, ctx := opentracing.StartSpanFromContext(ctx, "detailed.Summaries") + defer span.Finish() + result := NodeSummaries{} for id, node := range rns { if summary, ok := MakeNodeSummary(rc, node); ok { diff --git a/render/func_name.go b/render/func_name.go new file mode 100644 index 0000000000..63c768282f --- /dev/null +++ b/render/func_name.go @@ -0,0 +1,17 @@ +package render + +import ( + "reflect" + "runtime" +) + +func functionName(i interface{}) string { + return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name() +} + +func typeName(i interface{}) string { + if m, ok := i.(*memoise); ok { + return "memoise:" + typeName(m.Renderer) + } + return reflect.TypeOf(i).String() +} diff --git a/render/render.go b/render/render.go index 6b1955a7c5..a3c3d1b497 100644 --- a/render/render.go +++ b/render/render.go @@ -3,6 +3,9 @@ package render import ( "context" + opentracing "github.com/opentracing/opentracing-go" + otlog "github.com/opentracing/opentracing-go/log" + "github.com/weaveworks/scope/report" ) @@ -51,6 +54,8 @@ func (ts Transformers) Transform(nodes Nodes) Nodes { // Render renders the report and then transforms it func Render(ctx context.Context, rpt report.Report, renderer Renderer, transformer Transformer) Nodes { + span, ctx := opentracing.StartSpanFromContext(ctx, "Render:"+typeName(renderer)) + defer span.Finish() return transformer.Transform(renderer.Render(ctx, rpt)) } @@ -65,6 +70,8 @@ func MakeReduce(renderers ...Renderer) Renderer { // Render produces a set of Nodes given a Report. func (r Reduce) Render(ctx context.Context, rpt report.Report) Nodes { + span, ctx := opentracing.StartSpanFromContext(ctx, "Reduce.Render") + defer span.Finish() l := len(r) switch l { case 0: @@ -74,7 +81,9 @@ func (r Reduce) Render(ctx context.Context, rpt report.Report) Nodes { for _, renderer := range r { renderer := renderer // Pike!! go func() { + span, ctx := opentracing.StartSpanFromContext(ctx, typeName(renderer)) c <- renderer.Render(ctx, rpt) + span.Finish() }() } for ; l > 1; l-- { @@ -101,6 +110,8 @@ func MakeMap(f MapFunc, r Renderer) Renderer { // Render transforms a set of Nodes produces by another Renderer. // using a map function func (m Map) Render(ctx context.Context, rpt report.Report) Nodes { + span, ctx := opentracing.StartSpanFromContext(ctx, "Map.Render:"+functionName(m.MapFunc)) + defer span.Finish() var ( input = m.Renderer.Render(ctx, rpt) output = newJoinResults(nil) @@ -113,6 +124,8 @@ func (m Map) Render(ctx context.Context, rpt report.Report) Nodes { output.add(inRenderable.ID, outRenderable) } } + span.LogFields(otlog.Int("input.nodes", len(input.Nodes)), + otlog.Int("ouput.nodes", len(output.nodes))) return output.result(input) }