diff --git a/.gitignore b/.gitignore index 8634f93d0..18a9ba4fd 100644 --- a/.gitignore +++ b/.gitignore @@ -69,9 +69,6 @@ depcomp /cockpit-askpass /cockpit-session /cockpit-ssh -/cockpit-stub -/cockpit-kube-auth -/cockpit-kube-launch /test-session /cockpit-bridge /remotectl @@ -160,8 +157,6 @@ po*.js.gz /pkg/*/cockpit-components-*.js /pkg/*/cockpit-components-*.js -/pkg/kubernetes/kubernetes-templates.js -/pkg/kubernetes/registry-templates.js /pkg/playground/react-demo-*.js /pkg/selinux/setroubleshoot-view.js /pkg/tuned/change-profile.js diff --git a/Makefile.am b/Makefile.am index 78514950f..b7e5df42b 100644 --- a/Makefile.am +++ b/Makefile.am @@ -154,7 +154,6 @@ WEBPACK_PACKAGES = \ dashboard \ docker \ kdump \ - kubernetes \ machines \ networkmanager \ pcp \ diff --git a/Vagrantfile b/Vagrantfile index ce132bdcc..4c23e638a 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -48,7 +48,6 @@ Vagrant.configure(2) do |config| etcd \ firewalld \ git \ - kubernetes \ NetworkManager \ pcp \ qemu \ diff --git a/bots/npm-update b/bots/npm-update index 6551fdd5d..7a1f13d6d 100755 --- a/bots/npm-update +++ b/bots/npm-update @@ -20,16 +20,12 @@ # To use this example add a line to an issue with the "bot" label # -# * [ ] npm-update angular +# * [ ] npm-update patternfly # # Dependencies that are either fragile (minor updates break) # or are part of our public Javascript API and need caution FRAGILE = [ - "angular", - "angular-bootstrap-npm", - "angular-gettext", - "angular-route", "jquery", "patternfly", "paternfly-bootstrap-combobox", diff --git a/doc/guide/Makefile-guide.am b/doc/guide/Makefile-guide.am index 941b1745f..4fc702902 100644 --- a/doc/guide/Makefile-guide.am +++ b/doc/guide/Makefile-guide.am @@ -26,7 +26,6 @@ GUIDE_INCLUDES = \ doc/guide/feature-docker.xml \ doc/guide/feature-firewall.xml \ doc/guide/feature-journal.xml \ - doc/guide/feature-kubernetes.xml \ doc/guide/feature-machines.xml \ doc/guide/feature-networkmanager.xml \ doc/guide/feature-packagekit.xml \ diff --git a/doc/guide/cockpit-guide.xml b/doc/guide/cockpit-guide.xml index ebf224222..30ed58543 100644 --- a/doc/guide/cockpit-guide.xml +++ b/doc/guide/cockpit-guide.xml @@ -45,7 +45,6 @@ - diff --git a/doc/guide/feature-kubernetes.xml b/doc/guide/feature-kubernetes.xml deleted file mode 100644 index 61d81143b..000000000 --- a/doc/guide/feature-kubernetes.xml +++ /dev/null @@ -1,34 +0,0 @@ - - - - Kubernetes - - Cockpit has a dashboard that interacts with a - Kubernetes cluster or an - Openshift v3 cluster. This - functionality is in the Cockpit kubernetes package. - - The dashboard is part of a normal authenticated Cockpit session. Cockpit - communicates with Kubernetes via its REST API. - - Usually some form of authentication is necessary to access the Kubernetes REST API. - Like the kubectl and oc commands, Cockpit uses - the authentication and server information in the ~/.kube/config file for - the logged in user. - - If a user is able to use kubectl successfully when at their shell terminal, - then that same user will able to use Kubernetes dashboard when logged into Cockpit: - - -$ kubectl get pods -NAME READY STATUS RESTARTS AGE -docker-registry-1-l4pyh 1/1 Running 10 23d -... - - - When running Openshift one can use the oc login command to configure the - ~/.kube/config file correctly. This in turn allows Cockpit to use that - login information. - - diff --git a/package.json b/package.json index 8c6510fbf..c900e9430 100644 --- a/package.json +++ b/package.json @@ -5,10 +5,6 @@ "dependencies": { "@babel/polyfill": "7.4.4", "@patternfly/react-console": "1.10.50", - "angular": "1.3.20", - "angular-bootstrap-npm": "0.13.4", - "angular-gettext": "2.3.11", - "angular-route": "1.3.20", "bootstrap": "3.4.1", "bootstrap-datepicker": "1.9.0", "c3": "0.4.23", @@ -17,12 +13,8 @@ "jquery-flot": "0.8.3", "js-sha1": "0.6.0", "json-stable-stringify-without-jsonify": "1.0.1", - "kubernetes-container-terminal": "1.0.3", - "kubernetes-object-describer": "1.1.4", - "kubernetes-topology-graph": "0.0.25", "moment": "2.24.0", "mustache": "3.0.1", - "object-describer": "git+https://github.com/kubernetes-ui/object-describer.git#v1.0.4", "patternfly": "3.58.0", "patternfly-bootstrap-combobox": "1.1.7", "patternfly-react": "2.34.3", @@ -64,7 +56,6 @@ "eslint-plugin-promise": "^4.0.1", "eslint-plugin-react": "7.13.0", "eslint-plugin-standard": "^4.0.0", - "exports-loader": "~0.6.3", "extend": "~3.0.0", "extract-text-webpack-plugin": "^4.0.0-beta.0", "html-webpack-plugin": "^3.2.0", diff --git a/pkg/Makefile.am b/pkg/Makefile.am index 322ff0713..846696ac4 100644 --- a/pkg/Makefile.am +++ b/pkg/Makefile.am @@ -34,39 +34,3 @@ EXTRA_DIST += \ $(metainfo_DATA) \ $(pixmaps_DATA) \ $(NULL) - -if WITH_GOLANG - -AM_V_GO = $(am__v_GO_@AM_V@) -am__v_GO_ = $(am__v_GO_@AM_DEFAULT_V@) -am__v_GO_0 = @echo " GO " $@; - -GO_BUILD_RULE = \ - GOPATH=$(abs_srcdir)/pkg/kubernetes/standalone $(GOLANG) build \ - -ldflags "-B 0x"`head -c20 /dev/urandom|od -An -tx1|tr -d ' \n'` "$@" - -COCKPIT_KUBE_HELPERS = \ - pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/creds.go \ - pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/client.go \ - $(NULL) - -COCKPIT_KUBE_AUTH = $(COCKPIT_KUBE_HELPERS) \ - pkg/kubernetes/standalone/src/cockpit-kube-auth/main.go \ - $(NULL) - -COCKPIT_KUBE_LAUNCH = $(COCKPIT_KUBE_HELPERS) \ - pkg/kubernetes/standalone/src/cockpit-kube-launch/main.go \ - $(NULL) - -cockpit-kube-auth$(EXEEXT): $(COCKPIT_KUBE_AUTH) - $(AM_V_GO) $(GO_BUILD_RULE) - -cockpit-kube-launch$(EXEEXT): $(COCKPIT_KUBE_LAUNCH) - $(AM_V_GO) $(GO_BUILD_RULE) - -libexec_PROGRAMS += cockpit-kube-auth cockpit-kube-launch - -cockpit_kube_auth_SOURCES = $(COCKPIT_KUBE_AUTH) -cockpit_kube_launch_SOURCES = $(COCKPIT_KUBE_LAUNCH) - -endif diff --git a/pkg/kubernetes/README.md b/pkg/kubernetes/README.md deleted file mode 100644 index 885e3bdc5..000000000 --- a/pkg/kubernetes/README.md +++ /dev/null @@ -1,22 +0,0 @@ -Developing the kubernetes component ------------------------------------ - -This component adds functionality to Cockpit to perform admin tasks on -Kubernetes or Openshift. You'll see a "Cluster" tab listed in Cockpit. - -### Running a test instance - -There's a test instance of Openshift (and also Kubernetes) that's you -can run using the following command: - - $ bots/vm-run openshift - -To then access that it run the following in another terminal: - - $ sudo yum install kubernetes-client - $ mkdir -p ~/.kube - $ cp bots/images/files/openshift.kubeconfig ~/.kube/config - -You should now be able to use the kubectl command to access the cluster: - - $ kubectl get pods diff --git a/pkg/kubernetes/index.html b/pkg/kubernetes/index.html deleted file mode 100644 index 07dd948ed..000000000 --- a/pkg/kubernetes/index.html +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - Kubernetes Cluster - - - - - - - - - - - - -
-
- -
-
-
- - -
-

Connecting...

-

Couldn't connect to server

-

{{curtains.message}}

-
- - -
-
- - diff --git a/pkg/kubernetes/manifest.json.in b/pkg/kubernetes/manifest.json.in deleted file mode 100644 index b0ffab22f..000000000 --- a/pkg/kubernetes/manifest.json.in +++ /dev/null @@ -1,14 +0,0 @@ -{ - "version": "@VERSION@", - "requires": { - "cockpit": "137.x" - }, - - "dashboard": { - "index": { - "label": "Cluster", - "order": 20, - "icon": "pficon-cluster" - } - } -} diff --git a/pkg/kubernetes/override.json b/pkg/kubernetes/override.json deleted file mode 100644 index 73a28e673..000000000 --- a/pkg/kubernetes/override.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "dashboard": { - "registry": { - "label": "Image Registry", - "order": 30, - "icon": "pficon-registry" - } - } -} diff --git a/pkg/kubernetes/registry.html b/pkg/kubernetes/registry.html deleted file mode 100644 index 96fcb5dc3..000000000 --- a/pkg/kubernetes/registry.html +++ /dev/null @@ -1,80 +0,0 @@ - - - - - -Image Registry - - - - - - - - - - - - - - - -
-
- -
-
-
- - -
-

Connecting...

-

Couldn't connect to server

-

{{curtains.message}}

-
- -
-
- - - diff --git a/pkg/kubernetes/scripts/app.js b/pkg/kubernetes/scripts/app.js deleted file mode 100644 index f9cbfa864..000000000 --- a/pkg/kubernetes/scripts/app.js +++ /dev/null @@ -1,355 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-bootstrap-npm/dist/angular-bootstrap.js'); - - require('./kube-client'); - require('./kube-client-cockpit'); - require('./connection'); - - require('../views/auth-dialog.html'); - require('../views/filter-bar.html'); - require('../views/filter-project.html'); - - angular.module('kubernetes.app', [ - 'ui.bootstrap', - 'kubeClient', - 'kubeClient.cockpit', - 'kubernetes.connection' - ]) - - .controller('MainCtrl', [ - '$scope', - '$location', - '$rootScope', - '$timeout', - '$modal', - 'kubeLoader', - 'kubeSelect', - 'KubeDiscoverSettings', - 'filterService', - 'connectionActions', - function($scope, $location, $rootScope, $timeout, $modal, - loader, select, discoverSettings, filter, connectionActions) { - $scope.settings = { }; - - /* Used to set detect which route is active */ - $scope.viewActive = function(segment) { - var url = $location.url() || "/"; - var parts = url.split('?')[0].split("/"); - if (!segment && !parts[1]) - return true; - if (segment === parts[1]) - return true; - return false; - }; - - /* Used to build simple route URLs */ - $scope.viewUrl = function(segment, forceQS) { - var namespace = loader.limits.namespace; - var path; - var parts = []; - if (angular.isArray(namespace)) - namespace = null; - - if (segment) - parts.push(segment); - else - forceQS = true; - - if (!forceQS && namespace) - parts.push(namespace); - - path = "/" + parts.map(encodeURIComponent).join("/"); - if (namespace && forceQS) - return path + "?namespace=" + encodeURIComponent(namespace); - else - return path; - }; - - /* Used while debugging */ - $scope.console = console; - - /* Show the body when ready */ - function visible() { - document.getElementsByTagName("body")[0].removeAttribute("hidden"); - } - - /* Show after some seconds whether ready or not */ - $timeout(visible, 3000); - - /* Curtains related logic */ - function connect(force) { - $scope.curtains = { }; - discoverSettings(force).then(function(settings) { - $scope.settings = settings; - $scope.curtains = null; - filter.globals(settings.isAdmin); - filter.load().then(visible); - }, function(resp) { - $scope.curtains = { - status: resp.status, - resp: resp, - message: resp.message || resp.statusText, - }; - $scope.settings = null; - visible(); - }); - } - - /* Connect automatically initially */ - connect(); - - /* Used by reconnect buttons */ - $scope.reconnect = function(force) { - if (force === undefined) - force = true; - - discoverSettings(force); - loader.reset(); - connect(); - }; - - /* When the loader changes digest */ - loader.listen(function() { - $rootScope.$applyAsync(); - }, $rootScope); - - $scope.changeAuth = function(ex) { - var promise = $modal.open({ - animation: false, - controller: 'ChangeAuthCtrl', - templateUrl: 'views/auth-dialog.html', - resolve: { - dialogData: function() { - return connectionActions.load(ex); - } - }, - }).result; - - /* If the change is successful, reconnect */ - promise.then(function(force) { - $scope.reconnect(force); - }); - return promise; - }; - } - ]) - - .directive('filterBar', [ - 'filterService', - function(filter) { - return { - restrict: 'E', - scope: true, - transclude: true, - link: function(scope, element, attrs) { - scope.filter = filter; - }, - templateUrl: 'views/filter-bar.html' - }; - } - ]) - - .directive('filterProject', [ - 'filterService', - function(filter) { - return { - restrict: 'E', - scope: true, - link: function(scope, element, attrs) { - scope.filter = filter; - }, - templateUrl: 'views/filter-project.html' - }; - } - ]) - - .factory('filterService', [ - '$q', - '$route', - '$rootScope', - 'kubeLoader', - 'kubeSelect', - 'KubeDiscoverSettings', - function($q, $route, $rootScope, loader, select, discoverSettings) { - /* - * We have the following cases to account for: - * - * Openshift: - * - Have Project objects - * - Project objects are listable by any user, only accessilbe returned - * - * Kubernetes and Openshift - * - Namespace objects are only accessible to all users - * - * The globals variable is set based on this. - */ - - var globals = true; - - var promise = discoverSettings().then(function(settings) { - var ret = []; - if (settings.flavor === "openshift") { - ret.push(loader.watch("projects", $rootScope)); - ret.push(loader.load("projects")); - } - if (settings.isAdmin) - ret.push(loader.watch("namespaces", $rootScope)); - return $q.all(ret); - }); - - /* - * When either a Namespace or Project is loaded we'll want to reinterpret - * how we look at the current namespace. This helps to handle cases where - * the user can't see all projects, and one is loaded. - */ - loader.listen(function(present) { - var link, object; - for (link in present) { - object = present[link]; - if (object.kind == "Namespace" || object.kind == "Project") { - loadNamespace($route.current); - return; - } - } - }); - - function calcAvailable() { - var all; - if (globals) - all = select().kind("Namespace"); - if (!all || all.length === 0) - all = select().kind("Project") - .statusPhase("Active"); - - var link, meta; - var ret = []; - for (link in all) { - meta = all[link].metadata || { }; - if (meta.name) - ret.push(meta.name); - } - - return ret; - } - - function loadNamespace(route) { - var value = null; - if (route) - value = route.params["namespace"] || null; - - /* - * When we can't see globals, we tell the loader about - * all namespaces that we can see. It'll open up individual - * watches about those namespaces. - */ - if (value === null && !globals) { - value = calcAvailable(); - /* We might not be global, but the projects may not - * be loaded yet */ - if (value.length < 1) - value = null; - } - - if (!angular.equals(value, loader.limits.namespaces)) { - loader.limit({ namespace: value }); - } - } - - $rootScope.$on("$routeChangeSuccess", function (event, current, prev) { - loadNamespace(current); - }); - - $rootScope.$on("$routeUpdate", function (event, current, prev) { - loadNamespace(current); - }); - - if ($route.current) - loadNamespace($route.current); - - return { - load: function() { - return promise; - }, - globals: function(value) { - if (arguments.length === 0) - return globals; - value = !!value; - if (globals !== value) { - globals = value; - loadNamespace($route.current); - } - }, - namespaces: calcAvailable, - namespace: function(value) { - if (arguments.length === 0) - return $route.current.params["namespace"]; - var copy = angular.copy($route.current.params); - copy["namespace"] = value || undefined; - copy["target"] = null; - $route.updateParams(copy); - } - }; - } - ]) - - /* The default orderBy filter doesn't work on objects */ - .filter('orderObjectBy', function() { - return function(items, field) { - var i; - var sorted = []; - for (i in items) - sorted.push(items[i]); - if (!angular.isArray(field)) - field = [ String(field) ]; - var criteria = field.map(function(v) { - return v.split('.'); - }); - function value(obj, x) { - return obj ? obj[x] : undefined; - } - sorted.sort(function(a, b) { - var ra, rb, i; - var len = criteria.length; - for (i = 0; i < len; i++) { - ra = criteria[i].reduce(value, a); - rb = criteria[i].reduce(value, b); - if (ra === rb) - continue; - return (ra > rb ? 1 : -1); - } - return 0; - }); - return sorted; - }; - }) - - .filter("formatBytes", [ - "KubeFormat", - function(format) { - return function(num) { - if (typeof num == "number") - return format.formatBytes(num); - return num; - }; - }]); -}()); diff --git a/pkg/kubernetes/scripts/charts.js b/pkg/kubernetes/scripts/charts.js deleted file mode 100644 index 032232a93..000000000 --- a/pkg/kubernetes/scripts/charts.js +++ /dev/null @@ -1,557 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-bootstrap-npm/dist/angular-bootstrap.js'); - - var d3 = require('d3'); - - var focusedClasses = { - "chart-focused": true, - "chart-unfocused": false - }; - var unfocusedClasses = { - "chart-focused": false, - "chart-unfocused": true - }; - var focusResetClasses = { - "chart-focused": false, - "chart-unfocused": false - }; - - function parsePXVal(val) { - var n; - if (val) - n = parseInt(val.slice(0, val.length - 2), 10); - - if (!n || isNaN(n)) - n = 0; - - return n; - } - - function getPadding(el) { - // May return null on FF when iframe is hidden. - var style = window.getComputedStyle(el, null); - if (style) { - return { - left: parsePXVal(style.getPropertyValue('padding-left')), - right: parsePXVal(style.getPropertyValue('padding-right')), - top: parsePXVal(style.getPropertyValue('padding-top')), - bottom: parsePXVal(style.getPropertyValue('padding-bottom')) - }; - } else { - return { - left: 0, - right: 0, - top: 0, - bottom: 0 - }; - } - } - - function getSize(el) { - var p = getPadding(el); - var width = el.clientWidth - p.left - p.right; - var height = el.clientHeight - p.top - p.bottom; - - if (width < 0) - width = 0; - if (height < 0) - height = 0; - - return { - width: width, - height: height - }; - } - - angular.module('ui.charts', [ - 'ui.bootstrap', - ]) - - .directive('thresholdHeatMap', [ - "$window", - "KubeTranslate", - "$timeout", - function ($window, translate, $timeout) { - const _ = translate.gettext; - - return { - restrict: 'A', - scope: { - data: '=?', - legendLabels: '=?', - thresholds: '=?', - colors: '=?', - }, - link: function($scope, element, attributes) { - var data; - var padding = 2; - var thresholdDefaults = [0, 0.7, 0.8, 0.9]; - var heatmapColorDefaults = ['#bbbbbb', '#d4f0fa', '#F9D67A', '#EC7A08', '#CE0000']; - var legendLabelDefaults = [_("Unavailable"), '< 70%', '70-80%', '80-90%', '> 90%']; - - var maxSize = attributes['maxBlockSize']; - if (!maxSize || isNaN(maxSize)) { - maxSize = 64; - } else { - maxSize = parseInt(maxSize, 10); - if (maxSize < 5) - maxSize = 5; - else if (maxSize > 64) - maxSize = 64; - } - - if (!$scope.thresholds) - $scope.thresholds = thresholdDefaults; - - if (!$scope.colors) - $scope.colors = heatmapColorDefaults; - - if (!$scope.legendLabels) - $scope.legendLabels = legendLabelDefaults; - - var svg = d3.select(element[0]).append("svg") - .classed("heatmap-pf-svg", true) - .style("width", "100%"); - - if (attributes['legend']) - buildLegend(); - - function getBlockSize(n, x, y) { - if (x < 1 || y < 1) - return 0; - - if (n === 0) - return maxSize; - - var px = Math.ceil(Math.sqrt(n * x / y)); - var py = Math.ceil(Math.sqrt(n * y / x)); - var sx, sy; - - if (Math.floor(px * y / x) * px < n) - sx = y / Math.ceil(px * y / x); - else - sx = x / px; - - if (Math.floor(py * x / y) * py < n) - sy = x / Math.ceil(x * py / y); - else - sy = y / py; - - return Math.max(sx, sy); - } - - function getSizeInfo() { - var length = data ? data.length : 0; - var size = getSize(element[0]); - var h = size.height; - var w = size.width; - - var rows; - - var blockSize = getBlockSize(length, w, h); - if ((blockSize - padding) > maxSize) { - blockSize = padding + maxSize; - - // Attempt to square off the area, check if square fits - rows = Math.ceil(Math.sqrt(length)); - if (blockSize * rows > w || - blockSize * rows > h) { - rows = (blockSize === 0) ? 0 : Math.floor(h / blockSize); - } - } else { - rows = (blockSize === 0) ? 0 : Math.floor(h / blockSize); - } - return { - rows: rows, - block: blockSize - }; - } - - function buildLegend() { - var colors = $scope.colors.slice(0); - var labels = $scope.legendLabels.slice(0); - - labels.reverse(); - colors.reverse(); - - var legend = d3.select("#" + attributes['legend']) - .append('ul') - .classed('chart-legend', true); - - var li = legend.selectAll("li").data(labels); - - var newLi = li.enter().append("li") - .classed('chart-legend-item', true) - .on("mouseover", function(d, i) { - var color = colors[i]; - var rsel = "rect[data-color='" + color + "']"; - var lsel = "li[data-color='" + color + "']"; - - legend.selectAll("li").classed(unfocusedClasses); - legend.select(lsel).classed(focusedClasses); - - svg.selectAll("rect").classed(unfocusedClasses); - svg.selectAll(rsel).classed(focusedClasses); - }) - .on("mouseout", function (d, i) { - svg.selectAll("rect").classed(focusResetClasses); - legend.selectAll("li").classed(focusResetClasses); - }); - - newLi.append("span") - .classed('legend-pf-color-box', true); - - newLi.append("span") - .classed('legend-pf-text', true); - - li.attr("data-color", function (d, i) { - return colors[i]; - }); - - li.select("span.legend-pf-color-box") - .style("background-color", function (d, i) { - return colors[i]; - }); - - li.select("span.legend-pf-text") - .text(function (d) { - return d; - }); - } - - function getcolor(d, colorFunc) { - var value = d; - if (d && d.value !== undefined) - value = d.value; - - if (isNaN(value)) - value = -1; - - return colorFunc(value); - } - - function refresh() { - var colorFunc = d3.scale.threshold() - .domain($scope.thresholds) - .range($scope.colors); - - var size = getSizeInfo(); - if (!data) - data = [ ]; - - var fillSize = size.block - padding; - if (fillSize < 1) - return; - - svg.attr("height", size.block * size.rows); - var blocks = svg.selectAll('rect').data(data); - - blocks.enter().append('rect') - .on("mouseover", function(d, i) { - svg.selectAll('rect').classed(unfocusedClasses); - d3.select(this).classed(focusedClasses); - }) - .on("mouseout", function (d, i) { - svg.selectAll('rect').classed(focusResetClasses); - }) - .append("title"); - - blocks - .attr('x', function (d, i) { - return Math.floor(i / size.rows) * size.block; - }) - .attr('y', function (d, i) { - return i % size.rows * size.block; - }) - .attr('width', fillSize) - .attr('height', fillSize) - .attr('data-color', function (d) { - return getcolor(d, colorFunc); - }) - .style('fill', function (d) { - return getcolor(d, colorFunc); - }) - .on('click', function (d) { - if (d && d.name) - $scope.$emit("boxClick", d.name); - }) - .select("title") - .text(function(d) { - return d.tooltip; - }); - - blocks.exit().remove(); - } - - $scope.$watchCollection('data', function(newValue) { - data = newValue; - refresh(); - }); - - angular.element($window).bind('resize', function () { - refresh(); - }); - - $scope.$watch( - function () { - return [element[0].offsetWidth, element[0].offsetHeight].join('x'); - }, - function (value) { - refresh(); - } - ); - } - }; - } - ]) - - .directive('donutPctChart', [ - "$window", - function ($window) { - return { - restrict: 'A', - scope: { - data: '=?', - largeTitle: '=?', - smallTitle: '=?', - }, - link: function($scope, element, attributes) { - var arc, selectedArc, data; - var colors = d3.scale.category20(); - - var pie = d3.layout.pie().value(function (d) { - if (typeof d === 'object') - return d.value; - else - return d; - }); - - var legend; - if (attributes['legend']) { - legend = d3.select("#" + attributes['legend']) - .append('ul') - .classed('chart-legend', true); - } - - var svg = d3.select(element[0]).append("svg"); - svg.style("width", "100%"); - svg.style("height", "100%"); - - var g = svg.append("g"); - g.append('text').attr('class', "chart-title"); - - function updateSize() { - var size = getSize(element[0]); - var width = size.width; - var height = size.height; - var c; - var radius = Math.min(width, height) / 2; - var barSize = parseInt(attributes['barSize'], 10); - if (isNaN(barSize)) - barSize = 20; - - if ((barSize * 2) > radius) - barSize = radius; - - arc = d3.svg.arc() - .innerRadius(radius - (barSize * 2)) - .outerRadius(radius - barSize); - - selectedArc = d3.svg.arc() - .innerRadius(radius - (barSize * 2)) - .outerRadius(radius - (barSize - 2)); - - c = (radius - barSize - 2) * 2; - g.attr('data-innersize', Math.sqrt((c * c) / 2)); - updateTitle(); - - g.attr("transform", "translate(" + width / 2 + "," + height / 2 + ")"); - refresh(); - } - - function calFontSize() { - var width = this.getComputedTextLength(); - var inner = parseInt(g.attr("data-innersize"), 10); - var style = window.getComputedStyle(this, null); - var size, ratio; - - if (style && width) { - size = style.getPropertyValue('font-size'); - ratio = inner / width; - } else { - width = 0; - } - - if (!isNaN(inner) && width > inner) - return "calc(" + size + " * " + ratio + ")"; - } - - function updateTitle() { - var title = g.select('text.chart-title'); - var size = parseInt(g.attr("data-innersize"), 10); - if (isNaN(size)) - return; - - title.selectAll('tspan').remove(); - if ($scope.largeTitle) { - title.insert('tspan').text($scope.largeTitle) - .classed('donut-title-big-pf', true) - .attr('dy', 0) - .attr('x', 0) - .style("font-size", calFontSize); - } - - if ($scope.smallTitle) { - title.insert('tspan').text($scope.smallTitle) - .classed('donut-title-small-pf', true) - .attr('dy', 20) - .attr('x', 0) - .style("font-size", calFontSize); - } - } - - function select(id) { - var sel = "path[data-id='" + id + "']"; - var lsel = "li[data-id='" + id + "']"; - g.selectAll("path").classed(unfocusedClasses); - - g.select(sel).attr("d", function (d, i) { - return selectedArc(d, i); - }); - g.select(sel).classed(focusedClasses); - - if (legend) { - legend.selectAll("li").classed(unfocusedClasses); - legend.select(lsel).classed(focusedClasses); - } - } - - function unselect() { - g.selectAll("path") - .classed(focusResetClasses) - .attr("d", arc); - if (legend) { - legend.selectAll("li") - .classed(focusResetClasses); - } - } - - function refreshLegend() { - var li = legend.selectAll("li").data(data); - - var newLi = li.enter().append("li") - .classed('chart-legend-item', true) - .on("mouseover", function() { - select(this.getAttribute('data-id')); - }) - .on("mouseout", unselect); - - newLi.append("span").classed('legend-pf-color-box', true); - newLi.append("span").classed('legend-pf-text', true); - - li.attr("data-id", function (d, i) { - return i; - }); - - li.select("span.legend-pf-color-box") - .style("background-color", function (d, i) { - if (d && d.color) - return d.color; - else - return colors(i); - }); - - li.select("span.legend-pf-text") - .text(function (d) { - if (d && d.label) - return d.label; - else - return d; - }); - - li.exit().remove(); - } - - function refresh() { - if (!data) - data = []; - - var path = g.selectAll("path") - .data(pie(data)); - - path.enter().append("path") - .on("mouseover", function(i) { - select(this.getAttribute('data-id')); - }) - .on("mouseout", unselect) - .append("title"); - - path.attr("fill", function(d, i) { - if (d.data && d.data.color) - return d.data.color; - else - return colors(i); - }) - .attr("d", arc) - .attr("data-id", function (d, i) { - return i; - }) - .select("title") - .text(function(d) { - if (d.data && d.data.tooltip) - return d.data.tooltip; - }); - - path.exit().remove(); - - if (legend) - refreshLegend(); - } - - $scope.$watchCollection('data', function(newValue) { - data = newValue; - refresh(); - }); - - /* Watch the selection for changes */ - $scope.$watchGroup(["largeTitle", "smallTitle"], function() { - updateTitle(); - }); - - angular.element($window).bind('resize', function () { - updateSize(); - }); - - $scope.$watch( - function () { - return [element[0].offsetWidth, element[0].offsetHeight].join('x'); - }, - function (value) { - updateSize(); - } - ); - } - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/connection.js b/pkg/kubernetes/scripts/connection.js deleted file mode 100644 index 19f6fc53e..000000000 --- a/pkg/kubernetes/scripts/connection.js +++ /dev/null @@ -1,686 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - - require('angular-dialog.js'); - require('./kube-client-cockpit'); - require('./utils'); - - require('../views/auth-form.html'); - require('../views/auth-rejected-cert.html'); - require('../views/container-page.html'); - require('../views/containers-page.html'); - require('../views/containers-listing.html'); - require('../views/container-page-inline.html'); - require('../views/container-body.html'); - require('../views/pod-body.html'); - - angular.module('kubernetes.connection', [ - 'ui.cockpit', - 'kubeClient', - 'kubeClient.cockpit', - 'kubeUtils', - ]) - - .factory("sessionCertificates", [ - "cockpitKubectlConfig", - function (kubectl) { - var trustedCerts = {}; - - function trustCert(cluster, pem) { - var options = kubectl.generateKubeOptions(cluster); - var address = options.address || "localhost"; - trustedCerts[address] = pem; - } - - function getCert(address) { - address = address || "localhost"; - return trustedCerts[address]; - } - - return { - getCert: getCert, - trustCert: trustCert - }; - } - ]) - - .factory("connectionActions", [ - "$q", - "cockpitKubeDiscover", - "cockpitKubectlConfig", - "cockpitRunCommand", - "cockpitConnectionInfo", - "CockpitKubeRequest", - "KubeMapNamedArray", - "CockpitTranslate", - "sessionCertificates", - function($q, cockpitKubeDiscover, kubectl, runCommand, - cockpitConnectionInfo, CockpitKubeRequest, - mapNamedArray, translate, sessionCertificates) { - var DEFAULT_ADDRESS = "http://localhost:8080"; - const _ = translate.gettext; - - function kubectlError(ex) { - // Because angular warns about all throws - console.warn("Unexpected Kubectl Error", ex); - return $q.reject(new Error(_("Error writing kubectl config"))); - } - - function kubectlData() { - return kubectl.read().then(function(data) { - var config; - try { - config = JSON.parse(data); - } catch (ex) { - console.warn("received invalid kubectl config", ex); - config = {}; - } - return config; - }); - } - - function loadConfigData(config, useConfig) { - var user, cluster, context; - var contexts = mapNamedArray(config.contexts); - var users = mapNamedArray(config.users); - var clusters = mapNamedArray(config.clusters); - - if (useConfig) - context = contexts[useConfig["current-context"]]; - else - context = contexts[config["current-context"]]; - - if (context && context.context) { - if (context.context.user) - user = users[context.context.user]; - if (context.context.cluster) - cluster = clusters[context.context.cluster]; - } - - return { - users: users, - clusters: clusters, - contexts: contexts, - currentUser: user, - currentCluster: cluster, - currentContext: context, - config: config - }; - } - - function load(error) { - var defer = $q.defer(); - var promise; - - var result = { - haveKubectl: false, - defaultAddress: DEFAULT_ADDRESS, - error: error, - users: undefined, - clusters: undefined, - contexts: undefined, - currentUser: undefined, - currentCluster: undefined, - currentContext: undefined, - config: undefined - }; - - if (!error) { - promise = cockpitKubeDiscover().then(function(options) { - var address = "localhost"; - if (options.address) - address = options.address; - - if (options.tls) - result.defaultAddress = "https://" + address + ":" + options.port; - else - result.defaultAddress = "http://" + address + ":" + options.port; - - return kubectlData(); - }, function(ex) { - result.error = ex; - return kubectlData(); - }); - } else { - promise = kubectlData(); - } - - promise.then(function(config) { - var useConfig; - - result.haveKubectl = true; - - if (cockpitConnectionInfo.type && cockpitConnectionInfo.type != "open") - useConfig = cockpitConnectionInfo.kubeConfig; - - angular.extend(result, loadConfigData(config, useConfig)); - defer.resolve(result); - }, function(ex) { - if (cockpitConnectionInfo.kubeConfig) - angular.extend(result, loadConfigData(cockpitConnectionInfo.kubeConfig)); - defer.resolve(result); - }); - return defer.promise; - } - - function prepareData(config, cluster, user) { - var i; - var contexts, context; - var default_cluster = { - cluster: { server: DEFAULT_ADDRESS } - }; - - config = config || {}; - cluster = cluster || default_cluster; - - function ensureValid(name, options) { - var added; - var chars = "abcdefghijklmnopqrstuvwxyz"; - name = name.toLowerCase().replace(/[^a-z0-9:/-]/g, "-"); - while (options[name]) { - var length = 0; - if (!added) - name = name + "/"; - - added = ""; - - while (length < 4) { - added += chars[Math.floor(Math.random() * chars.length)]; - length++; - } - - name = name + added; - } - return name; - } - - function generateClusterName(cluster) { - var a = document.createElement("a"); - a.href = cluster.cluster.server; - - var name = a.hostname; - - if (a.port) - name = name + ":" + a.port; - - return ensureValid(name, mapNamedArray(config.clusters)); - } - - function generateUserName(user, clusterName) { - var name; - if (user.user && user.user.username) - name = user.user.username; - else - name = "user"; - name = name + "/" + clusterName; - return ensureValid(name, mapNamedArray(config.users)); - } - - function generateContextName(userName, clusterName) { - var name = clusterName + "/" + userName; - return ensureValid(name, mapNamedArray(config.contexts)); - } - - if (!cluster.name) - cluster.name = generateClusterName(cluster); - - if (user && !user.name) - user.name = generateUserName(user, cluster.name); - - contexts = config.contexts || []; - for (i = 0; i < contexts.length; i++) { - var c = contexts[i]; - if (c.context) { - var inner = c.context || {}; - if (inner.cluster == cluster.name && - ((user && inner.user == user.name) || (!user && !inner.user))) { - context = { name: c.name }; - break; - } - } - } - - if (!context) { - context = { - name: generateContextName(user ? user.name : "noauth", cluster.name), - context: { - user: user ? user.name : undefined, - cluster: cluster.name, - } - }; - } - - return { - cluster: cluster, - user: user, - context: context - }; - } - - /* Openshift returns token information in the hash of a Location URL */ - function parseBearerToken(url) { - var token = null; - var parser = document.createElement('a'); - parser.href = url; - var hash = parser.hash; - if (hash[0] == "#") - hash = hash.substr(1); - hash.split("&").forEach(function(part) { - var item = part.split("="); - if (item.shift() == "access_token") - token = item.join("="); - }); - return token; - } - - /* Retrieve a bearer token using basic auth if possible */ - function populateBearerToken(cluster, user) { - /* The user data without any token */ - var data = angular.extend({ }, user ? user.user : null); - - /* If no password is set, just skip this step */ - if (!data.password) - return $q.when(); - - delete data.token; - - /* Build an Openshift OAuth WWW-Authenticate request */ - var config = kubectl.generateKubeOptions(cluster.cluster, data); - var trust = sessionCertificates.getCert(config.address); - if (config.tls && trust) - config.tls["authority"] = { data: trust }; - - if (!config.headers) - config.headers = { }; - config.headers["X-CSRF-Token"] = "1"; /* Any value will do */ - var path = '/oauth/authorize?response_type=token&client_id=openshift-challenging-client'; - var request = new CockpitKubeRequest("GET", path, "", config); - - return request.then(function(response) { - /* Shouldn't return success. Not OAuth capable */ - return ""; - }, function(response) { - if (response.status == 302) { - var token; - var header = response.headers["Location"]; - if (header) { - /* - * When OAuth is in play (ie: Openshift, Origin, Atomic, then - * user/password basic auth doesn't work for accessing the API. - * - * Unfortunately kubectl won't let us save both user/password and - * the token (if we wanted it for future use). So we have to remove - * the user and password data. - */ - token = parseBearerToken(header); - if (token) { - delete user.user.username; - delete user.user.password; - user.user.token = token; - } - } - return ""; - } else if (response.status == 404) { - return ""; /* Not OAuth capable */ - } else { - return $q.reject(response); - } - }); - } - - function writeKubectlConfig(cluster, user, context) { - var cluster_args, user_args, cmd_args; - var commands = []; - var promise; - - // Everything here must run serially - if (user && user.user) { - user_args = [ "kubectl", "config", "set-credentials", user.name ]; - - if (user.user.username) { - user_args.push("--username=" + user.user.username); - user_args.push("--password=" + (user.user.password || "")); - } - - if (user.user.token) - user_args.push("--token=" + user.user.token); - - commands.push(user_args); - } - - if (cluster && cluster.cluster) { - cluster_args = [ "kubectl", "config", "set-cluster", - cluster.name, "--server=" + cluster.cluster.server, - "--insecure-skip-tls-verify=" + !!cluster.cluster["insecure-skip-tls-verify"] - ]; - commands.push(cluster_args); - } - - if (context) { - cmd_args = [ "kubectl", "config", "set-context", context.name ]; - - angular.forEach(["namespace", "user", "cluster"], function(value, key) { - if (context.context && context.context[value]) - cmd_args.push("--" + value + "=" + context.context[value]); - }); - commands.push(cmd_args); - commands.push([ "kubectl", "config", "use-context", context.name ]); - } - - promise = $q.when(); - angular.forEach(commands, function(command) { - promise = promise.then(function (result) { - return runCommand(command); - }); - }); - - return promise.then(function () { - return kubectlData().then(function(data) { - return loadConfigData(data); - }); - }).catch(kubectlError); - } - - return { - prepareData: prepareData, - load: load, - writeKubectlConfig: writeKubectlConfig, - populateBearerToken: populateBearerToken - }; - } - ]) - - .controller("ChangeAuthCtrl", [ - "$q", - "$scope", - "$modalInstance", - "dialogData", - "connectionActions", - "CockpitKubeRequest", - "cockpitKubectlConfig", - "sessionCertificates", - function($q, $scope, instance, dialogData, connectionActions, - CockpitKubeRequest, kubectl, sessionCertificates) { - angular.extend($scope, dialogData); - - function connect(data) { - var cluster = data.currentCluster ? data.currentCluster.cluster : null; - var user = data.currentUser ? data.currentUser.user : null; - - var options = kubectl.generateKubeOptions(cluster, user); - var trust = sessionCertificates.getCert(options.address); - - var force = $scope.haveKubectl ? "kubectl" : options; - if (options.tls && trust) { - options.tls["authority"] = { data: trust }; - force = options; - } - - var promise = new CockpitKubeRequest("GET", "/api", "", options); - return promise.then(function() { - return force; - }).catch(function (ex) { - data.error = ex; - angular.extend($scope, data); - $scope.$broadcast("loadData"); - - return $q.reject([]); - }); - } - - $scope.$on("selectUser", function (ev, user) { - var users = $scope.users || {}; - if (user && user.name && !users[user.name]) - delete user.name; - - $scope.currentUser = user; - }); - - $scope.$on("selectCluster", function (ev, cluster) { - var clusters = $scope.clusters || {}; - if (cluster && cluster.name && !clusters[cluster.name]) - delete cluster.name; - - $scope.currentCluster = cluster; - }); - - $scope.saveAndConnect = function (data) { - return connectionActions.populateBearerToken(data.cluster, data.user) - .then(function () { - if ($scope.haveKubectl) { - return connectionActions.writeKubectlConfig(data.cluster, data.user, data.context); - } else { - return $q.when({ - currentUser: data.user, - currentCluster: data.cluster, - }); - } - }, function (ex) { - $scope.currentUser = data.user; - $scope.currentCluster = data.cluster; - $scope.error = ex; - - $scope.$broadcast("loadData"); - return $q.reject([]); - }) - .then(connect); - }; - } - ]) - - .directive("authForm", [ - "$q", - "connectionActions", - "CockpitTranslate", - "CockpitFormat", - function($q, connectionActions, translate, format) { - const _ = translate.gettext; - return { - restrict: "E", - scope: true, - link: function($scope, element, attrs) { - $scope.fields = {}; - - function loadData() { - if ($scope.error) { - var msg = $scope.error.statusText; - if (!msg) - msg = $scope.error.problem; - - if (msg == "not-found") - msg = _("Couldn't find running API server"); - - $scope.failure(format.format(_("Connection Error: $0"), msg)); - } - - if ($scope.currentCluster) - $scope.selectCluster($scope.currentCluster); - else - $scope.fields.address = $scope.defaultAddress; - - if ($scope.currentUser) - $scope.selectUser($scope.currentUser); - - $scope.useAuth = !!$scope.currentUser; - } - - function validate() { - var errors = []; - var ex; - var address_re = /^[a-z0-9:/.-]+$/i; - var address = $scope.fields.address; - var cluster = { cluster: {} }; - var user; - - if (!$scope.fields.address || !address_re.test(address.toLowerCase())) { - ex = new Error(_("Please provide a valid address")); - ex.target = "#kubernetes-address"; - errors.push(ex); - ex = null; - } else if (address.indexOf("http://") !== 0 && - address.indexOf("https://") !== 0) { - address = "http://" + address; - } - - user = $scope.useAuth ? $scope.currentUser : null; - if (!user && $scope.useAuth) - user = { user: {} }; - - if (user && !$scope.fields.username && - (!user.name || user.user.username)) { - ex = new Error(_("Please provide a username")); - ex.target = "#kubernetes-username"; - errors.push(ex); - ex = null; - } - - if ($scope.currentCluster) - cluster = $scope.currentCluster; - - cluster.cluster.server = address; - cluster.cluster["insecure-skip-tls-verify"] = !!$scope.fields.skipVerify; - - if (user) { - if ($scope.fields.username) { - user.user.username = $scope.fields.username; - user.user.password = $scope.fields.password; - } else { - delete user.user.username; - delete user.user.password; - } - if ($scope.fields.token) - user.user.token = $scope.fields.token; - else - delete user.user.token; - } - - if (errors.length > 0) - return $q.reject(errors); - - var data = connectionActions.prepareData($scope.config, cluster, user); - return $q.when(data); - } - - $scope.selectCluster = function selectCluster(cluster) { - var inner = cluster && cluster.cluster ? cluster.cluster : {}; - $scope.fields.address = inner.server; - $scope.fields.skipVerify = !!inner["insecure-skip-tls-verify"]; - $scope.$emit("selectCluster", cluster); - }; - - $scope.selectUser = function selectUser(user) { - var inner = user && user.user ? user.user : {}; - $scope.fields.username = inner.username; - $scope.fields.password = inner.password; - $scope.fields.token = inner.token; - $scope.$emit("selectUser", user); - }; - - $scope.hasCert = function hasCert(user) { - if (user && user.user) return user.user["client-key"] || user.user["client-key-data"]; - return false; - }; - - $scope.toggleAuth = function toggleAuth() { - $scope.useAuth = !$scope.useAuth; - }; - - $scope.update = function() { - return validate().then(function (data) { - return $scope.saveAndConnect(data); - }); - }; - - $scope.$on("loadData", loadData); - loadData(); - }, - templateUrl: "views/auth-form.html" - }; - } - ]) - - .directive("authRejectedCert", [ - "$q", - "connectionActions", - "sessionCertificates", - "cockpitRunCommand", - "CockpitTranslate", - "CockpitFormat", - function($q, connectionActions, sessionCertificates, - runCommand, translate, format) { - const _ = translate.gettext; - return { - restrict: "E", - scope: true, - link: function($scope, element, attrs) { - var pem = null; - $scope.address = null; - - function getCertDetails() { - var options = $scope.error ? $scope.error.options : {}; - var cmd = runCommand([ "openssl", "x509", "-noout", "-text" ]); - options = options || {}; - pem = options["rejected-certificate"]; - cmd.then(function(data) { - $scope.details = data; - }, function(ex) { - var msg = format.format(_("Error getting certificate details: $0"), ex.problem); - $scope.failure(msg); - }); - cmd.send(pem); - cmd.send("\n\n"); - } - - function loadData() { - if ($scope.currentCluster) - $scope.address = $scope.currentCluster.cluster.server; - else - $scope.address = $scope.defaultAddress; - - $scope.action = "skip"; - $scope.details = null; - getCertDetails(); - } - - $scope.update = function update() { - var cluster = { cluster: { server: $scope.address } }; - if ($scope.currentCluster) - cluster = $scope.currentCluster; - - var data = connectionActions.prepareData($scope.config, cluster, $scope.currentUser); - if ($scope.action == "pem") - sessionCertificates.trustCert(data.cluster.cluster, pem); - - if ($scope.action != "pem") - data.cluster.cluster['insecure-skip-tls-verify'] = true; - - return $scope.saveAndConnect(data); - }; - - $scope.$on("loadData", loadData); - loadData(); - }, - templateUrl: "views/auth-rejected-cert.html" - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/containers.js b/pkg/kubernetes/scripts/containers.js deleted file mode 100644 index c58a86ce6..000000000 --- a/pkg/kubernetes/scripts/containers.js +++ /dev/null @@ -1,342 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-route'); - require('angular-dialog.js'); - require('./kube-client'); - require('./listing'); - - require('kubernetes-container-terminal/dist/container-terminal.js'); - - angular.module('kubernetes.containers', [ - 'ngRoute', - 'ui.cockpit', - 'kubernetesUI', - 'kubeClient', - 'kubernetes.listing' - ]) - - .config([ - '$routeProvider', - function($routeProvider) { - $routeProvider - .when('/pods/:pod_namespace/:pod_name/:container_name', { - templateUrl: 'views/container-page.html', - controller: 'ContainerCtrl' - }) - .when('/pods/:pod_namespace/:pod_name', { - redirectTo: '/pods' - }) - .when('/pods/:pod_namespace?', { - templateUrl: 'views/containers-page.html', - controller: 'ContainersCtrl' - }); - } - ]) - - /* - * The controller for the containers view. - */ - .controller('ContainersCtrl', [ - '$scope', - 'KubeContainers', - 'kubeLoader', - 'kubeSelect', - 'ListingState', - '$routeParams', - '$location', - function($scope, containers, loader, select, ListingState, $routeParams, $location) { - var selector = {}; - var qs = $location.search(); - for (var key in qs) { - if (key !== "namespace") - selector[key] = qs[key]; - } - - loader.listen(function() { - var pods = select().kind("Pod"); - if ($routeParams.pod_namespace) - pods.namespace($routeParams.pod_namespace); - if (!angular.equals({}, selector)) - pods.label(selector); - - $scope.pods = pods; - }, $scope); - - loader.watch("Pod", $scope); - - $scope.listing = new ListingState($scope); - - $scope.containers = containers; - - $scope.$on("activate", function(ev, id) { - ev.preventDefault(); - $location.path(id); - }); - - $scope.should_mask = function(name) { - return name.toLowerCase().indexOf("password") !== -1; - }; - } - ]) - - /* - * The controller for the containers view. - */ - .controller('ContainerCtrl', [ - '$scope', - 'KubeContainers', - 'kubeLoader', - 'kubeSelect', - '$routeParams', - '$route', - function($scope, containers, loader, select, $routeParams, $route) { - var target = $routeParams["container_name"] || ""; - $scope.target = target; - - loader.listen(function() { - $scope.pod = select().kind("Pod") - .namespace($routeParams.pod_namespace || "") - .name($routeParams.pod_name || "") - .one(); - if ($scope.pod) { - angular.forEach(containers($scope.pod) || [], function (con) { - if (con.spec && con.spec.name === target) - $scope.container = con; - }); - } - }, $scope); - - loader.watch("Pod", $scope); - - $scope.back = function() { - $route.updateParams({ "container_name" : undefined }); - }; - - $scope.should_mask = function(name) { - return name.toLowerCase().indexOf("password") !== -1; - }; - } - ]) - - /** - * Build an array of container objects where each object contains the data from both - * the spec and status sections of the pod. Looks like this: - * { id: id, spec: pod.spec.containers[n], status: pod.status.containerStatuses[n] } - * - * The returned array will not change once created for a given pod item. - */ - .factory('KubeContainers', [ - 'KubeMapNamedArray', - function(mapNamedArray) { - return function (item) { - var specs, statuses, pod_id; - if (!item.containers) { - pod_id = "pods/" + item.metadata.namespace + "/" + item.metadata.name; - if (item.spec) - specs = mapNamedArray(item.spec.containers); - else - specs = { }; - - if (item.status) - statuses = mapNamedArray(item.status.containerStatuses); - else - statuses = { }; - - item.containers = Object.keys(specs).map(function(name) { - var key = pod_id + "/" + name; - return { spec: specs[name], status: statuses[name], key: key }; - }); - } - return item.containers; - }; - } - ]) - - .directive('containersListing', - function() { - return { - restrict: 'A', - templateUrl: 'views/containers-listing.html' - }; - } - ) - - .directive('containerPageInline', - function() { - return { - restrict: 'A', - templateUrl: 'views/container-page-inline.html' - }; - } - ) - - .directive('kubeContainerBody', - function() { - return { - restrict: 'E', - templateUrl: 'views/container-body.html' - }; - } - ) - - .directive('kubePodBody', - function() { - return { - restrict: 'E', - templateUrl: 'views/pod-body.html' - }; - } - ) - - /* - * Displays a container console. - * - * - */ - .directive('kubeConsole', [ - 'kubernetesContainerSocket', - function(socket) { - return { - restrict: 'E', - scope: { - pod: '&', - container: '&', - command: '@', - prevent: '=' - }, - link: function(scope, element, attrs) { - var limit = 64 * 1024; - - var outer = angular.element("
"); - outer.addClass("console-ct"); - element.append(outer); - var pre = angular.element("
");
-                            outer.append(pre);
-                            var wait = null;
-                            var ws = null;
-
-                            function connect() {
-                                pre.empty();
-
-                                var url = "";
-                                var pod = scope.pod();
-                                if (pod.metadata)
-                                    url += pod.metadata.selfLink;
-                                else
-                                    url += pod;
-                                url += "/log";
-                                if (url.indexOf('?') === -1)
-                                    url += '?';
-                                url += "follow=1";
-
-                                var container = scope.container ? scope.container() : null;
-                                if (container)
-                                    url += "&container=" + encodeURIComponent(container);
-
-                                var writing = [];
-                                var count = 0;
-
-                                function drain() {
-                                    wait = null;
-                                    var at_bottom = pre[0].scrollHeight - pre[0].scrollTop <= pre[0].offsetHeight;
-                                    var text = writing.join("");
-
-                                    /*
-                             * Stay under the limit. I wish we could use some other mechanism
-                             * for limiting the log output, such as:
-                             *
-                             * https://github.com/kubernetes/kubernetes/issues/12447
-                             */
-                                    count += text.length;
-                                    var children, first, removed;
-                                    while (count > limit) {
-                                        children = pre.children();
-                                        if (children.length < 1)
-                                            break;
-
-                                        first = angular.element(children[0]);
-                                        removed = first.text().length;
-                                        first.remove();
-                                        count -= removed;
-                                    }
-
-                                    /* And add our text */
-                                    var span = angular.element("").text(text);
-                                    writing.length = 0;
-                                    pre.append(span);
-                                    if (at_bottom)
-                                        pre[0].scrollTop = pre[0].scrollHeight;
-                                }
-
-                                ws = socket(url);
-                                ws.onclose = function(ev) {
-                                    writing.push(ev.reason);
-                                    drain();
-                                    disconnect();
-                                    ws = null;
-                                };
-                                ws.onmessage = function(ev) {
-                                    writing.push(ev.data);
-                                    if (wait === null)
-                                        wait = window.setTimeout(drain, 50);
-                                };
-                            }
-
-                            function disconnect() {
-                                if (ws) {
-                                    ws.onopen = ws.onmessage = ws.onerror = ws.onclose = null;
-                                    if (ws.readyState < 2) // CLOSING
-                                        ws.close();
-                                    ws = null;
-                                }
-                                window.clearTimeout(wait);
-                                wait = null;
-                            }
-
-                            scope.$watch("prevent", function(prevent) {
-                                if (!prevent && !ws)
-                                    connect();
-                            });
-
-                            scope.$on("$destroy", disconnect);
-                        }
-                    };
-                }
-            ])
-
-    /*
-     * Filter to display short docker ids
-     *
-     * {{ myid | kube-identifier }}
-     *
-     * Removes docker:// prefix and shortens.
-     */
-            .filter('kubeIdentifier', function() {
-                var regex = /docker:\/\/([\w]{12})\w+/;
-                return function(item) {
-                    var match = regex.exec(item);
-                    if (match)
-                        return match[1];
-                    return item;
-                };
-            });
-}());
diff --git a/pkg/kubernetes/scripts/dashboard.js b/pkg/kubernetes/scripts/dashboard.js
deleted file mode 100644
index 863a8e31b..000000000
--- a/pkg/kubernetes/scripts/dashboard.js
+++ /dev/null
@@ -1,514 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    require('angular-route');
-
-    require('./details');
-    require('./app');
-    require('./graphs');
-    require('./nodes');
-    require('./volumes');
-
-    require('../views/dashboard-page.html');
-    require('../views/deploy.html');
-    require('../views/file-button.html');
-
-    angular.module('kubernetes.dashboard', [
-        'ngRoute',
-        'kubernetes.details',
-        'kubernetes.app',
-        'kubernetes.graph',
-        'kubernetes.nodes'
-    ])
-
-            .config(['$routeProvider', function($routeProvider) {
-                $routeProvider.when('/', {
-                    templateUrl: 'views/dashboard-page.html',
-                    controller: 'DashboardCtrl',
-                    reloadOnSearch: false,
-                });
-            }])
-
-            .controller('DashboardCtrl', [
-                '$scope',
-                'kubeLoader',
-                'kubeSelect',
-                'dashboardData',
-                'dashboardActions',
-                'itemActions',
-                'nodeActions',
-                'nodeData',
-                '$location',
-                function($scope, loader, select, data, actions, itemActions,
-                    nodeActions, nodeData, $location) {
-                    loader.listen(function() {
-                        $scope.services = select().kind("Service");
-                        $scope.nodes = select().kind("Node");
-                        $scope.pods = select().kind("Pod");
-                        $scope.volumes = select().kind("PersistentVolume");
-                        $scope.pvcs = select().kind("PersistentVolumeClaim");
-
-                        $scope.status = {
-                            pods: {
-                                Pending: $scope.pods.statusPhase("Pending"),
-                                Failed: $scope.pods.statusPhase("Failed"),
-                                Unknown: $scope.pods.statusPhase("Unknown"),
-                            },
-                            nodes: {
-                                Pending: $scope.nodes.statusPhase("Pending"),
-                                Terminated: $scope.nodes.statusPhase("Terminated"),
-                                NotReady: $scope.nodes.conditionNotTrue("Ready"),
-                                OutOfDisk: $scope.nodes.conditionTrue("OutOfDisk"),
-                            },
-                            volumes: {
-                                Pending: $scope.volumes.statusPhase("Pending"),
-                                PendingClaims: $scope.pvcs.statusPhase("Pending"),
-                                Available: $scope.volumes.statusPhase("Available"),
-                                Released: $scope.volumes.statusPhase("Released"),
-                                Failed: $scope.volumes.statusPhase("Failed"),
-                            },
-                        };
-                    }, $scope);
-
-                    loader.watch("Node", $scope);
-                    loader.watch("Service", $scope);
-                    loader.watch("ReplicationController", $scope);
-                    loader.watch("Pod", $scope);
-                    loader.watch("PersistentVolume", $scope);
-                    loader.watch("PersistentVolumeClaim", $scope);
-
-                    $scope.editServices = false;
-                    $scope.toggleServiceChange = function toggleServiceChange() {
-                        $scope.editServices = !$scope.editServices;
-                    };
-
-                    $scope.jumpService = function jumpService(ev, service) {
-                        if ($scope.editServices)
-                            return;
-
-                        var meta = service.metadata || {};
-                        var spec = service.spec || {};
-                        if (spec.selector && !angular.equals({}, spec.selector) && meta.namespace)
-                            $location.path("/pods/" + encodeURIComponent(meta.namespace)).search(spec.selector);
-                    };
-
-                    $scope.navigateNode = function(node) {
-                        var meta = node.metadata || {};
-                        if (meta.name)
-                            $location.path("/nodes/" + encodeURIComponent(meta.name));
-                    };
-
-                    /* All the actions available on the $scope */
-                    angular.extend($scope, actions);
-                    angular.extend($scope, data);
-                    angular.extend($scope, nodeData);
-                    $scope.modifyService = itemActions.modifyService;
-                    $scope.addNode = nodeActions.addNode;
-
-                    /* Highlighting */
-
-                    $scope.highlighted = null;
-                    $scope.$on("highlight", function(ev, uid) {
-                        $scope.highlighted = uid;
-                    });
-                    $scope.highlight = function highlight(uid) {
-                        $scope.$broadcast("highlight", uid);
-                    };
-
-                    $scope.servicesState = function services_state() {
-                        if ($scope.failure)
-                            return 'failed';
-                        var service;
-                        for (service in $scope.services)
-                            break;
-                        return service ? 'ready' : 'empty';
-                    };
-                }])
-
-            .directive('kubernetesAddress', function() {
-                return {
-                    restrict: 'E',
-                    link: function($scope, element, attributes) {
-                        $scope.$watchGroup(["item.spec.clusterIP", "item.spec.ports"], function(values) {
-                            var address = values[0];
-                            var ports = values[1];
-                            var href = null;
-                            var text = null;
-
-                            /* No ports */
-                            if (!ports || !ports.length) {
-                                text = address;
-
-                                /* One single HTTP or HTTPS port */
-                            } else if (ports.length == 1) {
-                                text = address + ":" + ports[0].port;
-                                if (ports[0].protocol === "TCP") {
-                                    if (ports[0].port === 80)
-                                        href = "http://" + encodeURIComponent(address);
-                                    else if (ports[0].port === 443)
-                                        href = "https://" + encodeURIComponent(address);
-                                } else {
-                                    text += "/" + ports[0].protocol;
-                                }
-                            } else {
-                                text = " " + address + " " + ports.map(function(p) {
-                                    if (p.protocol === "TCP")
-                                        return p.port;
-                                    else
-                                        return p.port + "/" + p.protocol;
-                                }).join(" ");
-                            }
-
-                            var el;
-                            element.empty();
-                            if (href) {
-                                el = angular.element("")
-                                        .attr("href", href)
-                                        .attr("target", "_blank")
-                                        .on("click", function(ev) { ev.stopPropagation() });
-                                element.append(el);
-                            } else {
-                                el = element;
-                            }
-                            el.text(text);
-                        });
-                    }
-                };
-            })
-
-            .factory('dashboardActions', [
-                '$modal',
-                function($modal) {
-                    function deploy() {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'DeployCtrl',
-                            templateUrl: 'views/deploy.html',
-                            resolve: {},
-                        }).result;
-                    }
-
-                    return {
-                        deploy: deploy,
-                    };
-                }
-            ])
-
-            .factory('dashboardData', [
-                'kubeSelect',
-                function(select) {
-                    function conditionDigest(arg, match) {
-                        if (typeof arg == "string")
-                            return [ arg ];
-                        var conditions = (arg.status || { }).conditions || [ ];
-                        var result = [ ];
-                        conditions.forEach(function(condition) {
-                            if ((match && condition.status == "True") ||
-                        (!match && condition.status != "True")) {
-                                result.push(condition.type);
-                            }
-                        });
-                        return result;
-                    }
-
-                    select.register({
-                        name: "conditionTrue",
-                        digests: function(arg) {
-                            return conditionDigest(arg, true);
-                        }
-                    });
-
-                    select.register({
-                        name: "conditionNotTrue",
-                        digests: function(arg) {
-                            return conditionDigest(arg, false);
-                        }
-                    });
-
-                    return {
-                        nodeContainers: function nodeContainers(node) {
-                            var count = 0;
-                            var meta = node.metadata || { };
-                            angular.forEach(select().kind("Pod")
-                                    .host(meta.name), function(pod) {
-                                var spec = pod.spec || { };
-                                var n = 1;
-                                if (spec.containers)
-                                    n = spec.containers.length;
-                                count += n;
-                            });
-                            return count;
-                        },
-
-                        serviceStatus: function serviceStatus(service) {
-                            var spec = service.spec || { };
-                            var meta = service.metadata || { };
-                            var state = "";
-
-                            var pods = select().kind("Pod")
-                                    .namespace(meta.namespace || "")
-                                    .label(spec.selector || {});
-                            angular.forEach(pods, function(pod) {
-                                if (!pod.status || !pod.status.phase)
-                                    return;
-                                switch (pod.status.phase) {
-                                case "Pending":
-                                    if (!state)
-                                        state = "wait";
-                                    break;
-                                case "Running":
-                                    break;
-                                case "Succeeded":
-                                    break;
-                                case "Unknown":
-                                    break;
-                                case "Failed":
-                                    /* falls through */
-                                default: /* assume failed */
-                                    state = "fail";
-                                    break;
-                                }
-                            });
-
-                            return state;
-                        },
-
-                        serviceContainers: function serviceContainers(service) {
-                            var spec = service.spec || { };
-                            var meta = service.metadata || {};
-
-                            /* Calculate number of containers */
-                            var x = 0;
-                            var y = 0;
-
-                            /*
-                     * Calculate "x of y" containers, where x is the current
-                     * number and y is the expected number. If x==y then only
-                     * show x. The calculation is based on the statuses of the
-                     * containers within the pod.  Pod states: Pending,
-                     * Running, Succeeded, Failed, and Unknown.
-                     */
-                            var pods = select().kind("Pod")
-                                    .namespace(meta.namespace || "")
-                                    .label(spec.selector || {});
-                            angular.forEach(pods, function(pod) {
-                                if (!pod.status || !pod.status.phase)
-                                    return;
-                                var spec = pod.spec || { };
-                                var n = 1;
-                                if (spec.containers)
-                                    n = spec.containers.length;
-                                switch (pod.status.phase) {
-                                case "Pending":
-                                    y += n;
-                                    break;
-                                case "Running":
-                                    x += n;
-                                    y += n;
-                                    break;
-                                case "Succeeded": // don't increment either counter
-                                    break;
-                                case "Unknown":
-                                    y += n;
-                                    break;
-                                case "Failed":
-                                    /* falls through */
-                                default: /* assume failed */
-                                    y += n;
-                                    break;
-                                }
-                            });
-
-                            if (x != y)
-                                return x + " of " + y;
-                            else
-                                return "" + x;
-                        }
-                    };
-                }
-            ])
-
-            .controller("DeployCtrl", [
-                "$q",
-                "$scope",
-                "$timeout",
-                "$modalInstance",
-                "filterService",
-                "kubeMethods",
-                "KubeFormat",
-                "KubeTranslate",
-                function($q, $scope, $timeout, $instance, filter, methods, KubeFormat, translate) {
-                    const _ = translate.gettext;
-
-                    var file;
-                    var fields = {
-                        "filename": "",
-                        "namespace" : filter.namespace(),
-                    };
-
-                    function validate_manifest() {
-                        var defer = $q.defer();
-                        var ex;
-                        var fails = [];
-
-                        var ns = fields.namespace;
-                        if (!ns)
-                            ex = new Error(_("Namespace cannot be empty."));
-                        else if (!/^[a-z0-9]+$/i.test(ns))
-                            ex = new Error(_("Please provide a valid namespace."));
-                        if (ex) {
-                            ex.target = "#deploy-app-namespace-group";
-                            fails.push(ex);
-                            ex = null;
-                        }
-
-                        if (!file)
-                            ex = new Error(_("No metadata file was selected. Please select a Kubernetes metadata file."));
-                        else if (file.type && !file.type.match("json.*"))
-                            ex = new Error(_("The selected file is not a valid Kubernetes application manifest."));
-                        if (ex) {
-                            ex.target = "#deploy-app-manifest-file-button";
-                            fails.push(ex);
-                            ex = null;
-                        }
-
-                        var reader;
-
-                        if (fails.length) {
-                            defer.reject(fails);
-                        } else {
-                            reader = new window.FileReader();
-                            reader.onerror = function(event) {
-                                ex = new Error(KubeFormat.format(_("Unable to read the Kubernetes application manifest. Code $0."),
-                                                                 event.target.error.code));
-                                ex.target = "#deploy-app-manifest-file-button";
-                                defer.reject(ex);
-                            };
-                            reader.onload = function() {
-                                try {
-                                    defer.resolve({
-                                        objects : JSON.parse(reader.result),
-                                        namespace : ns
-                                    });
-                                } catch (err) {
-                                    ex = new Error(KubeFormat.format(_("Unable to decode Kubernetes application manifest.")));
-                                    ex.target = "#deploy-app-manifest-file-button";
-                                    defer.reject(ex);
-                                }
-                            };
-                            reader.readAsText(file);
-                        }
-
-                        return defer.promise;
-                    }
-
-                    function deploy_manifest() {
-                        var defer = $q.defer();
-
-                        validate_manifest().then(function(data) {
-                            methods.create(data.objects, data.namespace)
-                                    .then(function() {
-                                        if ($scope.namespace && data.namespace != $scope.namespace)
-                                            filter.namespace(data.namespace);
-                                        defer.resolve();
-                                    })
-                                    .catch(function(response) {
-                                        var ex;
-                                        var resp = response.data;
-
-                                        /* Interpret this code as a conflict, so suggest user creates a new namespace */
-                                        if (response && response.code === 409) {
-                                            ex = new Error(KubeFormat.format(_("Please create another namespace for $0 \"$1\""),
-                                                                             response.details.kind, response.details.id));
-                                            ex.target = "#deploy-app-namespace-field";
-                                        } else {
-                                            ex = resp || response;
-                                        }
-
-                                        defer.reject(ex);
-                                    });
-                        }, function(ex) {
-                            defer.reject(ex);
-                        });
-
-                        return defer.promise;
-                    }
-
-                    $scope.types = [
-                        {
-                            name: _("Manifest"),
-                            type: "manifest",
-                        }
-                    ];
-
-                    $scope.selected = $scope.types[0];
-                    $scope.fields = fields;
-                    $scope.namespaces = filter.namespaces();
-                    $scope.namespace = filter.namespace();
-
-                    $scope.$on("file", function(ev, newFile) {
-                        $scope.$applyAsync(function() {
-                            file = newFile;
-                            fields.filename = file ? file.name : "";
-                        });
-                    });
-
-                    $scope.performDeploy = function performDeploy() {
-                        if ($scope.selected.type == 'manifest') {
-                            return deploy_manifest();
-                        }
-                    };
-
-                    $scope.select = function(type) {
-                        $scope.selected = type;
-                    };
-                }
-            ])
-
-            .directive('fileButton', function() {
-                return {
-                    templateUrl: 'views/file-button.html',
-                    restrict: 'A',
-                    link: function($scope, element, attributes) {
-                        var button, file_input;
-                        if (element[0].children.length == 2) {
-                            button = element[0].children[1];
-                            file_input = element[0].children[0];
-                            button.onclick = function () {
-                                file_input.click();
-                            };
-                            file_input.onchange = function () {
-                                var files = file_input.files || [];
-                                $scope.$emit('file', files[0]);
-                            };
-                        }
-
-                        element.on('$destroy', function() {
-                            if (file_input)
-                                file_input.onchange = null;
-
-                            if (button)
-                                button.onclick = null;
-                        });
-                    }
-                };
-            });
-}());
diff --git a/pkg/kubernetes/scripts/date.js b/pkg/kubernetes/scripts/date.js
deleted file mode 100644
index c71cc46db..000000000
--- a/pkg/kubernetes/scripts/date.js
+++ /dev/null
@@ -1,73 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    var moment = require('moment');
-
-    require('./kube-client');
-
-    angular.module('kubernetes.date', [
-        "kubeClient"
-    ])
-
-            .factory('momentLib', [
-                function() {
-                    return moment;
-                }
-            ])
-
-            .factory('refreshEveryMin', [
-                "$rootScope",
-                "$window",
-                "kubeLoader",
-                function($rootScope, $window, loader) {
-                    var last = 0;
-                    var interval = 60000;
-                    var tol = 500;
-
-                    loader.listen(function() {
-                        last = (new Date()).getTime();
-                    });
-
-                    $window.setInterval(function() {
-                        var now = (new Date()).getTime();
-                        if ((now - last) + tol >= interval)
-                            $rootScope.$applyAsync();
-                        last = now;
-                    }, interval);
-
-                    return {};
-                }
-            ])
-
-            .filter('dateRelative', [
-                "refreshEveryMin",
-                function() {
-                    function dateRelative(timestamp) {
-                        if (!timestamp) {
-                            return timestamp;
-                        }
-                        return moment(timestamp).fromNow();
-                    }
-                    dateRelative.$stateful = true;
-                    return dateRelative;
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/details.js b/pkg/kubernetes/scripts/details.js
deleted file mode 100644
index 394573991..000000000
--- a/pkg/kubernetes/scripts/details.js
+++ /dev/null
@@ -1,736 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    require('object-describer/dist/object-describer.js');
-    require('kubernetes-object-describer/dist/object-describer.js');
-    require('angular-dialog.js');
-
-    require('./containers');
-    require('./date');
-    require('./kube-client');
-    require('./listing');
-    require('./utils');
-    require('./volumes');
-
-    require('../views/details-page.html');
-    require('../views/pod-container.html');
-    require('../views/details-page.html');
-    require('../views/item-delete.html');
-    require('../views/route-modify.html');
-    require('../views/replicationcontroller-modify.html');
-    require('../views/service-modify.html');
-    require('../views/deploymentconfig-body.html');
-    require('../views/replicationcontroller-pods.html');
-    require('../views/replicationcontroller-body.html');
-    require('../views/route-body.html');
-    require('../views/service-body.html');
-    require('../views/service-endpoint.html');
-
-    require('../views/pod-page.html');
-    require('../views/image-page.html');
-    require('../views/registry-dashboard-page.html');
-    require('../views/details-page.html');
-    require('../views/project-page.html');
-    require('../views/topology-page.html');
-    require('../views/node-page.html');
-    require('../views/dashboard-page.html');
-    require('../views/nodes-page.html');
-    require('../views/deploymentconfig-page.html');
-    require('../views/pv-page.html');
-    require('../views/container-page.html');
-    require('../views/service-page.html');
-    require('../views/group-page.html');
-    require('../views/containers-page.html');
-    require('../views/projects-page.html');
-    require('../views/user-page.html');
-    require('../views/images-page.html');
-    require('../views/replicationcontroller-page.html');
-    require('../views/route-page.html');
-    require('../views/imagestream-page.html');
-    require('../views/volumes-page.html');
-
-    function validItem(item, type) {
-        var valid = (item && (!type || item.kind === type) &&
-                     item.spec && item.metadata);
-        var type_name = type || "Object";
-
-        if (!valid)
-            console.warn("Invalid " + type_name, item);
-
-        return valid;
-    }
-
-    function format_addresses_with_ports(addresses, ports) {
-        var text = addresses.join(", ");
-
-        if (ports && ports.length) {
-            text = text + ":" + ports.map(function(p) {
-                if (p.protocol === "TCP")
-                    return p.port;
-                else
-                    return p.port + "/" + p.protocol;
-            }).join(", ");
-        }
-
-        return text;
-    }
-
-    angular.module('kubernetes.details', [
-        'ngRoute',
-        'ui.cockpit',
-        'kubernetesUI',
-        'kubeClient',
-        'kubeUtils',
-        'kubernetes.listing',
-        'kubernetes.date',
-        'kubernetes.volumes',
-        'kubernetes.containers',
-    ])
-
-            .config([
-                '$routeProvider',
-                function($routeProvider) {
-                    $routeProvider
-                            .when('/list/:namespace?', {
-                                templateUrl: 'views/details-page.html',
-                                controller: 'DetailsCtrl'
-                            })
-                            .when('/l/pods/:pod_namespace/:pod_name/:container_name', {
-                                templateUrl: 'views/pod-container.html',
-                                controller: 'ContainerCtrl',
-                            })
-                            .when('/l/:target_type/:target_namespace/:target', {
-                                templateUrl: function (params) {
-                                    var re = /s$/;
-                                    var kind = params.target_type || "";
-
-                                    return 'views/' + kind.replace(re, "") + "-page.html";
-                                },
-                                controller: 'DetailCtrl',
-                                resolve: {
-                                    'kindData': [
-                                        'kindData',
-                                        function (kindData) {
-                                            return kindData();
-                                        }
-                                    ]
-                                }
-                            })
-                            .when('/l/:target_type', {
-                                templateUrl: 'views/details-page.html',
-                                controller: 'DetailCtrl',
-                                resolve: {
-                                    'kindData': [
-                                        'kindData',
-                                        function (kindData) {
-                                            return kindData();
-                                        }
-                                    ]
-                                }
-                            });
-                }
-            ])
-
-            .factory("kindData", [
-                "$q",
-                "$route",
-                "$location",
-                function($q, $route, $location) {
-                    var typesToKinds = {
-                        'services': 'Service',
-                        'routes': 'Route',
-                        'deploymentconfigs': 'DeploymentConfig',
-                        'replicationcontrollers': 'ReplicationController',
-                        'pods': 'Pod',
-                    };
-
-                    return function() {
-                        var current = $route.current.params['target_type'];
-                        var kind;
-                        if (current)
-                            kind = typesToKinds[current];
-
-                        if (!kind) {
-                            $location.path('/');
-                            return $q.reject();
-                        }
-
-                        return $q.when({
-                            'kind' : kind,
-                            'type' : current,
-                        });
-                    };
-                }
-            ])
-
-            .factory("detailsWatch", [
-                "kubeLoader",
-                "KubeDiscoverSettings",
-                function (loader, settings) {
-                    return function(until) {
-                        loader.watch("Pod", until);
-                        loader.watch("Service", until);
-                        loader.watch("ReplicationController", until);
-                        loader.watch("Endpoints", until);
-                        loader.watch("PersistentVolumeClaim", until);
-                        settings().then(function(settings) {
-                            if (settings.flavor === "openshift") {
-                                loader.watch("DeploymentConfig", until);
-                                loader.watch("Route", until);
-                            }
-                        });
-                    };
-                }
-            ])
-
-            .factory("detailsData", [
-                'kubeSelect',
-                'volumeData',
-                'KubeContainers',
-                "KubeTranslate",
-                function (select, volumeData, containers, translate) {
-                    const _ = translate.gettext;
-                    var names = {
-                        'services': {
-                            'name' : _("Services")
-                        },
-                        'routes': {
-                            'name' : _("Routes"),
-                            'flavor': "openshift"
-                        },
-                        'deploymentconfigs': {
-                            'name': _("Deployment Configs"),
-                            'flavor': "openshift"
-                        },
-                        'replicationcontrollers': {
-                            'name' : _("Replication Controllers")
-                        },
-                        'pods': {
-                            'name' : _("Pods")
-                        }
-                    };
-
-                    function item_identifier(item) {
-                        var meta = item.metadata || { };
-                        var id = item.kind.toLowerCase() + "s/";
-                        if (meta.namespace)
-                            id = id + meta.namespace + "/";
-                        return id + meta.name;
-                    }
-
-                    function service_endpoint(service) {
-                        return select().kind("Endpoints")
-                                .namespace(service.metadata.namespace)
-                                .name(service.metadata.name)
-                                .one();
-                    }
-
-                    function replicationcontroller_pods(item) {
-                        var meta = item.metadata || {};
-                        var spec = item.spec || {};
-                        return select().kind("Pod")
-                                .namespace(meta.namespace || "")
-                                .label(spec.selector || {});
-                    }
-
-                    function podStatus(item) {
-                        var status = item.status || {};
-                        var meta = item.metadata || {};
-
-                        if (meta.deletionTimestamp)
-                            return "Terminating";
-                        else
-                            return status.phase;
-                    }
-
-                    return {
-                        itemIdentifier: item_identifier,
-                        serviceEndpoint: service_endpoint,
-                        replicationcontrollerPods: replicationcontroller_pods,
-                        podStatus: podStatus,
-                        volumesForPod: volumeData.volumesForPod,
-                        claimFromVolumeSource: volumeData.claimFromVolumeSource,
-                        containers: containers,
-                        names: names
-                    };
-                }
-            ])
-
-    /*
-     * The controller for the details view.
-     */
-            .controller('DetailsCtrl', [
-                '$scope',
-                'kubeLoader',
-                'kubeSelect',
-                'KubeDiscoverSettings',
-                'ListingState',
-                '$location',
-                'itemActions',
-                'detailsData',
-                'detailsWatch',
-                function($scope, loader, select, discoverSettings, ListingState,
-                    $location, actions, detailsData, detailsWatch) {
-                    loader.listen(function() {
-                        $scope.pods = select().kind("Pod");
-                        $scope.services = select().kind("Service");
-                        $scope.replicationcontrollers = select().kind("ReplicationController");
-                        $scope.deploymentconfigs = select().kind("DeploymentConfig");
-                        $scope.routes = select().kind("Route");
-                    }, $scope);
-
-                    detailsWatch($scope);
-                    $scope.listing = new ListingState($scope);
-                    $scope.showAll = true;
-
-                    $scope.$on("activate", function(ev, id) {
-                        ev.preventDefault();
-                        actions.navigate(id);
-                    });
-
-                    /* All the data and actions available on the $scope */
-                    angular.extend($scope, detailsData);
-                    angular.extend($scope, actions);
-                }
-            ])
-
-            .controller('DetailCtrl', [
-                '$scope',
-                'kindData',
-                'kubeLoader',
-                'kubeSelect',
-                'ListingState',
-                '$routeParams',
-                '$location',
-                'itemActions',
-                'detailsData',
-                'detailsWatch',
-                function($scope, kindData, loader, select, ListingState, $routeParams,
-                    $location, actions, detailsData, detailsWatch) {
-                    var target = $routeParams["target"] || "";
-                    $scope.target = target;
-                    $scope.name = detailsData.names[kindData.type].name;
-
-                    loader.listen(function() {
-                        if (kindData.type)
-                            $scope[kindData.type] = select().kind(kindData.kind);
-
-                        if (target && $routeParams.target_namespace) {
-                            $scope.item = select().kind(kindData.kind)
-                                    .namespace($routeParams.target_namespace)
-                                    .name(target)
-                                    .one();
-                        }
-                    }, $scope);
-
-                    detailsWatch($scope);
-                    $scope.listing = new ListingState($scope);
-                    $scope.listing.inline = true;
-
-                    $scope.$on("activate", function(ev, id) {
-                        ev.preventDefault();
-                        actions.navigate(id);
-                    });
-
-                    /* All the data and actions available on the $scope */
-                    angular.extend($scope, detailsData);
-                    angular.extend($scope, actions);
-                    angular.extend($scope, kindData);
-                }
-            ])
-
-            .directive('kubernetesServiceCluster', function() {
-                return {
-                    restrict: 'E',
-                    link: function($scope, element, attributes) {
-                        $scope.$watchGroup(["item.spec.clusterIP",
-                            "item.spec.ports"], function(values) {
-                            var text = format_addresses_with_ports([values[0]],
-                                                                   values[1]);
-                            element.text(text);
-                        });
-                    }
-                };
-            })
-
-            .factory('itemActions', [
-                '$modal',
-                '$location',
-                function($modal, $location) {
-                    function deleteItem(item) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'ItemDeleteCtrl',
-                            templateUrl: 'views/item-delete.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { item: item };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function modifyRoute(item) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'RouteModifyCtrl',
-                            templateUrl: 'views/route-modify.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { item: item };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function modifyRC(item) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'RCModifyCtrl',
-                            templateUrl: 'views/replicationcontroller-modify.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { item: item };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function modifyService(item) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'ServiceModifyCtrl',
-                            templateUrl: 'views/service-modify.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { item: item };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function navigate(path) {
-                        var prefix = '/l';
-                        path = path || "";
-                        if (!path)
-                            prefix = "/list";
-
-                        if (path && path.indexOf('/') !== 0)
-                            prefix = prefix + '/';
-
-                        $location.path(prefix + path);
-                    }
-
-                    return {
-                        modifyRC: modifyRC,
-                        modifyRoute: modifyRoute,
-                        deleteItem: deleteItem,
-                        modifyService: modifyService,
-                        navigate: navigate,
-                    };
-                }
-            ])
-
-            .controller("ItemDeleteCtrl", [
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                function($scope, $instance, dialogData, methods) {
-                    angular.extend($scope, dialogData);
-
-                    $scope.performDelete = function performDelete() {
-                        return methods.delete($scope.item).catch(function(ex) {
-                            /* HACK: While debugging delete issues */
-                            console.log(JSON.stringify(ex));
-                        });
-                    };
-                }
-            ])
-
-            .controller("RCModifyCtrl", [
-                "$q",
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                "KubeTranslate",
-                function($q, $scope, $instance, dialogData, methods, translate) {
-                    const _ = translate.gettext;
-                    var item = dialogData.item;
-                    var fields = {};
-
-                    if (!validItem(item, "ReplicationController")) {
-                        $scope.$applyAsync(function () {
-                            $scope.$dismiss();
-                        });
-                        return;
-                    }
-
-                    fields.replicas = item.spec ? item.spec.replicas : 1;
-
-                    function validate() {
-                        var defer = $q.defer();
-                        var replicas = Number(fields.replicas.trim());
-                        var ex;
-
-                        if (isNaN(replicas) || replicas < 0)
-                            ex = new Error(_("Not a valid number of replicas"));
-                        else if (replicas > 128)
-                            ex = new Error(_("The maximum number of replicas is 128"));
-
-                        if (ex) {
-                            ex.target = "#replicas";
-                            defer.reject(ex);
-                        } else {
-                            defer.resolve({ spec: { replicas: replicas } });
-                        }
-
-                        return defer.promise;
-                    }
-
-                    $scope.fields = fields;
-                    $scope.item = item;
-
-                    $scope.performModify = function performModify() {
-                        return validate().then(function(data) {
-                            return methods.patch($scope.item, data);
-                        });
-                    };
-                }
-            ])
-
-            .controller("RouteModifyCtrl", [
-                "$q",
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                "KubeTranslate",
-                function($q, $scope, $instance, dialogData, methods, translate) {
-                    const _ = translate.gettext;
-                    var fields = {};
-
-                    if (!validItem(dialogData.item, "Route")) {
-                        $scope.$applyAsync(function () {
-                            $scope.$dismiss();
-                        });
-                        return;
-                    }
-
-                    fields.host = dialogData.item.spec.host;
-
-                    function validate() {
-                        var defer = $q.defer();
-                        var host = fields.host.trim();
-                        var ex;
-
-                        if (!host) {
-                            ex = new Error(_("Not a valid value for Host"));
-                            ex.target = "#host-value";
-                            defer.reject(ex);
-                        } else {
-                            defer.resolve({ spec: { host: fields.host.trim() } });
-                        }
-
-                        return defer.promise;
-                    }
-
-                    $scope.fields = fields;
-                    angular.extend($scope, dialogData);
-
-                    $scope.performModify = function performModify() {
-                        return validate().then(function(data) {
-                            return methods.patch($scope.item, data);
-                        });
-                    };
-                }
-            ])
-
-            .controller("ServiceModifyCtrl", [
-                "$q",
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                'kubeLoader',
-                'kubeSelect',
-                "KubeRequest",
-                "KubeTranslate",
-                "KubeFormat",
-                function($q, $scope, $instance, dialogData, loader, select, KubeRequest, translate, format) {
-                    const _ = translate.gettext;
-                    var fields = {};
-                    var key;
-
-                    if (!validItem(dialogData.item, "Service")) {
-                        $scope.$applyAsync(function () {
-                            $scope.$dismiss();
-                        });
-                        return;
-                    }
-
-                    $scope.rcs = select().kind("ReplicationController")
-                            .namespace(dialogData.item.metadata.namespace || "")
-                            .label(dialogData.item.spec.selector || {});
-
-                    for (key in $scope.rcs) {
-                        var item = $scope.rcs[key];
-                        fields[key] = {
-                            name: item.metadata.name,
-                            replicas: item.spec.replicas,
-                        };
-                    }
-
-                    $scope.service = dialogData.item;
-                    $scope.fields = fields;
-                    angular.extend($scope, dialogData);
-
-                    function validate() {
-                        var defer = $q.defer();
-                        var link;
-                        var objects = [];
-                        var failures = [];
-
-                        for (link in fields) {
-                            var ex;
-                            var replicas = Number(fields[link].replicas);
-                            var name = fields[link].name;
-
-                            if (isNaN(replicas) || replicas < 0)
-                                ex = new Error(_("Not a valid number of replicas"));
-                            else if (replicas > 128)
-                                ex = new Error(_("The maximum number of replicas is 128"));
-
-                            if (ex) {
-                                ex.target = "#" + name;
-                                failures.push(ex);
-                            } else {
-                                objects.push({
-                                    link: link,
-                                    name: name,
-                                    data: { spec: { replicas: replicas } }
-                                });
-                            }
-                        }
-
-                        if (failures.length > 0) {
-                            defer.reject(failures);
-                        } else
-                            defer.resolve(objects);
-
-                        return defer.promise;
-                    }
-
-                    $scope.performModify = function performModify() {
-                        var defer = $q.defer();
-                        var req;
-
-                        validate().then(function (objects) {
-                            function step() {
-                                var obj = objects.shift();
-                                if (!obj) {
-                                    defer.resolve();
-                                    return;
-                                }
-
-                                defer.notify(format.format(_("Updating $0..."), obj.name));
-
-                                var config = { headers: { "Content-Type": "application/strategic-merge-patch+json" } };
-                                new KubeRequest("PATCH", obj.link, JSON.stringify(obj.data), config)
-                                        .then(function(response) {
-                                            step();
-                                        }, function(response) {
-                                            var resp = response.data;
-                                            return defer.reject(resp || response);
-                                        });
-                            }
-
-                            step();
-                        })
-                                .catch(function(exs) {
-                                    defer.reject(exs);
-                                });
-
-                        var promise = defer.promise;
-                        promise.cancel = function cancel() {
-                            if (req && req.cancel)
-                                req.cancel();
-                        };
-
-                        return promise;
-                    };
-                }
-            ])
-
-            .directive('deploymentconfigBody',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/deploymentconfig-body.html'
-                           };
-                       }
-            )
-
-            .directive('replicationcontrollerPods',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/replicationcontroller-pods.html'
-                           };
-                       }
-            )
-
-            .directive('replicationcontrollerBody',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/replicationcontroller-body.html'
-                           };
-                       }
-            )
-
-            .directive('routeBody',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/route-body.html'
-                           };
-                       }
-            )
-
-            .directive('serviceBody',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/service-body.html'
-                           };
-                       }
-            )
-
-            .directive('serviceEndpoint',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/service-endpoint.html'
-                           };
-                       }
-            );
-}());
diff --git a/pkg/kubernetes/scripts/fixture-basic.js b/pkg/kubernetes/scripts/fixture-basic.js
deleted file mode 100644
index 5b2594f1d..000000000
--- a/pkg/kubernetes/scripts/fixture-basic.js
+++ /dev/null
@@ -1,233 +0,0 @@
-export const FIXTURE_BASIC = {
-    "nodes/127.0.0.1": {
-        "kind": "Node",
-        "metadata": {
-            "name": "127.0.0.1",
-            "uid": "f530580d-a169-11e4-8651-10c37bdb8410",
-            "creationTimestamp": "2015-01-21T13:35:18+01:00",
-            "resourceVersion": 1,
-        },
-        "spec": {
-            "capacity": {
-                "cpu": "1k",
-                "memory": "3Gi",
-            }
-        },
-        "status": {
-            "hostIP": "127.0.0.1",
-            "conditions": [
-                {
-                    "kind": "Ready",
-                    "status": "Full",
-                    "lastTransitionTime": null
-                }
-            ]
-        }
-    },
-    "namespaces/default/pods/database-1": {
-        "kind": "Pod",
-        "metadata": {
-            "name": "wordpress",
-            "resourceVersion": 5,
-            "uid": "0b547d64-ab8a-11e4-9a7c-080027300d85",
-            "namespace": "default",
-            "labels": {
-                "name": "wordpressreplica"
-            },
-        },
-        "spec": {
-            "volumes": null,
-            "containers": [
-                {
-                    "name": "slave",
-                    "image": "jbfink/wordpress",
-                    "ports": [
-                        {
-                            "hostPort": 81,
-                            "containerPort": 80,
-                            "protocol": "TCP"
-                        }
-                    ],
-                    "imagePullPolicy": "IfNotPresent"
-                }
-            ],
-            "restartPolicy": {
-                "always": {}
-            },
-            "dnsPolicy": "ClusterFirst",
-            "nodeName": "127.0.0.1"
-        },
-        "status": {
-            "phase": "Running",
-            "conditions": [
-                {
-                    "kind": "Ready",
-                    "status": "Full"
-                }
-            ],
-            "hostIP": "127.0.0.1",
-            "podIP": "172.17.4.173",
-            "info": {
-                "POD": {
-                    "state": {
-                        "running": {
-                            "startedAt": "2015-02-13T16:21:35Z"
-                        }
-                    },
-                    "ready": false,
-                    "restartCount": 0,
-                    "containerID": "docker://9031b6aef7829ec029955377bd53642760899d4eed37738830756d0ce092a01d",
-                    "podIP": "172.17.4.173",
-                    "image": "kubernetes/pause:0.8.0",
-                    "imageID": "docker://6c4579af347b649857e915521132f15a06186d73faa62145e3eeeb6be0e97c27"
-                },
-                "slave": {
-                    "state": {
-                        "running": {
-                            "startedAt": "2015-02-13T16:27:49Z"
-                        }
-                    },
-                    "ready": true,
-                    "restartCount": 0,
-                    "containerID": "docker://dc70bd24ecc7fd86a385d67bdbc2a60b219cf34fdd215f8f599c95ba93b1a82b",
-                    "image": "jbfink/wordpress",
-                    "imageID": "docker://0beee7f478c860c8444aa6a3966e1cb0cd574a01c874fc5dcc48585bd45dba52"
-                }
-            }
-        }
-    },
-    "namespaces/default/pods/apache": {
-        "kind": "Pod",
-        "metadata": {
-            "name": "apache",
-            "uid": "11768037-ab8a-11e4-9a7c-080027300d85",
-            "resourceVersion": 5,
-            "namespace": "default",
-            "labels": {
-                "name": "apache"
-            },
-        },
-        "spec": {
-            "volumes": null,
-            "containers": [
-                {
-                    "name": "slave",
-                    "image": "fedora/apache",
-                    "ports": [
-                        {
-                            "hostPort": 8084,
-                            "containerPort": 80,
-                            "protocol": "TCP"
-                        }
-                    ],
-                    "imagePullPolicy": "IfNotPresent"
-                }
-            ],
-            "restartPolicy": {
-                "always": {}
-            },
-            "dnsPolicy": "ClusterFirst"
-        },
-    },
-    "namespaces/other/pods/apache": {
-        "kind": "Pod",
-        "metadata": {
-            "name": "apache",
-            "uid": "9f1a316f-4db6-11e5-971a-525400e58104",
-            "resourceVersion": 5,
-            "namespace": "other",
-            "labels": {
-                "name": "apache"
-            },
-        },
-        "spec": {
-            "volumes": null,
-            "containers": [
-                {
-                    "name": "slave",
-                    "image": "fedora/apache",
-                    "ports": [
-                        {
-                            "hostPort": 8084,
-                            "containerPort": 80,
-                            "protocol": "TCP"
-                        }
-                    ],
-                    "imagePullPolicy": "IfNotPresent"
-                }
-            ],
-            "restartPolicy": {
-                "always": {}
-            },
-            "dnsPolicy": "ClusterFirst"
-        },
-    },
-    "namespaces/default/services/kubernetes": {
-        "kind": "Service",
-        "metadata": {
-            "name": "kubernetes",
-            "namespace": "default",
-            "uid": "9750385b-7fa4-11e4-91e3-10c37bdb8410",
-            "resourceVersion": "15",
-        },
-        "spec": {
-            "port": 443,
-            "protocol": "TCP",
-            "selector": {
-                "component": "apiserver",
-                "provider": "kubernetes"
-            },
-            "clusterIP": "10.254.224.238",
-            "containerPort": 0,
-            "sessionAffinity": "None"
-        },
-        "status": {}
-    },
-    "namespaces/default/services/kubernetes-ro": {
-        "kind": "Service",
-        "apiVersion": "v1",
-        "metadata": {
-            "name": "kubernetes-ro",
-            "namespace": "default",
-            "selfLink": "/api/v1/namespaces/default/services/kubernetes-ro",
-            "uid": "97504104-7fa4-11e4-91e3-10c37bdb8410",
-            "resourceVersion": "16",
-        },
-        "spec": {
-            "port": 80,
-            "protocol": "TCP",
-            "selector": {
-                "component": "apiserver",
-                "provider": "kubernetes"
-            },
-            "clusterIP": "10.254.117.100",
-            "containerPort": 0,
-            "sessionAffinity": "None"
-        },
-        "status": {}
-    },
-    "namespaces/default/imagestreams/mock-image-stream": {
-        "kind": "ImageStream",
-        "apiVersion": "v1",
-        "metadata": {
-            "name": "mock-image-stream",
-            "namespace":"default",
-            "uid":"c216455b-4cc5-11e5-8a7f-0e5582eacc27"
-        },
-        "spec": {
-            "dockerImageRepository": "mock/image",
-            "tags": [
-                {
-                    "name": "latest",
-                    "annotations": {
-                        "description": "Mock Image",
-                        "iconClass": "icon-mock",
-                        "tags": "builder,mock",
-                        "version": "3.0"
-                    }
-                }
-            ]
-        },
-        "status": {}
-    },
-};
diff --git a/pkg/kubernetes/scripts/fixture-large.js b/pkg/kubernetes/scripts/fixture-large.js
deleted file mode 100644
index 4e75c9b1b..000000000
--- a/pkg/kubernetes/scripts/fixture-large.js
+++ /dev/null
@@ -1,16041 +0,0 @@
-export const FIXTURE_LARGE = {
-    "namespaces/default/pods/mock-0": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-0",
-                "number": "0",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-0",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000000",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-1": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-1",
-                "number": "1",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-1",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000001",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-2": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-2",
-                "number": "2",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-2",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000002",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-3": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-3",
-                "number": "3",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-3",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000003",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-4": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-4",
-                "number": "4",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-4",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000004",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-5": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-5",
-                "number": "5",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-5",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000005",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-6": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-6",
-                "number": "6",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-6",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000006",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-7": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-7",
-                "number": "7",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-7",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000007",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-8": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-8",
-                "number": "8",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-8",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000008",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-9": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-9",
-                "number": "9",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-9",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000009",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-10": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-10",
-                "number": "10",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-10",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000010",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-11": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-11",
-                "number": "11",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-11",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000011",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-12": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-12",
-                "number": "12",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-12",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000012",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-13": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-13",
-                "number": "13",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-13",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000013",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-14": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-14",
-                "number": "14",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-14",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000014",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-15": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-15",
-                "number": "15",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-15",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000015",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-16": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-16",
-                "number": "16",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-16",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000016",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-17": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-17",
-                "number": "17",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-17",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000017",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-18": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-18",
-                "number": "18",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-18",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000018",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-19": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-19",
-                "number": "19",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-19",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000019",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-20": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-20",
-                "number": "20",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-20",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000020",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-21": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-21",
-                "number": "21",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-21",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000021",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-22": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-22",
-                "number": "22",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-22",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000022",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-23": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-23",
-                "number": "23",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-23",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000023",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-24": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-24",
-                "number": "24",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-24",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000024",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-25": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-25",
-                "number": "25",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-25",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000025",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-26": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-26",
-                "number": "26",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-26",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000026",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-27": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-27",
-                "number": "27",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-27",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000027",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-28": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-28",
-                "number": "28",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-28",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000028",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-29": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-29",
-                "number": "29",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-29",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000029",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-30": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-30",
-                "number": "30",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-30",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000030",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-31": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-31",
-                "number": "31",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-31",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000031",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-32": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-32",
-                "number": "32",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-32",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000032",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-33": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-33",
-                "number": "33",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-33",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000033",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-34": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-34",
-                "number": "34",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-34",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000034",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-35": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-35",
-                "number": "35",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-35",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000035",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-36": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-36",
-                "number": "36",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-36",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000036",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-37": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-37",
-                "number": "37",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-37",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000037",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-38": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-38",
-                "number": "38",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-38",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000038",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-39": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-39",
-                "number": "39",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-39",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000039",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-40": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-40",
-                "number": "40",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-40",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000040",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-41": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-41",
-                "number": "41",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-41",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000041",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-42": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-42",
-                "number": "42",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-42",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000042",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-43": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-43",
-                "number": "43",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-43",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000043",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-44": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-44",
-                "number": "44",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-44",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000044",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-45": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-45",
-                "number": "45",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-45",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000045",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-46": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-46",
-                "number": "46",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-46",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000046",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-47": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-47",
-                "number": "47",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-47",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000047",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-48": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-48",
-                "number": "48",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-48",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000048",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-49": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-49",
-                "number": "49",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-49",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000049",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-50": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-50",
-                "number": "50",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-50",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000050",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-51": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-51",
-                "number": "51",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-51",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000051",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-52": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-52",
-                "number": "52",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-52",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000052",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-53": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-53",
-                "number": "53",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-53",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000053",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-54": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-54",
-                "number": "54",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-54",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000054",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-55": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-55",
-                "number": "55",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-55",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000055",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-56": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-56",
-                "number": "56",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-56",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000056",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-57": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-57",
-                "number": "57",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-57",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000057",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-58": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-58",
-                "number": "58",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-58",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000058",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-59": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-59",
-                "number": "59",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-59",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000059",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-60": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-60",
-                "number": "60",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-60",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000060",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-61": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-61",
-                "number": "61",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-61",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000061",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-62": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-62",
-                "number": "62",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-62",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000062",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-63": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-63",
-                "number": "63",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-63",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000063",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-64": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-64",
-                "number": "64",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-64",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000064",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-65": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-65",
-                "number": "65",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-65",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000065",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-66": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-66",
-                "number": "66",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-66",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000066",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-67": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-67",
-                "number": "67",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-67",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000067",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-68": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-68",
-                "number": "68",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-68",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000068",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-69": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-69",
-                "number": "69",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-69",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000069",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-70": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-70",
-                "number": "70",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-70",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000070",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-71": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-71",
-                "number": "71",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-71",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000071",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-72": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-72",
-                "number": "72",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-72",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000072",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-73": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-73",
-                "number": "73",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-73",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000073",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-74": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-74",
-                "number": "74",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-74",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000074",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-75": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-75",
-                "number": "75",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-75",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000075",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-76": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-76",
-                "number": "76",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-76",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000076",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-77": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-77",
-                "number": "77",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-77",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000077",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-78": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-78",
-                "number": "78",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-78",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000078",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-79": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-79",
-                "number": "79",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-79",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000079",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-80": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-80",
-                "number": "80",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-80",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000080",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-81": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-81",
-                "number": "81",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-81",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000081",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-82": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-82",
-                "number": "82",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-82",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000082",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-83": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-83",
-                "number": "83",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-83",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000083",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-84": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-84",
-                "number": "84",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-84",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000084",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-85": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-85",
-                "number": "85",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-85",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000085",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-86": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-86",
-                "number": "86",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-86",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000086",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-87": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-87",
-                "number": "87",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-87",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000087",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-88": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-88",
-                "number": "88",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-88",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000088",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-89": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-89",
-                "number": "89",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-89",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000089",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-90": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-90",
-                "number": "90",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-90",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000090",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-91": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-91",
-                "number": "91",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-91",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000091",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-92": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-92",
-                "number": "92",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-92",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000092",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-93": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-93",
-                "number": "93",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-93",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000093",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-94": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-94",
-                "number": "94",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-94",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000094",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-95": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-95",
-                "number": "95",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-95",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000095",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-96": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-96",
-                "number": "96",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-96",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000096",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-97": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-97",
-                "number": "97",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-97",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000097",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-98": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-98",
-                "number": "98",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-98",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000098",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-99": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-99",
-                "number": "99",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-99",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000099",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-100": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-100",
-                "number": "100",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-100",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000100",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-101": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-101",
-                "number": "101",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-101",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000101",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-102": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-102",
-                "number": "102",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-102",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000102",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-103": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-103",
-                "number": "103",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-103",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000103",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-104": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-104",
-                "number": "104",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-104",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000104",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-105": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-105",
-                "number": "105",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-105",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000105",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-106": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-106",
-                "number": "106",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-106",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000106",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-107": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-107",
-                "number": "107",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-107",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000107",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-108": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-108",
-                "number": "108",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-108",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000108",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-109": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-109",
-                "number": "109",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-109",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000109",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-110": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-110",
-                "number": "110",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-110",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000110",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-111": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-111",
-                "number": "111",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-111",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000111",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-112": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-112",
-                "number": "112",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-112",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000112",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-113": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-113",
-                "number": "113",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-113",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000113",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-114": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-114",
-                "number": "114",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-114",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000114",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-115": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-115",
-                "number": "115",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-115",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000115",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-116": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-116",
-                "number": "116",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-116",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000116",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-117": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-117",
-                "number": "117",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-117",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000117",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-118": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-118",
-                "number": "118",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-118",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000118",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-119": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-119",
-                "number": "119",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-119",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000119",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-120": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-120",
-                "number": "120",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-120",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000120",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-121": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-121",
-                "number": "121",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-121",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000121",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-122": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-122",
-                "number": "122",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-122",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000122",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-123": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-123",
-                "number": "123",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-123",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000123",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-124": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-124",
-                "number": "124",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-124",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000124",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-125": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-125",
-                "number": "125",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-125",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000125",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-126": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-126",
-                "number": "126",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-126",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000126",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-127": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-127",
-                "number": "127",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-127",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000127",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-128": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-128",
-                "number": "128",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-128",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000128",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-129": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-129",
-                "number": "129",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-129",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000129",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-130": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-130",
-                "number": "130",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-130",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000130",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-131": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-131",
-                "number": "131",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-131",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000131",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-132": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-132",
-                "number": "132",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-132",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000132",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-133": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-133",
-                "number": "133",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-133",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000133",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-134": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-134",
-                "number": "134",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-134",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000134",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-135": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-135",
-                "number": "135",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-135",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000135",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-136": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-136",
-                "number": "136",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-136",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000136",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-137": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-137",
-                "number": "137",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-137",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000137",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-138": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-138",
-                "number": "138",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-138",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000138",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-139": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-139",
-                "number": "139",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-139",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000139",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-140": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-140",
-                "number": "140",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-140",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000140",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-141": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-141",
-                "number": "141",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-141",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000141",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-142": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-142",
-                "number": "142",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-142",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000142",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-143": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-143",
-                "number": "143",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-143",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000143",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-144": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-144",
-                "number": "144",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-144",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000144",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-145": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-145",
-                "number": "145",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-145",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000145",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-146": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-146",
-                "number": "146",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-146",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000146",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-147": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-147",
-                "number": "147",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-147",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000147",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-148": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-148",
-                "number": "148",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-148",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000148",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-149": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-149",
-                "number": "149",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-149",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000149",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-150": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-150",
-                "number": "150",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-150",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000150",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-151": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-151",
-                "number": "151",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-151",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000151",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-152": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-152",
-                "number": "152",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-152",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000152",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-153": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-153",
-                "number": "153",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-153",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000153",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-154": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-154",
-                "number": "154",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-154",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000154",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-155": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-155",
-                "number": "155",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-155",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000155",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-156": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-156",
-                "number": "156",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-156",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000156",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-157": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-157",
-                "number": "157",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-157",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000157",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-158": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-158",
-                "number": "158",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-158",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000158",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-159": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-159",
-                "number": "159",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-159",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000159",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-160": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-160",
-                "number": "160",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-160",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000160",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-161": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-161",
-                "number": "161",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-161",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000161",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-162": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-162",
-                "number": "162",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-162",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000162",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-163": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-163",
-                "number": "163",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-163",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000163",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-164": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-164",
-                "number": "164",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-164",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000164",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-165": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-165",
-                "number": "165",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-165",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000165",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-166": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-166",
-                "number": "166",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-166",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000166",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-167": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-167",
-                "number": "167",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-167",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000167",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-168": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-168",
-                "number": "168",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-168",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000168",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-169": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-169",
-                "number": "169",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-169",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000169",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-170": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-170",
-                "number": "170",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-170",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000170",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-171": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-171",
-                "number": "171",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-171",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000171",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-172": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-172",
-                "number": "172",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-172",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000172",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-173": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-173",
-                "number": "173",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-173",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000173",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-174": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-174",
-                "number": "174",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-174",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000174",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-175": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-175",
-                "number": "175",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-175",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000175",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-176": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-176",
-                "number": "176",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-176",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000176",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-177": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-177",
-                "number": "177",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-177",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000177",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-178": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-178",
-                "number": "178",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-178",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000178",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-179": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-179",
-                "number": "179",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-179",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000179",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-180": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-180",
-                "number": "180",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-180",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000180",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-181": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-181",
-                "number": "181",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-181",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000181",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-182": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-182",
-                "number": "182",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-182",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000182",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-183": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-183",
-                "number": "183",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-183",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000183",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-184": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-184",
-                "number": "184",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-184",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000184",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-185": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-185",
-                "number": "185",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-185",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000185",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-186": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-186",
-                "number": "186",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-186",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000186",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-187": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-187",
-                "number": "187",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-187",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000187",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-188": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-188",
-                "number": "188",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-188",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000188",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-189": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-189",
-                "number": "189",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-189",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000189",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-190": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-190",
-                "number": "190",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-190",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000190",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-191": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-191",
-                "number": "191",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-191",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000191",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-192": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-192",
-                "number": "192",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-192",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000192",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-193": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-193",
-                "number": "193",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-193",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000193",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-194": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-194",
-                "number": "194",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-194",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000194",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-195": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-195",
-                "number": "195",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-195",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000195",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-196": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-196",
-                "number": "196",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-196",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000196",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-197": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-197",
-                "number": "197",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-197",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000197",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-198": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-198",
-                "number": "198",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-198",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000198",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-199": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-199",
-                "number": "199",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-199",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000199",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-200": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-200",
-                "number": "200",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-200",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000200",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-201": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-201",
-                "number": "201",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-201",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000201",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-202": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-202",
-                "number": "202",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-202",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000202",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-203": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-203",
-                "number": "203",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-203",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000203",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-204": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-204",
-                "number": "204",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-204",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000204",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-205": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-205",
-                "number": "205",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-205",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000205",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-206": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-206",
-                "number": "206",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-206",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000206",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-207": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-207",
-                "number": "207",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-207",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000207",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-208": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-208",
-                "number": "208",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-208",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000208",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-209": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-209",
-                "number": "209",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-209",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000209",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-210": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-210",
-                "number": "210",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-210",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000210",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-211": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-211",
-                "number": "211",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-211",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000211",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-212": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-212",
-                "number": "212",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-212",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000212",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-213": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-213",
-                "number": "213",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-213",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000213",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-214": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-214",
-                "number": "214",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-214",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000214",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-215": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-215",
-                "number": "215",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-215",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000215",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-216": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-216",
-                "number": "216",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-216",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000216",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-217": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-217",
-                "number": "217",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-217",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000217",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-218": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-218",
-                "number": "218",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-218",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000218",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-219": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-219",
-                "number": "219",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-219",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000219",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-220": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-220",
-                "number": "220",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-220",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000220",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-221": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-221",
-                "number": "221",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-221",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000221",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-222": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-222",
-                "number": "222",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-222",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000222",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-223": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-223",
-                "number": "223",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-223",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000223",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-224": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-224",
-                "number": "224",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-224",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000224",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-225": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-225",
-                "number": "225",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-225",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000225",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-226": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-226",
-                "number": "226",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-226",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000226",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-227": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-227",
-                "number": "227",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-227",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000227",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-228": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-228",
-                "number": "228",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-228",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000228",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-229": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-229",
-                "number": "229",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-229",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000229",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-230": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-230",
-                "number": "230",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-230",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000230",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-231": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-231",
-                "number": "231",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-231",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000231",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-232": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-232",
-                "number": "232",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-232",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000232",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-233": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-233",
-                "number": "233",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-233",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000233",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-234": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-234",
-                "number": "234",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-234",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000234",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-235": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-235",
-                "number": "235",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-235",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000235",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-236": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-236",
-                "number": "236",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-236",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000236",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-237": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-237",
-                "number": "237",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-237",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000237",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-238": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-238",
-                "number": "238",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-238",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000238",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-239": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-239",
-                "number": "239",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-239",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000239",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-240": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-240",
-                "number": "240",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-240",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000240",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-241": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-241",
-                "number": "241",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-241",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000241",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-242": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-242",
-                "number": "242",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-242",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000242",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-243": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-243",
-                "number": "243",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-243",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000243",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-244": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-244",
-                "number": "244",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-244",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000244",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-245": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-245",
-                "number": "245",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-245",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000245",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-246": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-246",
-                "number": "246",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-246",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000246",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-247": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-247",
-                "number": "247",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-247",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000247",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-248": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-248",
-                "number": "248",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-248",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000248",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-249": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-249",
-                "number": "249",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-249",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000249",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-250": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-250",
-                "number": "250",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-250",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000250",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-251": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-251",
-                "number": "251",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-251",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000251",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-252": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-252",
-                "number": "252",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-252",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000252",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-253": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-253",
-                "number": "253",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-253",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000253",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-254": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-254",
-                "number": "254",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-254",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000254",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-255": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-255",
-                "number": "255",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-255",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000255",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-256": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-256",
-                "number": "256",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-256",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000256",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-257": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-257",
-                "number": "257",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-257",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000257",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-258": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-258",
-                "number": "258",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-258",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000258",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-259": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-259",
-                "number": "259",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-259",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000259",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-260": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-260",
-                "number": "260",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-260",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000260",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-261": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-261",
-                "number": "261",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-261",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000261",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-262": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-262",
-                "number": "262",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-262",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000262",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-263": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-263",
-                "number": "263",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-263",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000263",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-264": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-264",
-                "number": "264",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-264",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000264",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-265": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-265",
-                "number": "265",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-265",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000265",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-266": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-266",
-                "number": "266",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-266",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000266",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-267": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-267",
-                "number": "267",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-267",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000267",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-268": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-268",
-                "number": "268",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-268",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000268",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-269": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-269",
-                "number": "269",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-269",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000269",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-270": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-270",
-                "number": "270",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-270",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000270",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-271": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-271",
-                "number": "271",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-271",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000271",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-272": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-272",
-                "number": "272",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-272",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000272",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-273": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-273",
-                "number": "273",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-273",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000273",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-274": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-274",
-                "number": "274",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-274",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000274",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-275": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-275",
-                "number": "275",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-275",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000275",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-276": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-276",
-                "number": "276",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-276",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000276",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-277": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-277",
-                "number": "277",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-277",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000277",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-278": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-278",
-                "number": "278",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-278",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000278",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-279": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-279",
-                "number": "279",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-279",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000279",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-280": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-280",
-                "number": "280",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-280",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000280",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-281": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-281",
-                "number": "281",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-281",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000281",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-282": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-282",
-                "number": "282",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-282",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000282",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-283": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-283",
-                "number": "283",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-283",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000283",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-284": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-284",
-                "number": "284",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-284",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000284",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-285": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-285",
-                "number": "285",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-285",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000285",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-286": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-286",
-                "number": "286",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-286",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000286",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-287": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-287",
-                "number": "287",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-287",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000287",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-288": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-288",
-                "number": "288",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-288",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000288",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-289": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-289",
-                "number": "289",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-289",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000289",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-290": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-290",
-                "number": "290",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-290",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000290",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-291": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-291",
-                "number": "291",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-291",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000291",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-292": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-292",
-                "number": "292",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-292",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000292",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-293": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-293",
-                "number": "293",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-293",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000293",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-294": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-294",
-                "number": "294",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-294",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000294",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-295": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-295",
-                "number": "295",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-295",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000295",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-296": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-296",
-                "number": "296",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-296",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000296",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-297": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-297",
-                "number": "297",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-297",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000297",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-298": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-298",
-                "number": "298",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-298",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000298",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-299": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-299",
-                "number": "299",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-299",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000299",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-300": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-300",
-                "number": "300",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-300",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000300",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-301": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-301",
-                "number": "301",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-301",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000301",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-302": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-302",
-                "number": "302",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-302",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000302",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-303": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-303",
-                "number": "303",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-303",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000303",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-304": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-304",
-                "number": "304",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-304",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000304",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-305": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-305",
-                "number": "305",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-305",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000305",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-306": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-306",
-                "number": "306",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-306",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000306",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-307": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-307",
-                "number": "307",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-307",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000307",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-308": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-308",
-                "number": "308",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-308",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000308",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-309": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-309",
-                "number": "309",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-309",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000309",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-310": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-310",
-                "number": "310",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-310",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000310",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-311": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-311",
-                "number": "311",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-311",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000311",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-312": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-312",
-                "number": "312",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-312",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000312",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-313": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-313",
-                "number": "313",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-313",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000313",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-314": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-314",
-                "number": "314",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-314",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000314",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-315": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-315",
-                "number": "315",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-315",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000315",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-316": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-316",
-                "number": "316",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-316",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000316",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-317": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-317",
-                "number": "317",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-317",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000317",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-318": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-318",
-                "number": "318",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-318",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000318",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-319": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-319",
-                "number": "319",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-319",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000319",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-320": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-320",
-                "number": "320",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-320",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000320",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-321": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-321",
-                "number": "321",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-321",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000321",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-322": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-322",
-                "number": "322",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-322",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000322",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-323": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-323",
-                "number": "323",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-323",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000323",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-324": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-324",
-                "number": "324",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-324",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000324",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-325": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-325",
-                "number": "325",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-325",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000325",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-326": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-326",
-                "number": "326",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-326",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000326",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-327": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-327",
-                "number": "327",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-327",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000327",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-328": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-328",
-                "number": "328",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-328",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000328",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-329": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-329",
-                "number": "329",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-329",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000329",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-330": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-330",
-                "number": "330",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-330",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000330",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-331": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-331",
-                "number": "331",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-331",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000331",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-332": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-332",
-                "number": "332",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-332",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000332",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-333": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-333",
-                "number": "333",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-333",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000333",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-334": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-334",
-                "number": "334",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-334",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000334",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-335": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-335",
-                "number": "335",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-335",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000335",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-336": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-336",
-                "number": "336",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-336",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000336",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-337": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-337",
-                "number": "337",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-337",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000337",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-338": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-338",
-                "number": "338",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-338",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000338",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-339": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-339",
-                "number": "339",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-339",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000339",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-340": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-340",
-                "number": "340",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-340",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000340",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-341": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-341",
-                "number": "341",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-341",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000341",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-342": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-342",
-                "number": "342",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-342",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000342",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-343": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-343",
-                "number": "343",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-343",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000343",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-344": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-344",
-                "number": "344",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-344",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000344",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-345": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-345",
-                "number": "345",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-345",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000345",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-346": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-346",
-                "number": "346",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-346",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000346",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-347": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-347",
-                "number": "347",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-347",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000347",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-348": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-348",
-                "number": "348",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-348",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000348",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-349": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-349",
-                "number": "349",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-349",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000349",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-350": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-350",
-                "number": "350",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-350",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000350",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-351": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-351",
-                "number": "351",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-351",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000351",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-352": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-352",
-                "number": "352",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-352",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000352",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-353": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-353",
-                "number": "353",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-353",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000353",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-354": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-354",
-                "number": "354",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-354",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000354",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-355": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-355",
-                "number": "355",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-355",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000355",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-356": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-356",
-                "number": "356",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-356",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000356",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-357": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-357",
-                "number": "357",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-357",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000357",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-358": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-358",
-                "number": "358",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-358",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000358",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-359": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-359",
-                "number": "359",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-359",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000359",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-360": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-360",
-                "number": "360",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-360",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000360",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-361": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-361",
-                "number": "361",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-361",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000361",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-362": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-362",
-                "number": "362",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-362",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000362",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-363": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-363",
-                "number": "363",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-363",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000363",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-364": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-364",
-                "number": "364",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-364",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000364",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-365": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-365",
-                "number": "365",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-365",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000365",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-366": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-366",
-                "number": "366",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-366",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000366",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-367": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-367",
-                "number": "367",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-367",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000367",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-368": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-368",
-                "number": "368",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-368",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000368",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-369": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-369",
-                "number": "369",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-369",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000369",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-370": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-370",
-                "number": "370",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-370",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000370",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-371": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-371",
-                "number": "371",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-371",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000371",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-372": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-372",
-                "number": "372",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-372",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000372",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-373": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-373",
-                "number": "373",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-373",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000373",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-374": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-374",
-                "number": "374",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-374",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000374",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-375": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-375",
-                "number": "375",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-375",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000375",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-376": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-376",
-                "number": "376",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-376",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000376",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-377": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-377",
-                "number": "377",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-377",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000377",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-378": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-378",
-                "number": "378",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-378",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000378",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-379": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-379",
-                "number": "379",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-379",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000379",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-380": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-380",
-                "number": "380",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-380",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000380",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-381": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-381",
-                "number": "381",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-381",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000381",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-382": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-382",
-                "number": "382",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-382",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000382",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-383": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-383",
-                "number": "383",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-383",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000383",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-384": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-384",
-                "number": "384",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-384",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000384",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-385": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-385",
-                "number": "385",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-385",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000385",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-386": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-386",
-                "number": "386",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-386",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000386",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-387": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-387",
-                "number": "387",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-387",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000387",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-388": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-388",
-                "number": "388",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-388",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000388",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-389": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-389",
-                "number": "389",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-389",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000389",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-390": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-390",
-                "number": "390",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-390",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000390",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-391": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-391",
-                "number": "391",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-391",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000391",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-392": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-392",
-                "number": "392",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-392",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000392",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-393": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-393",
-                "number": "393",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-393",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000393",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-394": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-394",
-                "number": "394",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-394",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000394",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-395": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-395",
-                "number": "395",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-395",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000395",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-396": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-396",
-                "number": "396",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-396",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000396",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-397": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-397",
-                "number": "397",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-397",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000397",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-398": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-398",
-                "number": "398",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-398",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000398",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-399": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-399",
-                "number": "399",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-399",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000399",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-400": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-400",
-                "number": "400",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-400",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000400",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-401": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-401",
-                "number": "401",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-401",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000401",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-402": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-402",
-                "number": "402",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-402",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000402",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-403": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-403",
-                "number": "403",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-403",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000403",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-404": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-404",
-                "number": "404",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-404",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000404",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-405": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-405",
-                "number": "405",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-405",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000405",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-406": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-406",
-                "number": "406",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-406",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000406",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-407": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-407",
-                "number": "407",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-407",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000407",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-408": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-408",
-                "number": "408",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-408",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000408",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-409": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-409",
-                "number": "409",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-409",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000409",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-410": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-410",
-                "number": "410",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-410",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000410",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-411": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-411",
-                "number": "411",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-411",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000411",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-412": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-412",
-                "number": "412",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-412",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000412",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-413": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-413",
-                "number": "413",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-413",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000413",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-414": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-414",
-                "number": "414",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-414",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000414",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-415": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-415",
-                "number": "415",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-415",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000415",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-416": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-416",
-                "number": "416",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-416",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000416",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-417": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-417",
-                "number": "417",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-417",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000417",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-418": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-418",
-                "number": "418",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-418",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000418",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-419": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-419",
-                "number": "419",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-419",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000419",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-420": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-420",
-                "number": "420",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-420",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000420",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-421": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-421",
-                "number": "421",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-421",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000421",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-422": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-422",
-                "number": "422",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-422",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000422",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-423": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-423",
-                "number": "423",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-423",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000423",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-424": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-424",
-                "number": "424",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-424",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000424",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-425": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-425",
-                "number": "425",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-425",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000425",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-426": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-426",
-                "number": "426",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-426",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000426",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-427": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-427",
-                "number": "427",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-427",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000427",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-428": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-428",
-                "number": "428",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-428",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000428",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-429": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-429",
-                "number": "429",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-429",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000429",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-430": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-430",
-                "number": "430",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-430",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000430",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-431": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-431",
-                "number": "431",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-431",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000431",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-432": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-432",
-                "number": "432",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-432",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000432",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-433": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-433",
-                "number": "433",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-433",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000433",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-434": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-434",
-                "number": "434",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-434",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000434",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-435": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-435",
-                "number": "435",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-435",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000435",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-436": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-436",
-                "number": "436",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-436",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000436",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-437": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-437",
-                "number": "437",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-437",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000437",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-438": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-438",
-                "number": "438",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-438",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000438",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-439": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-439",
-                "number": "439",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-439",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000439",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-440": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-440",
-                "number": "440",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-440",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000440",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-441": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-441",
-                "number": "441",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-441",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000441",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-442": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-442",
-                "number": "442",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-442",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000442",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-443": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-443",
-                "number": "443",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-443",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000443",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-444": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-444",
-                "number": "444",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-444",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000444",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-445": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-445",
-                "number": "445",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-445",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000445",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-446": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-446",
-                "number": "446",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-446",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000446",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-447": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-447",
-                "number": "447",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-447",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000447",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-448": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-448",
-                "number": "448",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-448",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000448",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-449": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-449",
-                "number": "449",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-449",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000449",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-450": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-450",
-                "number": "450",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-450",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000450",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-451": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-451",
-                "number": "451",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-451",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000451",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-452": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-452",
-                "number": "452",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-452",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000452",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-453": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-453",
-                "number": "453",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-453",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000453",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-454": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-454",
-                "number": "454",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-454",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000454",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-455": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-455",
-                "number": "455",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-455",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000455",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-456": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-456",
-                "number": "456",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-456",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000456",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-457": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-457",
-                "number": "457",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-457",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000457",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-458": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-458",
-                "number": "458",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-458",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000458",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-459": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-459",
-                "number": "459",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-459",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000459",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-460": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-460",
-                "number": "460",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-460",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000460",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-461": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-461",
-                "number": "461",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-461",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000461",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-462": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-462",
-                "number": "462",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-462",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000462",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-463": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-463",
-                "number": "463",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-463",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000463",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-464": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-464",
-                "number": "464",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-464",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000464",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-465": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-465",
-                "number": "465",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-465",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000465",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-466": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-466",
-                "number": "466",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-466",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000466",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-467": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-467",
-                "number": "467",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-467",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000467",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-468": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-468",
-                "number": "468",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-468",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000468",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-469": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-469",
-                "number": "469",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-469",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000469",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-470": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-470",
-                "number": "470",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-470",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000470",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-471": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-471",
-                "number": "471",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-471",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000471",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-472": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-472",
-                "number": "472",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-472",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000472",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-473": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-473",
-                "number": "473",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-473",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000473",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-474": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-474",
-                "number": "474",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-474",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000474",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-475": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-475",
-                "number": "475",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-475",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000475",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-476": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-476",
-                "number": "476",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-476",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000476",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-477": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-477",
-                "number": "477",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-477",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000477",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-478": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-478",
-                "number": "478",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-478",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000478",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-479": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-479",
-                "number": "479",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-479",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000479",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-480": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-480",
-                "number": "480",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-480",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000480",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-481": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-481",
-                "number": "481",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-481",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000481",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-482": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-482",
-                "number": "482",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-482",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000482",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-483": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-483",
-                "number": "483",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-483",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000483",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-484": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-484",
-                "number": "484",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-484",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000484",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-485": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-485",
-                "number": "485",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-485",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000485",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-486": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-486",
-                "number": "486",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-486",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000486",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-487": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-487",
-                "number": "487",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-487",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000487",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-488": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-488",
-                "number": "488",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-488",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000488",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-489": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-489",
-                "number": "489",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-489",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000489",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-490": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-490",
-                "number": "490",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-490",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000490",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-491": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-491",
-                "number": "491",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-491",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000491",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-492": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-492",
-                "number": "492",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-492",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000492",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-493": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-493",
-                "number": "493",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-493",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000493",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-494": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-494",
-                "number": "494",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-494",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000494",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-495": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-495",
-                "number": "495",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-495",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000495",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-496": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-496",
-                "number": "496",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-496",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000496",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-497": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-497",
-                "number": "497",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-497",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000497",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-498": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-498",
-                "number": "498",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-498",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000498",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-499": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-499",
-                "number": "499",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-499",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000499",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-500": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-500",
-                "number": "500",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-500",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000500",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-501": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-501",
-                "number": "501",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-501",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000501",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-502": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-502",
-                "number": "502",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-502",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000502",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-503": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-503",
-                "number": "503",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-503",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000503",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-504": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-504",
-                "number": "504",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-504",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000504",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-505": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-505",
-                "number": "505",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-505",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000505",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-506": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-506",
-                "number": "506",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-506",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000506",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-507": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-507",
-                "number": "507",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-507",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000507",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-508": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-508",
-                "number": "508",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-508",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000508",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-509": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-509",
-                "number": "509",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-509",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000509",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-510": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-510",
-                "number": "510",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-510",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000510",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-511": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-511",
-                "number": "511",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-511",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000511",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-512": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-512",
-                "number": "512",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-512",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000512",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-513": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-513",
-                "number": "513",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-513",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000513",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-514": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-514",
-                "number": "514",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-514",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000514",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-515": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-515",
-                "number": "515",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-515",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000515",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-516": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-516",
-                "number": "516",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-516",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000516",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-517": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-517",
-                "number": "517",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-517",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000517",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-518": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-518",
-                "number": "518",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-518",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000518",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-519": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-519",
-                "number": "519",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-519",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000519",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-520": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-520",
-                "number": "520",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-520",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000520",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-521": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-521",
-                "number": "521",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-521",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000521",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-522": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-522",
-                "number": "522",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-522",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000522",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-523": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-523",
-                "number": "523",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-523",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000523",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-524": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-524",
-                "number": "524",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-524",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000524",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-525": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-525",
-                "number": "525",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-525",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000525",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-526": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-526",
-                "number": "526",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-526",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000526",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-527": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-527",
-                "number": "527",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-527",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000527",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-528": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-528",
-                "number": "528",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-528",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000528",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-529": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-529",
-                "number": "529",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-529",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000529",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-530": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-530",
-                "number": "530",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-530",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000530",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-531": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-531",
-                "number": "531",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-531",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000531",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-532": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-532",
-                "number": "532",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-532",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000532",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-533": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-533",
-                "number": "533",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-533",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000533",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-534": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-534",
-                "number": "534",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-534",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000534",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-535": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-535",
-                "number": "535",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-535",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000535",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-536": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-536",
-                "number": "536",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-536",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000536",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-537": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-537",
-                "number": "537",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-537",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000537",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-538": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-538",
-                "number": "538",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-538",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000538",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-539": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-539",
-                "number": "539",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-539",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000539",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-540": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-540",
-                "number": "540",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-540",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000540",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-541": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-541",
-                "number": "541",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-541",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000541",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-542": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-542",
-                "number": "542",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-542",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000542",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-543": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-543",
-                "number": "543",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-543",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000543",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-544": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-544",
-                "number": "544",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-544",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000544",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-545": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-545",
-                "number": "545",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-545",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000545",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-546": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-546",
-                "number": "546",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-546",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000546",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-547": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-547",
-                "number": "547",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-547",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000547",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-548": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-548",
-                "number": "548",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-548",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000548",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-549": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-549",
-                "number": "549",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-549",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000549",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-550": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-550",
-                "number": "550",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-550",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000550",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-551": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-551",
-                "number": "551",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-551",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000551",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-552": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-552",
-                "number": "552",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-552",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000552",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-553": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-553",
-                "number": "553",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-553",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000553",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-554": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-554",
-                "number": "554",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-554",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000554",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-555": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-555",
-                "number": "555",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-555",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000555",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-556": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-556",
-                "number": "556",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-556",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000556",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-557": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-557",
-                "number": "557",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-557",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000557",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-558": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-558",
-                "number": "558",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-558",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000558",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-559": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-559",
-                "number": "559",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-559",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000559",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-560": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-560",
-                "number": "560",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-560",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000560",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-561": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-561",
-                "number": "561",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-561",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000561",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-562": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-562",
-                "number": "562",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-562",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000562",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-563": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-563",
-                "number": "563",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-563",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000563",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-564": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-564",
-                "number": "564",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-564",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000564",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-565": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-565",
-                "number": "565",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-565",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000565",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-566": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-566",
-                "number": "566",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-566",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000566",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-567": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-567",
-                "number": "567",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-567",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000567",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-568": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-568",
-                "number": "568",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-568",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000568",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-569": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-569",
-                "number": "569",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-569",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000569",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-570": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-570",
-                "number": "570",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-570",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000570",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-571": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-571",
-                "number": "571",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-571",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000571",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-572": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-572",
-                "number": "572",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-572",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000572",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-573": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-573",
-                "number": "573",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-573",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000573",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-574": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-574",
-                "number": "574",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-574",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000574",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-575": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-575",
-                "number": "575",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-575",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000575",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-576": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-576",
-                "number": "576",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-576",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000576",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-577": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-577",
-                "number": "577",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-577",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000577",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-578": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-578",
-                "number": "578",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-578",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000578",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-579": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-579",
-                "number": "579",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-579",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000579",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-580": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-580",
-                "number": "580",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-580",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000580",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-581": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-581",
-                "number": "581",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-581",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000581",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-582": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-582",
-                "number": "582",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-582",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000582",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-583": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-583",
-                "number": "583",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-583",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000583",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-584": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-584",
-                "number": "584",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-584",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000584",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-585": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-585",
-                "number": "585",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-585",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000585",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-586": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-586",
-                "number": "586",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-586",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000586",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-587": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-587",
-                "number": "587",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-587",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000587",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-588": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-588",
-                "number": "588",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-588",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000588",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-589": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-589",
-                "number": "589",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-589",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000589",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-590": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-590",
-                "number": "590",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-590",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000590",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-591": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-591",
-                "number": "591",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-591",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000591",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-592": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-592",
-                "number": "592",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-592",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000592",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-593": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-593",
-                "number": "593",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-593",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000593",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-594": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-594",
-                "number": "594",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-594",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000594",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-595": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-595",
-                "number": "595",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-595",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000595",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-596": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-596",
-                "number": "596",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-596",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000596",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-597": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-597",
-                "number": "597",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-597",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000597",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-598": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-598",
-                "number": "598",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-598",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000598",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-599": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-599",
-                "number": "599",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-599",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000599",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-600": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-600",
-                "number": "600",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-600",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000600",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-601": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-601",
-                "number": "601",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-601",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000601",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-602": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-602",
-                "number": "602",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-602",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000602",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-603": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-603",
-                "number": "603",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-603",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000603",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-604": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-604",
-                "number": "604",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-604",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000604",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-605": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-605",
-                "number": "605",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-605",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000605",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-606": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-606",
-                "number": "606",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-606",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000606",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-607": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-607",
-                "number": "607",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-607",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000607",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-608": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-608",
-                "number": "608",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-608",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000608",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-609": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-609",
-                "number": "609",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-609",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000609",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-610": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-610",
-                "number": "610",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-610",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000610",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-611": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-611",
-                "number": "611",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-611",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000611",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-612": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-612",
-                "number": "612",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-612",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000612",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-613": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-613",
-                "number": "613",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-613",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000613",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-614": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-614",
-                "number": "614",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-614",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000614",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-615": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-615",
-                "number": "615",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-615",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000615",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-616": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-616",
-                "number": "616",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-616",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000616",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-617": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-617",
-                "number": "617",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-617",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000617",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-618": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-618",
-                "number": "618",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-618",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000618",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-619": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-619",
-                "number": "619",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-619",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000619",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-620": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-620",
-                "number": "620",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-620",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000620",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-621": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-621",
-                "number": "621",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-621",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000621",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-622": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-622",
-                "number": "622",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-622",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000622",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-623": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-623",
-                "number": "623",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-623",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000623",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-624": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-624",
-                "number": "624",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-624",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000624",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-625": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-625",
-                "number": "625",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-625",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000625",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-626": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-626",
-                "number": "626",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-626",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000626",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-627": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-627",
-                "number": "627",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-627",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000627",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-628": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-628",
-                "number": "628",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-628",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000628",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-629": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-629",
-                "number": "629",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-629",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000629",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-630": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-630",
-                "number": "630",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-630",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000630",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-631": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-631",
-                "number": "631",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-631",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000631",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-632": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-632",
-                "number": "632",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-632",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000632",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-633": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-633",
-                "number": "633",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-633",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000633",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-634": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-634",
-                "number": "634",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-634",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000634",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-635": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-635",
-                "number": "635",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-635",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000635",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-636": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-636",
-                "number": "636",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-636",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000636",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-637": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-637",
-                "number": "637",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-637",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000637",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-638": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-638",
-                "number": "638",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-638",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000638",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-639": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-639",
-                "number": "639",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-639",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000639",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-640": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-640",
-                "number": "640",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-640",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000640",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-641": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-641",
-                "number": "641",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-641",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000641",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-642": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-642",
-                "number": "642",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-642",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000642",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-643": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-643",
-                "number": "643",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-643",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000643",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-644": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-644",
-                "number": "644",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-644",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000644",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-645": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-645",
-                "number": "645",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-645",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000645",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-646": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-646",
-                "number": "646",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-646",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000646",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-647": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-647",
-                "number": "647",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-647",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000647",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-648": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-648",
-                "number": "648",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-648",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000648",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-649": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-649",
-                "number": "649",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-649",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000649",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-650": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-650",
-                "number": "650",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-650",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000650",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-651": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-651",
-                "number": "651",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-651",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000651",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-652": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-652",
-                "number": "652",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-652",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000652",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-653": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-653",
-                "number": "653",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-653",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000653",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-654": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-654",
-                "number": "654",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-654",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000654",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-655": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-655",
-                "number": "655",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-655",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000655",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-656": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-656",
-                "number": "656",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-656",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000656",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-657": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-657",
-                "number": "657",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-657",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000657",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-658": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-658",
-                "number": "658",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-658",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000658",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-659": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-659",
-                "number": "659",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-659",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000659",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-660": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-660",
-                "number": "660",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-660",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000660",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-661": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-661",
-                "number": "661",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-661",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000661",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-662": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-662",
-                "number": "662",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-662",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000662",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-663": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-663",
-                "number": "663",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-663",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000663",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-664": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-664",
-                "number": "664",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-664",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000664",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-665": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-665",
-                "number": "665",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-665",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000665",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-666": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-666",
-                "number": "666",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-666",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000666",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-667": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-667",
-                "number": "667",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-667",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000667",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-668": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-668",
-                "number": "668",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-668",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000668",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-669": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-669",
-                "number": "669",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-669",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000669",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-670": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-670",
-                "number": "670",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-670",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000670",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-671": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-671",
-                "number": "671",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-671",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000671",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-672": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-672",
-                "number": "672",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-672",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000672",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-673": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-673",
-                "number": "673",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-673",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000673",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-674": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-674",
-                "number": "674",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-674",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000674",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-675": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-675",
-                "number": "675",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-675",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000675",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-676": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-676",
-                "number": "676",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-676",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000676",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-677": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-677",
-                "number": "677",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-677",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000677",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-678": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-678",
-                "number": "678",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-678",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000678",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-679": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-679",
-                "number": "679",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-679",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000679",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-680": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-680",
-                "number": "680",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-680",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000680",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-681": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-681",
-                "number": "681",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-681",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000681",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-682": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-682",
-                "number": "682",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-682",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000682",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-683": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-683",
-                "number": "683",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-683",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000683",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-684": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-684",
-                "number": "684",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-684",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000684",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-685": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-685",
-                "number": "685",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-685",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000685",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-686": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-686",
-                "number": "686",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-686",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000686",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-687": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-687",
-                "number": "687",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-687",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000687",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-688": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-688",
-                "number": "688",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-688",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000688",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-689": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-689",
-                "number": "689",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-689",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000689",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-690": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-690",
-                "number": "690",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-690",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000690",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-691": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-691",
-                "number": "691",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-691",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000691",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-692": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-692",
-                "number": "692",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-692",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000692",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-693": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-693",
-                "number": "693",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-693",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000693",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-694": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-694",
-                "number": "694",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-694",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000694",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-695": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-695",
-                "number": "695",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-695",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000695",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-696": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-696",
-                "number": "696",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-696",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000696",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-697": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-697",
-                "number": "697",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-697",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000697",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-698": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-698",
-                "number": "698",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-698",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000698",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-699": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-699",
-                "number": "699",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-699",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000699",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-700": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-700",
-                "number": "700",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-700",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000700",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-701": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-701",
-                "number": "701",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-701",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000701",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-702": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-702",
-                "number": "702",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-702",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000702",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-703": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-703",
-                "number": "703",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-703",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000703",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-704": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-704",
-                "number": "704",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-704",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000704",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-705": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-705",
-                "number": "705",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-705",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000705",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-706": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-706",
-                "number": "706",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-706",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000706",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-707": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-707",
-                "number": "707",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-707",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000707",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-708": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-708",
-                "number": "708",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-708",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000708",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-709": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-709",
-                "number": "709",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-709",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000709",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-710": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-710",
-                "number": "710",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-710",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000710",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-711": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-711",
-                "number": "711",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-711",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000711",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-712": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-712",
-                "number": "712",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-712",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000712",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-713": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-713",
-                "number": "713",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-713",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000713",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-714": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-714",
-                "number": "714",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-714",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000714",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-715": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-715",
-                "number": "715",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-715",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000715",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-716": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-716",
-                "number": "716",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-716",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000716",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-717": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-717",
-                "number": "717",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-717",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000717",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-718": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-718",
-                "number": "718",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-718",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000718",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-719": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-719",
-                "number": "719",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-719",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000719",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-720": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-720",
-                "number": "720",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-720",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000720",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-721": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-721",
-                "number": "721",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-721",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000721",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-722": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-722",
-                "number": "722",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-722",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000722",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-723": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-723",
-                "number": "723",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-723",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000723",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-724": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-724",
-                "number": "724",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-724",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000724",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-725": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-725",
-                "number": "725",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-725",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000725",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-726": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-726",
-                "number": "726",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-726",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000726",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-727": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-727",
-                "number": "727",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-727",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000727",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-728": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-728",
-                "number": "728",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-728",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000728",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-729": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-729",
-                "number": "729",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-729",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000729",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-730": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-730",
-                "number": "730",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-730",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000730",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-731": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-731",
-                "number": "731",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-731",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000731",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-732": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-732",
-                "number": "732",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-732",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000732",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-733": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-733",
-                "number": "733",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-733",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000733",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-734": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-734",
-                "number": "734",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-734",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000734",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-735": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-735",
-                "number": "735",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-735",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000735",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-736": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-736",
-                "number": "736",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-736",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000736",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-737": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-737",
-                "number": "737",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-737",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000737",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-738": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-738",
-                "number": "738",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-738",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000738",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-739": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-739",
-                "number": "739",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-739",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000739",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-740": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-740",
-                "number": "740",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-740",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000740",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-741": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-741",
-                "number": "741",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-741",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000741",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-742": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-742",
-                "number": "742",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-742",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000742",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-743": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-743",
-                "number": "743",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-743",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000743",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-744": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-744",
-                "number": "744",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-744",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000744",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-745": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-745",
-                "number": "745",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-745",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000745",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-746": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-746",
-                "number": "746",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-746",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000746",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-747": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-747",
-                "number": "747",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-747",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000747",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-748": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-748",
-                "number": "748",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-748",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000748",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-749": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-749",
-                "number": "749",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-749",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000749",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-750": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-750",
-                "number": "750",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-750",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000750",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-751": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-751",
-                "number": "751",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-751",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000751",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-752": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-752",
-                "number": "752",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-752",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000752",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-753": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-753",
-                "number": "753",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-753",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000753",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-754": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-754",
-                "number": "754",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-754",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000754",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-755": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-755",
-                "number": "755",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-755",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000755",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-756": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-756",
-                "number": "756",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-756",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000756",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-757": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-757",
-                "number": "757",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-757",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000757",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-758": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-758",
-                "number": "758",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-758",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000758",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-759": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-759",
-                "number": "759",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-759",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000759",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-760": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-760",
-                "number": "760",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-760",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000760",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-761": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-761",
-                "number": "761",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-761",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000761",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-762": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-762",
-                "number": "762",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-762",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000762",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-763": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-763",
-                "number": "763",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-763",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000763",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-764": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-764",
-                "number": "764",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-764",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000764",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-765": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-765",
-                "number": "765",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-765",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000765",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-766": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-766",
-                "number": "766",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-766",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000766",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-767": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-767",
-                "number": "767",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-767",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000767",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-768": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-768",
-                "number": "768",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-768",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000768",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-769": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-769",
-                "number": "769",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-769",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000769",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-770": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-770",
-                "number": "770",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-770",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000770",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-771": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-771",
-                "number": "771",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-771",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000771",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-772": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-772",
-                "number": "772",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-772",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000772",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-773": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-773",
-                "number": "773",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-773",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000773",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-774": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-774",
-                "number": "774",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-774",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000774",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-775": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-775",
-                "number": "775",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-775",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000775",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-776": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-776",
-                "number": "776",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-776",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000776",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-777": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-777",
-                "number": "777",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-777",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000777",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-778": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-778",
-                "number": "778",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-778",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000778",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-779": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-779",
-                "number": "779",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-779",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000779",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-780": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-780",
-                "number": "780",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-780",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000780",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-781": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-781",
-                "number": "781",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-781",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000781",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-782": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-782",
-                "number": "782",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-782",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000782",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-783": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-783",
-                "number": "783",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-783",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000783",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-784": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-784",
-                "number": "784",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-784",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000784",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-785": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-785",
-                "number": "785",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-785",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000785",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-786": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-786",
-                "number": "786",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-786",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000786",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-787": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-787",
-                "number": "787",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-787",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000787",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-788": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-788",
-                "number": "788",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-788",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000788",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-789": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-789",
-                "number": "789",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-789",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000789",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-790": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-790",
-                "number": "790",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-790",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000790",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-791": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-791",
-                "number": "791",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-791",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000791",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-792": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-792",
-                "number": "792",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-792",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000792",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-793": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-793",
-                "number": "793",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-793",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000793",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-794": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-794",
-                "number": "794",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-794",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000794",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-795": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-795",
-                "number": "795",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-795",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000795",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-796": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-796",
-                "number": "796",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-796",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000796",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-797": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-797",
-                "number": "797",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-797",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000797",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-798": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-798",
-                "number": "798",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-798",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000798",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-799": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-799",
-                "number": "799",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-799",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000799",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-800": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-800",
-                "number": "800",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-800",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000800",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-801": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-801",
-                "number": "801",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-801",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000801",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-802": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-802",
-                "number": "802",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-802",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000802",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-803": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-803",
-                "number": "803",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-803",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000803",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-804": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-804",
-                "number": "804",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-804",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000804",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-805": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-805",
-                "number": "805",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-805",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000805",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-806": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-806",
-                "number": "806",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-806",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000806",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-807": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-807",
-                "number": "807",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-807",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000807",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-808": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-808",
-                "number": "808",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-808",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000808",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-809": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-809",
-                "number": "809",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-809",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000809",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-810": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-810",
-                "number": "810",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-810",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000810",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-811": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-811",
-                "number": "811",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-811",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000811",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-812": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-812",
-                "number": "812",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-812",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000812",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-813": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-813",
-                "number": "813",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-813",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000813",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-814": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-814",
-                "number": "814",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-814",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000814",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-815": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-815",
-                "number": "815",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-815",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000815",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-816": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-816",
-                "number": "816",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-816",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000816",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-817": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-817",
-                "number": "817",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-817",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000817",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-818": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-818",
-                "number": "818",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-818",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000818",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-819": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-819",
-                "number": "819",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-819",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000819",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-820": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-820",
-                "number": "820",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-820",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000820",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-821": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-821",
-                "number": "821",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-821",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000821",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-822": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-822",
-                "number": "822",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-822",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000822",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-823": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-823",
-                "number": "823",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-823",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000823",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-824": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-824",
-                "number": "824",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-824",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000824",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-825": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-825",
-                "number": "825",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-825",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000825",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-826": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-826",
-                "number": "826",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-826",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000826",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-827": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-827",
-                "number": "827",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-827",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000827",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-828": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-828",
-                "number": "828",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-828",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000828",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-829": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-829",
-                "number": "829",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-829",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000829",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-830": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-830",
-                "number": "830",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-830",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000830",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-831": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-831",
-                "number": "831",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-831",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000831",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-832": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-832",
-                "number": "832",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-832",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000832",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-833": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-833",
-                "number": "833",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-833",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000833",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-834": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-834",
-                "number": "834",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-834",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000834",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-835": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-835",
-                "number": "835",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-835",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000835",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-836": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-836",
-                "number": "836",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-836",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000836",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-837": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-837",
-                "number": "837",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-837",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000837",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-838": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-838",
-                "number": "838",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-838",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000838",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-839": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-839",
-                "number": "839",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-839",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000839",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-840": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-840",
-                "number": "840",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-840",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000840",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-841": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-841",
-                "number": "841",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-841",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000841",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-842": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-842",
-                "number": "842",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-842",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000842",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-843": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-843",
-                "number": "843",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-843",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000843",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-844": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-844",
-                "number": "844",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-844",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000844",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-845": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-845",
-                "number": "845",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-845",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000845",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-846": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-846",
-                "number": "846",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-846",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000846",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-847": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-847",
-                "number": "847",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-847",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000847",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-848": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-848",
-                "number": "848",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-848",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000848",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-849": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-849",
-                "number": "849",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-849",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000849",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-850": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-850",
-                "number": "850",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-850",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000850",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-851": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-851",
-                "number": "851",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-851",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000851",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-852": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-852",
-                "number": "852",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-852",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000852",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-853": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-853",
-                "number": "853",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-853",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000853",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-854": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-854",
-                "number": "854",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-854",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000854",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-855": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-855",
-                "number": "855",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-855",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000855",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-856": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-856",
-                "number": "856",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-856",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000856",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-857": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-857",
-                "number": "857",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-857",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000857",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-858": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-858",
-                "number": "858",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-858",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000858",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-859": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-859",
-                "number": "859",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-859",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000859",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-860": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-860",
-                "number": "860",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-860",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000860",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-861": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-861",
-                "number": "861",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-861",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000861",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-862": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-862",
-                "number": "862",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-862",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000862",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-863": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-863",
-                "number": "863",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-863",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000863",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-864": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-864",
-                "number": "864",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-864",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000864",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-865": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-865",
-                "number": "865",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-865",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000865",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-866": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-866",
-                "number": "866",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-866",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000866",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-867": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-867",
-                "number": "867",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-867",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000867",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-868": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-868",
-                "number": "868",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-868",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000868",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-869": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-869",
-                "number": "869",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-869",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000869",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-870": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-870",
-                "number": "870",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-870",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000870",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-871": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-871",
-                "number": "871",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-871",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000871",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-872": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-872",
-                "number": "872",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-872",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000872",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-873": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-873",
-                "number": "873",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-873",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000873",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-874": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-874",
-                "number": "874",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-874",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000874",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-875": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-875",
-                "number": "875",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-875",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000875",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-876": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-876",
-                "number": "876",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-876",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000876",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-877": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-877",
-                "number": "877",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-877",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000877",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-878": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-878",
-                "number": "878",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-878",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000878",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-879": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-879",
-                "number": "879",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-879",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000879",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-880": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-880",
-                "number": "880",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-880",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000880",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-881": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-881",
-                "number": "881",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-881",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000881",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-882": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-882",
-                "number": "882",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-882",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000882",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-883": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-883",
-                "number": "883",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-883",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000883",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-884": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-884",
-                "number": "884",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-884",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000884",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-885": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-885",
-                "number": "885",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-885",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000885",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-886": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-886",
-                "number": "886",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-886",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000886",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-887": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-887",
-                "number": "887",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-887",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000887",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-888": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-888",
-                "number": "888",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-888",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000888",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-889": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-889",
-                "number": "889",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-889",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000889",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-890": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-890",
-                "number": "890",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-890",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000890",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-891": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-891",
-                "number": "891",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-891",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000891",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-892": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-892",
-                "number": "892",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-892",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000892",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-893": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-893",
-                "number": "893",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-893",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000893",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-894": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-894",
-                "number": "894",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-894",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000894",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-895": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-895",
-                "number": "895",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-895",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000895",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-896": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-896",
-                "number": "896",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-896",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000896",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-897": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-897",
-                "number": "897",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-897",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000897",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-898": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-898",
-                "number": "898",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-898",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000898",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-899": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-899",
-                "number": "899",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-899",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000899",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-900": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-900",
-                "number": "900",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-900",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000900",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-901": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-901",
-                "number": "901",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-901",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000901",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-902": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-902",
-                "number": "902",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-902",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000902",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-903": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-903",
-                "number": "903",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-903",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000903",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-904": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-904",
-                "number": "904",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-904",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000904",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-905": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-905",
-                "number": "905",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-905",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000905",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-906": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-906",
-                "number": "906",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-906",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000906",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-907": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-907",
-                "number": "907",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-907",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000907",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-908": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-908",
-                "number": "908",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-908",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000908",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-909": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-909",
-                "number": "909",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-909",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000909",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-910": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-910",
-                "number": "910",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-910",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000910",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-911": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-911",
-                "number": "911",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-911",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000911",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-912": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-912",
-                "number": "912",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-912",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000912",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-913": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-913",
-                "number": "913",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-913",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000913",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-914": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-914",
-                "number": "914",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-914",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000914",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-915": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-915",
-                "number": "915",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-915",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000915",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-916": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-916",
-                "number": "916",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-916",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000916",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-917": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-917",
-                "number": "917",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-917",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000917",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-918": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-918",
-                "number": "918",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-918",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000918",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-919": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-919",
-                "number": "919",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-919",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000919",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-920": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-920",
-                "number": "920",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-920",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000920",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-921": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-921",
-                "number": "921",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-921",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000921",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-922": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-922",
-                "number": "922",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-922",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000922",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-923": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-923",
-                "number": "923",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-923",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000923",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-924": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-924",
-                "number": "924",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-924",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000924",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-925": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-925",
-                "number": "925",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-925",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000925",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-926": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-926",
-                "number": "926",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-926",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000926",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-927": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-927",
-                "number": "927",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-927",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000927",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-928": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-928",
-                "number": "928",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-928",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000928",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-929": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-929",
-                "number": "929",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-929",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000929",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-930": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-930",
-                "number": "930",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-930",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000930",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-931": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-931",
-                "number": "931",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-931",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000931",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-932": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-932",
-                "number": "932",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-932",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000932",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-933": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-933",
-                "number": "933",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-933",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000933",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-934": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-934",
-                "number": "934",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-934",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000934",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-935": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-935",
-                "number": "935",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-935",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000935",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-936": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-936",
-                "number": "936",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-936",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000936",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-937": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-937",
-                "number": "937",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-937",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000937",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-938": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-938",
-                "number": "938",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-938",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000938",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-939": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-939",
-                "number": "939",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-939",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000939",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-940": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-940",
-                "number": "940",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-940",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000940",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-941": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-941",
-                "number": "941",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-941",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000941",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-942": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-942",
-                "number": "942",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-942",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000942",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-943": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-943",
-                "number": "943",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-943",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000943",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-944": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-944",
-                "number": "944",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-944",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000944",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-945": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-945",
-                "number": "945",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-945",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000945",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-946": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-946",
-                "number": "946",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-946",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000946",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-947": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-947",
-                "number": "947",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-947",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000947",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-948": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-948",
-                "number": "948",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-948",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000948",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-949": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-949",
-                "number": "949",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-949",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000949",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-950": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-950",
-                "number": "950",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-950",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000950",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-951": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-951",
-                "number": "951",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-951",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000951",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-952": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-952",
-                "number": "952",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-952",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000952",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-953": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-953",
-                "number": "953",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-953",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000953",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-954": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-954",
-                "number": "954",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-954",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000954",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-955": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-955",
-                "number": "955",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-955",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000955",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-956": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-956",
-                "number": "956",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-956",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000956",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-957": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-957",
-                "number": "957",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-957",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000957",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-958": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-958",
-                "number": "958",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-958",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000958",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-959": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-959",
-                "number": "959",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-959",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000959",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-960": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-960",
-                "number": "960",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-960",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000960",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-961": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-961",
-                "number": "961",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-961",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000961",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-962": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-962",
-                "number": "962",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-962",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000962",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-963": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-963",
-                "number": "963",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-963",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000963",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-964": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-964",
-                "number": "964",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-964",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000964",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-965": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-965",
-                "number": "965",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-965",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000965",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-966": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-966",
-                "number": "966",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-966",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000966",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-967": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-967",
-                "number": "967",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-967",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000967",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-968": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-968",
-                "number": "968",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-968",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000968",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-969": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-969",
-                "number": "969",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-969",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000969",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-970": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-970",
-                "number": "970",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-970",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000970",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-971": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-971",
-                "number": "971",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-971",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000971",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-972": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-972",
-                "number": "972",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-972",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000972",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-973": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-973",
-                "number": "973",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-973",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000973",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-974": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-974",
-                "number": "974",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-974",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000974",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-975": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-975",
-                "number": "975",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-975",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000975",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-976": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-976",
-                "number": "976",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-976",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000976",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-977": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-977",
-                "number": "977",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-977",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000977",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-978": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-978",
-                "number": "978",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-978",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000978",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-979": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-979",
-                "number": "979",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-979",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000979",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-980": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-980",
-                "number": "980",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-980",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000980",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-981": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-981",
-                "number": "981",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-981",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000981",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-982": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-982",
-                "number": "982",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-982",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000982",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-983": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-983",
-                "number": "983",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-983",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000983",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-984": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-984",
-                "number": "984",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-984",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000984",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-985": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-985",
-                "number": "985",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-985",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000985",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-986": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-986",
-                "number": "986",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-986",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000986",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-987": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-987",
-                "number": "987",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-987",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000987",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-988": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-988",
-                "number": "988",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-988",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000988",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-989": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-989",
-                "number": "989",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-989",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000989",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-990": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-990",
-                "number": "990",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-990",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000990",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-991": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-991",
-                "number": "991",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-991",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000991",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-992": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-992",
-                "number": "992",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-992",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000992",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-993": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-993",
-                "number": "993",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-993",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000993",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-994": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-994",
-                "number": "994",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-994",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000994",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-995": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-995",
-                "number": "995",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-995",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000995",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-996": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-996",
-                "number": "996",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "yes"
-            },
-            "name": "mock-996",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000996",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-997": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-997",
-                "number": "997",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "no"
-            },
-            "name": "mock-997",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000997",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-998": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-998",
-                "number": "998",
-                "tag": "silly",
-                "type": "even",
-                "factor3": "no"
-            },
-            "name": "mock-998",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000998",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/pods/mock-999": {
-        "kind": "Pod",
-        "metadata": {
-            "labels": {
-                "name": "mock-999",
-                "number": "999",
-                "tag": "silly",
-                "type": "odd",
-                "factor3": "yes"
-            },
-            "name": "mock-999",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100000999",
-            "namespace": "default"
-        }
-    },
-    "namespaces/default/replicationcontrollers/oddcontroller": {
-        "kind": "ReplicationController",
-        "metadata": {
-            "labels": {
-                "example": "mock",
-                "name": "oddcontroller"
-            },
-            "name": "oddcontroller",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100001000",
-            "namespace": "default"
-        },
-        "spec": {
-            "replicas": 1,
-            "selector": {
-                "tag": "silly",
-                "type": "odd"
-            }
-        }
-    },
-    "namespaces/default/replicationcontrollers/3controller": {
-        "kind": "ReplicationController",
-        "metadata": {
-            "labels": {
-                "example": "mock",
-                "name": "3controller"
-            },
-            "name": "3controller",
-            "resourceVersion": 10000,
-            "uid": "11768037-ab8a-11e4-9a7c-100001001",
-            "namespace": "default"
-        },
-        "spec": {
-            "replicas": 1,
-            "selector": {
-                "factor3": "yes"
-            }
-        }
-    }
-};
diff --git a/pkg/kubernetes/scripts/frob-fixture.js b/pkg/kubernetes/scripts/frob-fixture.js
deleted file mode 100755
index f5cf12dc5..000000000
--- a/pkg/kubernetes/scripts/frob-fixture.js
+++ /dev/null
@@ -1,76 +0,0 @@
-#!/usr/bin/env node
-
-/*
- * This is used to generate data sets like the one in mock-large.js
- * Use it like so:
- *
- *  $ ./frob-mock.js > ./mock-large.js
- */
-
-var last = 99999999;
-function uid() {
-    last += 1;
-    return "11768037-ab8a-11e4-9a7c-" + last;
-}
-
-var pod_template = {
-    "kind": "Pod",
-    "metadata": {
-        "labels": {
-            "name": "mock-",
-            "number": "",
-            "tag": "silly"
-        }
-    }
-};
-
-var objects = {};
-
-var pod, i;
-for (i = 0; i < 1000; i++) {
-    pod = JSON.parse(JSON.stringify(pod_template));
-    pod.metadata.name += i;
-    pod.metadata.resourceVersion += i;
-    pod.metadata.labels.name += i;
-    pod.metadata.labels.number += i;
-    pod.metadata.labels.type = ["even", "odd"][i % 2];
-    pod.metadata.labels.factor3 = ["yes", "no", "no"][i % 3];
-
-    objects["namespaces/default/pods/mock-" + i] = pod;
-}
-
-var repl_template = {
-    "kind": "ReplicationController",
-    "metadata": {
-        "labels": {
-            "example": "mock"
-        }
-    },
-    "spec": {
-        "replicas": 1,
-        "selector": { },
-    }
-};
-
-var repl = JSON.parse(JSON.stringify(repl_template));
-repl.metadata.name = "oddcontroller";
-repl.spec.selector = { "tag": "silly", "type": "odd" };
-objects["namespaces/default/replicationcontrollers/oddcontroller"] = repl;
-
-repl = JSON.parse(JSON.stringify(repl_template));
-repl.metadata.name = "3controller";
-repl.spec.selector = { "factor3": "yes" };
-objects["namespaces/default/replicationcontrollers/3controller"] = repl;
-
-var path, parts;
-for (path in objects) {
-    parts = path.split("/");
-    objects[path].metadata.resourceVersion = 10000;
-    objects[path].metadata.uid = uid();
-    objects[path].metadata.namespace = parts[1];
-    objects[path].metadata.name = parts.reverse()[0];
-    objects[path].metadata.labels.name = objects[path].metadata.name;
-}
-
-var data = JSON.stringify(objects, null, 4);
-process.stdout.write("define(" + data + ");\n");
diff --git a/pkg/kubernetes/scripts/frob-layers-v1compatibility.jsonp b/pkg/kubernetes/scripts/frob-layers-v1compatibility.jsonp
deleted file mode 100644
index bc0c40221..000000000
--- a/pkg/kubernetes/scripts/frob-layers-v1compatibility.jsonp
+++ /dev/null
@@ -1,1181 +0,0 @@
-sink([
-  {
-    "v1Compatibility": {
-      "id": "89e18bec96a4ca40a5152842d99c4781a190516182579deeadf13f20f44ecea6",
-      "parent": "6a2b1b2520571bdb32fb52dd9ce9e3a24838f9fb8025aa974bdd2d6b340d0669",
-      "created": "2016-03-02T13:49:23.199169725Z",
-      "container": "1f489ce72478945e5f71171d7153612b3472f994ab6f7f1f1bc8d6569799be63",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) LABEL version=1.0"
-        ],
-        "Image": "6a2b1b2520571bdb32fb52dd9ce9e3a24838f9fb8025aa974bdd2d6b340d0669",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {
-          "Test": "Value",
-          "version": "1.0"
-        },
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "6a2b1b2520571bdb32fb52dd9ce9e3a24838f9fb8025aa974bdd2d6b340d0669",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {
-          "Test": "Value",
-          "version": "1.0"
-        },
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "6a2b1b2520571bdb32fb52dd9ce9e3a24838f9fb8025aa974bdd2d6b340d0669",
-      "parent": "bbca6d51c41a46b40e63abc9f64ee4cddcaf989a5e9a0fbeaa1ee80f24f11149",
-      "created": "2016-03-02T13:49:17.622735453Z",
-      "container": "fc89ccedb7e2bd02ac22c6b2f814330ca29fe7467290cc55a8fc95ec610b9d09",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) LABEL Test=Value"
-        ],
-        "Image": "bbca6d51c41a46b40e63abc9f64ee4cddcaf989a5e9a0fbeaa1ee80f24f11149",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {
-          "Test": "Value"
-        },
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "bbca6d51c41a46b40e63abc9f64ee4cddcaf989a5e9a0fbeaa1ee80f24f11149",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {
-          "Test": "Value"
-        },
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "bbca6d51c41a46b40e63abc9f64ee4cddcaf989a5e9a0fbeaa1ee80f24f11149",
-      "parent": "d2a5b8c97b05b03c3e02cae4cd0732229840f9fd55b15edfa2a2a3831f92e455",
-      "created": "2016-03-02T13:49:12.537373555Z",
-      "container": "a0e4a63ee751bf5883b2b40d96543a48fe6af18ac5061d3cb2be6884505d451b",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ARG simple"
-        ],
-        "Image": "d2a5b8c97b05b03c3e02cae4cd0732229840f9fd55b15edfa2a2a3831f92e455",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "d2a5b8c97b05b03c3e02cae4cd0732229840f9fd55b15edfa2a2a3831f92e455",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "d2a5b8c97b05b03c3e02cae4cd0732229840f9fd55b15edfa2a2a3831f92e455",
-      "parent": "8533fc673cc91593f95373049cbe53d5f517a90c34377a3c4e746a3be6d028af",
-      "created": "2016-03-02T13:49:07.17643214Z",
-      "container": "80cb2cba4ad6dd3b66b0aafaf3d49a2f57720bc4ea67956fee9bf3bb44e2227a",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ARG hello=test"
-        ],
-        "Image": "8533fc673cc91593f95373049cbe53d5f517a90c34377a3c4e746a3be6d028af",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "8533fc673cc91593f95373049cbe53d5f517a90c34377a3c4e746a3be6d028af",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "8533fc673cc91593f95373049cbe53d5f517a90c34377a3c4e746a3be6d028af",
-      "parent": "ee546cdf7ed55e9055722350db6fe2d1364e2aba690f84c9fe5300ece1b539d7",
-      "created": "2016-03-02T13:49:01.993873286Z",
-      "container": "07837b3e4624fc3f3fd6c093880f313dd6eff7f97c48e66c879bebf70b087d26",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ONBUILD ADD . /app/src"
-        ],
-        "Image": "ee546cdf7ed55e9055722350db6fe2d1364e2aba690f84c9fe5300ece1b539d7",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "ee546cdf7ed55e9055722350db6fe2d1364e2aba690f84c9fe5300ece1b539d7",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [
-          "ADD . /app/src"
-        ],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "ee546cdf7ed55e9055722350db6fe2d1364e2aba690f84c9fe5300ece1b539d7",
-      "parent": "e2368fd48286bb997dac8c9681de714e76a825dc87fc2a6854baaed8e748b9de",
-      "created": "2016-03-02T13:48:55.221100229Z",
-      "container": "94a628e0153d7c579bec9c54fab7ed6296b90ee3f58d541209043628dda81a41",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) STOPSIGNAL [SIGKILL]"
-        ],
-        "Image": "e2368fd48286bb997dac8c9681de714e76a825dc87fc2a6854baaed8e748b9de",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "e2368fd48286bb997dac8c9681de714e76a825dc87fc2a6854baaed8e748b9de",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {},
-        "StopSignal": "SIGKILL"
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "e2368fd48286bb997dac8c9681de714e76a825dc87fc2a6854baaed8e748b9de",
-      "parent": "9541b952349ea6116d1ea82736f4407572257bc2080fe0a85656a13b5e8fed82",
-      "created": "2016-03-02T13:48:48.18265793Z",
-      "container": "298e297b12b4953029fc24de7fc21a493f30a6c34dfaa00a6b697672d358691a",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) CMD [\"-c\"]"
-        ],
-        "Image": "9541b952349ea6116d1ea82736f4407572257bc2080fe0a85656a13b5e8fed82",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "-c"
-        ],
-        "Image": "9541b952349ea6116d1ea82736f4407572257bc2080fe0a85656a13b5e8fed82",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "9541b952349ea6116d1ea82736f4407572257bc2080fe0a85656a13b5e8fed82",
-      "parent": "7733d572fc28bc5dfdaef85b85990201a5a835d8b65b31c6f659f313bea70d33",
-      "created": "2016-03-02T13:48:42.168991966Z",
-      "container": "7d9ccd9a84e6631b66190b5f73ef6e5b3fb2442d2615e857302c2e478aba302b",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ENTRYPOINT &{[\"top\" \"-b\"]}"
-        ],
-        "Image": "7733d572fc28bc5dfdaef85b85990201a5a835d8b65b31c6f659f313bea70d33",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": null,
-        "Image": "7733d572fc28bc5dfdaef85b85990201a5a835d8b65b31c6f659f313bea70d33",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": [
-          "top",
-          "-b"
-        ],
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "7733d572fc28bc5dfdaef85b85990201a5a835d8b65b31c6f659f313bea70d33",
-      "parent": "daa3842818eba54c8f9896c4a73004cb758f17cf17340c02bae7a02713fb1141",
-      "created": "2016-03-02T13:48:36.127887903Z",
-      "container": "84d126716b35735750893946e3f2b3538a4fe90b1c2fcb6dac25ec3e8ba10d3e",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) USER [nobody:wheel]"
-        ],
-        "Image": "daa3842818eba54c8f9896c4a73004cb758f17cf17340c02bae7a02713fb1141",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "nobody:wheel",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "\"/echo-script\""
-        ],
-        "Image": "daa3842818eba54c8f9896c4a73004cb758f17cf17340c02bae7a02713fb1141",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "daa3842818eba54c8f9896c4a73004cb758f17cf17340c02bae7a02713fb1141",
-      "parent": "9d4f2e1ac750a13b0b40c058ff1f43c408d2b3981a69709cb1d122916ffd0c52",
-      "created": "2016-03-02T13:48:27.418271646Z",
-      "container": "4f41201cb36cf14e8b786613487dd32db63023cacaf32d48be699b56c1b30403",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ADD file:7a0204a785c5c99c2e0a34e186257e7e1a06b46a6467172d42f2a8b6faaec266 in /usr/bin"
-        ],
-        "Image": "9d4f2e1ac750a13b0b40c058ff1f43c408d2b3981a69709cb1d122916ffd0c52",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "\"/echo-script\""
-        ],
-        "Image": "9d4f2e1ac750a13b0b40c058ff1f43c408d2b3981a69709cb1d122916ffd0c52",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux",
-      "Size": 124985485
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "9d4f2e1ac750a13b0b40c058ff1f43c408d2b3981a69709cb1d122916ffd0c52",
-      "parent": "f2fac80fdf50b0738e434a0a5b04677bcf39f3afb4c892b683035b1cc6810945",
-      "created": "2016-03-02T13:48:00.528642138Z",
-      "container": "7093d7c71526d6441bacd87becc23b258f9747c1121e4743ada00b5a3b16a974",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) CMD [\"/bin/sh\" \"-c\" \"\\\"/echo-script\\\"\"]"
-        ],
-        "Image": "f2fac80fdf50b0738e434a0a5b04677bcf39f3afb4c892b683035b1cc6810945",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "author": "cockpit@example.com",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "\"/echo-script\""
-        ],
-        "Image": "f2fac80fdf50b0738e434a0a5b04677bcf39f3afb4c892b683035b1cc6810945",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "f2fac80fdf50b0738e434a0a5b04677bcf39f3afb4c892b683035b1cc6810945",
-      "parent": "0b7194f278c0677c43cdc273985ac5534c30f1534e15457e328da8ded4cedd95",
-      "created": "2016-03-02T13:47:53.685835007Z",
-      "container": "9459e4feec9d3516c9ca21a6040bac1e9d62ae54dfeda031620ead552146c377",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "chmod +x /echo-script"
-        ],
-        "Image": "0b7194f278c0677c43cdc273985ac5534c30f1534e15457e328da8ded4cedd95",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "author": "cockpit@example.com",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "sh"
-        ],
-        "Image": "0b7194f278c0677c43cdc273985ac5534c30f1534e15457e328da8ded4cedd95",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux",
-      "Size": 49
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "0b7194f278c0677c43cdc273985ac5534c30f1534e15457e328da8ded4cedd95",
-      "parent": "0a85b5651d9d66663bde6e24c8322dd06394dcd2f14a590a71f5264b5bae68c9",
-      "created": "2016-03-02T13:47:46.440413292Z",
-      "container": "ff2c25f93e7b586ac29757d37bd8324dfc449de16270df6efe69276a8173a064",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ADD file:b35fc316562d0e29fa7ae1e767f3597811f4349e30aa74122b67965a103f817a in /"
-        ],
-        "Image": "0a85b5651d9d66663bde6e24c8322dd06394dcd2f14a590a71f5264b5bae68c9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "author": "cockpit@example.com",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "sh"
-        ],
-        "Image": "0a85b5651d9d66663bde6e24c8322dd06394dcd2f14a590a71f5264b5bae68c9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux",
-      "Size": 49
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "0a85b5651d9d66663bde6e24c8322dd06394dcd2f14a590a71f5264b5bae68c9",
-      "parent": "5a82ed0a2cc4a5a9f8ce2656d8d7c5254592baac28d1701b0153416759fbabf9",
-      "created": "2016-03-02T13:47:40.786531005Z",
-      "container": "9b31ac4ceb47e917187332bbdf26407d99de10e095941a3a2caba95a7d433850",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) EXPOSE 8888/tcp"
-        ],
-        "Image": "5a82ed0a2cc4a5a9f8ce2656d8d7c5254592baac28d1701b0153416759fbabf9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "author": "cockpit@example.com",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "ExposedPorts": {
-          "8888/tcp": {}
-        },
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "sh"
-        ],
-        "Image": "5a82ed0a2cc4a5a9f8ce2656d8d7c5254592baac28d1701b0153416759fbabf9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "5a82ed0a2cc4a5a9f8ce2656d8d7c5254592baac28d1701b0153416759fbabf9",
-      "parent": "fef924a0204a00b3ec67318e2ed337b189c99ea19e2bf10ed30a13b87c5e17ab",
-      "created": "2016-03-02T13:47:34.535472081Z",
-      "container": "01e40050638e9621b63c9f2da83f6b2778c4bdc9ef0c592649d819beeff43633",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) MAINTAINER cockpit@example.com"
-        ],
-        "Image": "65e4158d96256e032299e07ac28308d644c0e81d52b18dcb08847a5027b4f107",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "author": "cockpit@example.com",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": [
-          "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
-        ],
-        "Cmd": [
-          "sh"
-        ],
-        "Image": "65e4158d96256e032299e07ac28308d644c0e81d52b18dcb08847a5027b4f107",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": [],
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "fef924a0204a00b3ec67318e2ed337b189c99ea19e2bf10ed30a13b87c5e17ab",
-      "parent": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
-      "created": "2016-02-16T22:59:37.407805421Z",
-      "container": "d23509cd0189de02bef382544ebfab515f29094f3c0e2f161fa7ce09afa8974e",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": null,
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) CMD [\"sh\"]"
-        ],
-        "Image": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": null,
-        "Labels": {}
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": null,
-        "Cmd": [
-          "sh"
-        ],
-        "Image": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": null,
-        "Labels": {}
-      },
-      "architecture": "amd64",
-      "os": "linux"
-    }
-  },
-  {
-    "v1Compatibility": {
-      "id": "9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9",
-      "created": "2016-02-16T22:59:36.792440427Z",
-      "container": "13709f13afe11b7d4a007d2866afd20c5b783f0a89f4e6792a28102a4c12c473",
-      "container_config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": null,
-        "Cmd": [
-          "/bin/sh",
-          "-c",
-          "#(nop) ADD file:7cdf7a89f6a004b2e9501317bd72bd863d93a51255d8f83b2ed3058d385a4938 in /"
-        ],
-        "Image": "",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": null,
-        "Labels": null
-      },
-      "docker_version": "1.9.1",
-      "config": {
-        "Hostname": "13709f13afe1",
-        "Domainname": "",
-        "User": "",
-        "AttachStdin": false,
-        "AttachStdout": false,
-        "AttachStderr": false,
-        "Tty": false,
-        "OpenStdin": false,
-        "StdinOnce": false,
-        "Env": null,
-        "Cmd": null,
-        "Image": "",
-        "Volumes": null,
-        "WorkingDir": "",
-        "Entrypoint": null,
-        "OnBuild": null,
-        "Labels": null
-      },
-      "architecture": "amd64",
-      "os": "linux",
-      "Size": 1113554
-    }
-  }
-]);
diff --git a/pkg/kubernetes/scripts/graphs.js b/pkg/kubernetes/scripts/graphs.js
deleted file mode 100644
index 30276f12b..000000000
--- a/pkg/kubernetes/scripts/graphs.js
+++ /dev/null
@@ -1,863 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    var d3 = require('d3');
-
-    require('./kube-client');
-    require('./kube-client-cockpit');
-    require('./utils');
-
-    angular.module('kubernetes.graph', [
-        'kubeClient',
-        'kubeClient.cockpit',
-        'kubeUtils',
-    ])
-
-            .factory('CAdvisorSeries', [
-                "KubeRequest",
-                "CockpitMetrics",
-                "$exceptionHandler",
-                "$timeout",
-                function (KubeRequest, CockpitMetrics, $exceptionHandler, $timeout) {
-                    function CAdvisor(node) {
-                        var self = this;
-
-                        /* called when containers changed */
-                        var callbacks = [];
-
-                        /* cAdvisor has 10 second intervals */
-                        var interval = 10000;
-
-                        var last = { };
-
-                        var requests = { };
-
-                        /* Holds the container specs */
-                        self.specs = { };
-
-                        function feed(containers) {
-                            var x, y, ylen, i, len;
-                            var item, offset, timestamp, container, stat;
-
-                            /*
-                     * The cAdvisor data doesn't seem to have inherent guarantees of
-                     * continuity or regularity. In theory each stats object can have
-                     * it's own arbitrary timestamp ... although in practice they do
-                     * generally follow the interval to within a few milliseconds.
-                     *
-                     * So we first look for the lowest timestamp, treat that as our
-                     * base index, and then batch the data based on that.
-                     */
-
-                            var first = null;
-
-                            for (x in containers) {
-                                container = containers[x];
-                                if (container.stats) {
-                                    len = container.stats.length;
-                                    for (i = 0; i < len; i++) {
-                                        timestamp = container.stats[i].timestamp;
-                                        if (timestamp) {
-                                            if (first === null || timestamp < first)
-                                                first = timestamp;
-                                        }
-                                    }
-                                }
-                            }
-
-                            if (first === null)
-                                return;
-
-                            var base = Math.floor(new Date(first).getTime() / interval);
-
-                            var items = [];
-                            var name;
-                            var mapping = { };
-                            var new_ids = [];
-                            var id;
-                            var names = { };
-
-                            for (x in containers) {
-                                container = containers[x];
-
-                                /*
-                         * This builds the correct type of object graph for the
-                         * paths seen in grid.add() to operate on
-                         */
-                                name = container.name;
-                                if (!name)
-                                    continue;
-
-                                names[name] = name;
-                                mapping[name] = { "": name };
-                                id = name;
-
-                                if (container.aliases) {
-                                    ylen = container.aliases.length;
-                                    for (y = 0; y < ylen; y++) {
-                                        mapping[container.aliases[y]] = { "": name };
-
-                                        /* Try to use the real docker container id as our id */
-                                        if (container.aliases[y].length === 64)
-                                            id = container.aliases[y];
-                                    }
-                                }
-
-                                if (id && container.spec) {
-                                    if (!self.specs[id]) {
-                                        self.specs[id] = container.spec;
-                                        new_ids.push(id);
-                                    }
-                                }
-
-                                if (container.stats) {
-                                    len = container.stats.length;
-                                    for (i = 0; i < len; i++) {
-                                        stat = container.stats[i];
-                                        if (!stat.timestamp)
-                                            continue;
-
-                                        /* Convert the timestamp into an index */
-                                        offset = Math.floor(new Date(stat.timestamp).getTime() / interval);
-
-                                        item = items[offset - base];
-                                        if (!item)
-                                            item = items[offset - base] = { };
-                                        item[name] = stat;
-                                    }
-                                }
-                            }
-
-                            if (new_ids.length > 0)
-                                invokeCallbacks(new_ids);
-
-                            /* Make sure each offset has something */
-                            len = items.length;
-                            for (i = 0; i < len; i++) {
-                                if (items[i] === undefined)
-                                    items[i] = { };
-                            }
-
-                            /* Now for each offset, if it's a duplicate, put in a copy */
-                            for (name in names) {
-                                len = items.length;
-                                for (i = 0; i < len; i++) {
-                                    if (items[i][name] === undefined)
-                                        items[i][name] = last[name];
-                                    else
-                                        last[name] = items[i][name];
-                                }
-                            }
-
-                            self.series.input(base, items, mapping);
-                        }
-
-                        function request(query) {
-                            var body = JSON.stringify(query);
-
-                            /* Only one request active at a time for any given body */
-                            if (body in requests)
-                                return;
-
-                            var path = "/api/v1/proxy/nodes/" + encodeURIComponent(node) + ":4194/api/v1.2/docker";
-                            var req = KubeRequest("POST", path, query);
-
-                            requests[body] = req;
-                            req.then(function(data) {
-                                delete requests[body];
-                                feed(data.data);
-                            })
-                                    .catch(function(ex) {
-                                        delete requests[body];
-                                        if (ex.status != 503)
-                                            console.warn(ex);
-                                    });
-                        }
-
-                        function invokeCallbacks(/* ... */) {
-                            var i, len, func;
-                            for (i = 0, len = callbacks.length; i < len; i++) {
-                                func = callbacks[i];
-                                try {
-                                    if (func)
-                                        func.apply(self, arguments);
-                                } catch (e) {
-                                    $exceptionHandler(e);
-                                }
-                            }
-                        }
-
-                        self.fetch = function fetch(beg, end) {
-                            var query;
-                            if (!beg || !end) {
-                                query = { num_stats: 60 };
-                            } else {
-                                query = {
-                                    start: new Date((beg - 1) * interval).toISOString(),
-                                    end: new Date(end * interval).toISOString()
-                                };
-                            }
-                            request(query);
-                        };
-
-                        self.close = function close() {
-                            var req, body;
-                            for (body in requests) {
-                                req = requests[body];
-                                if (req && req.cancel)
-                                    req.cancel();
-                            }
-                        };
-
-                        self.watch = function watch(callback) {
-                            var ids;
-                            var timeout;
-                            callbacks.push(callback);
-                            if (self.specs) {
-                                ids = Object.keys(self.specs);
-                                if (ids.length > 0) {
-                                    timeout = $timeout(function() {
-                                        timeout = null;
-                                        callback.call(self, ids);
-                                    }, 0);
-                                }
-                            }
-
-                            return {
-                                cancel: function() {
-                                    var i, len;
-                                    $timeout.cancel(timeout);
-                                    timeout = null;
-                                    for (i = 0, len = callbacks.length; i < len; i++) {
-                                        if (callbacks[i] === callback)
-                                            callbacks[i] = null;
-                                    }
-                                }
-                            };
-                        };
-
-                        var cache = "cadv1-" + (node || null);
-                        self.series = CockpitMetrics.series(interval, cache, self.fetch);
-                    }
-
-                    return {
-                        new_cadvisor: function(node) {
-                            return new CAdvisor(node);
-                        },
-                    };
-                }
-            ])
-
-            .factory('ServiceGrid', [
-                "CAdvisorSeries",
-                "CockpitMetrics",
-                "kubeSelect",
-                "kubeLoader",
-                function ServiceGrid(CAdvisorSeries, CockpitMetrics, select, loader) {
-                    function CockpitServiceGrid(until) {
-                        var self = CockpitMetrics.grid(10000, 0, 0);
-
-                        /* All the cadvisors that have been opened, one per host */
-                        var cadvisors = { };
-
-                        /* Service uids */
-                        var services = { };
-
-                        /* The various rows being shown, override */
-                        self.rows = [ ];
-                        self.events = [ ];
-
-                        var change_queued = false;
-                        var current_metric = null;
-
-                        var rows = {
-                            cpu: { },
-                            memory: { },
-                            network: { }
-                        };
-
-                        var container_cpu = { };
-                        var container_mem = { };
-                        var container_rx = { };
-                        var container_tx = { };
-
-                        /* Track Pods and Services */
-                        loader.listen(function() {
-                            var changed = false;
-                            var seen_services = {};
-                            var seen_hosts = {};
-
-                            /* Lookup all the services */
-                            angular.forEach(select().kind("Service"), function(service) {
-                                var spec = service.spec;
-                                var meta = service.metadata;
-                                var name = meta.name;
-
-                                if (!spec || !spec.selector || name === "kubernetes" || name === "kubernetes-ro")
-                                    return;
-
-                                var uid = meta.uid;
-                                var pods = select().kind("Pod")
-                                        .namespace(meta.namespace || "")
-                                        .label(spec.selector || {});
-
-                                seen_services[uid] = true;
-                                if (!services[uid])
-                                    add_service(uid);
-
-                                /* Lookup all the pods for each service */
-                                angular.forEach(pods, function(pod) {
-                                    var status = pod.status || { };
-                                    var spec = pod.spec || { };
-                                    var host = spec.nodeName;
-                                    var container_ids = {};
-                                    var containers = status.containerStatuses || [];
-                                    var i;
-                                    var mapped = services[uid];
-
-                                    seen_hosts[host] = true;
-                                    if (host && !cadvisors[host]) {
-                                        add_cadvisor(host);
-                                    }
-
-                                    /* Note all the containers for that pod */
-                                    for (i = 0; i < containers.length; i++) {
-                                        var container = containers[i];
-                                        var id = container.containerID;
-                                        if (id && id.indexOf("docker://") === 0) {
-                                            container_ids[id] = id;
-                                            id = id.substring(9);
-                                            container_ids[id] = id;
-                                            if (!mapped || !mapped[id])
-                                                changed = true;
-                                        }
-                                    }
-                                    services[uid] = container_ids;
-                                });
-                            });
-
-                            var k;
-                            for (k in services) {
-                                if (!seen_services[k]) {
-                                    remove_service(k);
-                                    changed = true;
-                                }
-                            }
-
-                            for (k in cadvisors) {
-                                if (!seen_hosts[k]) {
-                                    remove_host(k);
-                                    changed = true;
-                                }
-                            }
-
-                            /* Notify for all rows */
-                            if (changed)
-                                self.sync();
-                        }, until);
-
-                        loader.watch("Pod", until);
-                        loader.watch("Service", until);
-
-                        function add_container(cadvisor, id) {
-                            var cpu = self.add(cadvisor, [ id, "cpu", "usage", "total" ]);
-                            container_cpu[id] = self.add(function(row, x, n) {
-                                row_delta(cpu, row, x, n);
-                            }, true);
-
-                            container_mem[id] = self.add(cadvisor, [ id, "memory", "usage" ]);
-
-                            var rx = self.add(cadvisor, [ id, "network", "rx_bytes" ]);
-                            container_rx[id] = self.add(function(row, x, n) {
-                                row_delta(rx, row, x, n);
-                            }, true);
-
-                            var tx = self.add(cadvisor, [ id, "network", "tx_bytes" ]);
-                            container_tx[id] = self.add(function(row, x, n) {
-                                row_delta(tx, row, x, n);
-                            }, true);
-
-                            self.sync();
-                        }
-
-                        function add_cadvisor(host) {
-                            var cadvisor = CAdvisorSeries.new_cadvisor(host);
-                            cadvisor.watch(function (ids) {
-                                var i;
-                                for (i = 0; i < ids.length; i++)
-                                    add_container(cadvisor, ids[i]);
-                            });
-
-                            /* A dummy row to force fetching data from the cadvisor */
-                            self.add(cadvisor, [ "unused-dummy" ]);
-
-                            /* TODO: Handle cadvisor failure somehow */
-                            cadvisors[host] = cadvisor;
-                        }
-
-                        function remove_host(host) {
-                            var cadvisor = cadvisors[host];
-                            if (cadvisor) {
-                                delete cadvisors[host];
-                                cadvisor.close();
-                                cadvisor = null;
-                                change_queued = true;
-                            }
-                        }
-
-                        function add_service(uid) {
-                            /* CPU needs summing of containers, and then delta between them */
-                            rows.cpu[uid] = self.add(function(row, x, n) {
-                                containers_sum(uid, container_cpu, row, x, n);
-                            });
-
-                            /* Memory row is pretty simple, just sum containers */
-                            rows.memory[uid] = self.add(function(row, x, n) {
-                                containers_sum(uid, container_mem, row, x, n);
-                            });
-
-                            /* Network sums containers, then sum tx and rx, and then delta */
-                            var tx = self.add(function(row, x, n) {
-                                containers_sum(uid, container_tx, row, x, n);
-                            });
-                            var rx = self.add(function(row, x, n) {
-                                containers_sum(uid, container_rx, row, x, n);
-                            });
-                            rows.network[uid] = self.add(function(row, x, n) {
-                                rows_sum([tx, rx], row, x, n);
-                            });
-
-                            change_queued = true;
-                        }
-
-                        function remove_service(uid) {
-                            delete services[uid];
-                            delete rows.network[uid];
-                            delete rows.cpu[uid];
-                            delete rows.memory[uid];
-                            change_queued = true;
-                        }
-
-                        function rows_sum(input, row, x, n) {
-                            var max = row.maximum || 0;
-                            var value, i, v, j;
-                            var len = input.length;
-
-                            /* Calculate the sum of the rows */
-                            for (i = 0; i < n; i++) {
-                                value = undefined;
-                                for (j = 0; j < len; j++) {
-                                    v = input[j][x + i];
-                                    if (v !== undefined) {
-                                        if (value === undefined)
-                                            value = v;
-                                        else
-                                            value += v;
-                                    }
-                                }
-
-                                if (value !== undefined && value > max) {
-                                    row.maximum = max = value;
-                                    change_queued = true;
-                                }
-
-                                row[x + i] = value;
-                            }
-                        }
-
-                        function row_delta(input, row, x, n) {
-                            var i, last, res, value;
-                            if (x > 0)
-                                last = input[x - 1];
-
-                            var max = row.maximum || 1;
-                            for (i = 0; i < n; i++) {
-                                value = input[x + i];
-                                if (last === undefined || value === undefined) {
-                                    res = undefined;
-                                } else {
-                                    res = (value - last);
-                                    if (res < 0) {
-                                        res = undefined;
-                                    } else if (res > max) {
-                                        row.maximum = max = res;
-                                        change_queued = true;
-                                    }
-                                }
-                                row[x + i] = res;
-                                last = value;
-                            }
-                        }
-
-                        function containers_sum(service, input, row, x, n) {
-                            var id, rowc;
-                            var subset = [];
-                            var mapped = services[service];
-                            if (mapped) {
-                                for (id in mapped) {
-                                    rowc = input[id];
-                                    if (rowc)
-                                        subset.push(rowc);
-                                }
-                            }
-                            rows_sum(subset, row, x, n);
-                        }
-
-                        self.metric = function metric(type) {
-                            if (type === undefined)
-                                return current_metric;
-                            if (rows[type] === undefined)
-                                throw Error("unsupported metric type");
-
-                            self.rows = [];
-                            current_metric = type;
-
-                            var service_uids = Object.keys(services);
-                            var row, i;
-                            var len = service_uids.length;
-                            for (i = 0; i < len; i++) {
-                                row = rows[type][service_uids[i]];
-                                if (row !== undefined) {
-                                    self.rows.push(row);
-                                    row.uid = service_uids[i];
-                                }
-                            }
-
-                            var event = new CustomEvent("changed", {
-                                bubbles: false,
-                                cancelable: false,
-                                detail: null
-                            });
-                            self.dispatchEvent(event, null);
-                        };
-
-                        var base_close = self.close;
-                        self.close = function close() {
-                            var hosts = Object.keys(cadvisors);
-                            var i;
-                            for (i = 0; i < hosts.length; i++) {
-                                var k = hosts[i];
-                                var cadvisor = cadvisors[k];
-                                if (cadvisor) {
-                                    delete cadvisors[k];
-                                    cadvisor.close();
-                                    cadvisor = null;
-                                }
-                            }
-                            base_close.apply(self);
-                        };
-
-                        self.addEventListener("notify", function () {
-                            if (change_queued) {
-                                change_queued = false;
-                                self.metric(current_metric);
-                            }
-                        });
-
-                        return self;
-                    }
-
-                    return {
-                        new_grid: function (until) {
-                            return new CockpitServiceGrid(until);
-                        }
-                    };
-                }
-            ])
-
-            .directive('kubernetesServiceGraph', [
-                "ServiceGrid",
-                "KubeTranslate",
-                "KubeFormat",
-                function kubernetesServiceGraph(ServiceGrid, KubeTranslate, KubeFormat) {
-                    const _ = KubeTranslate.gettext;
-
-                    function service_graph($scope, selector, highlighter) {
-                        var grid = ServiceGrid.new_grid($scope);
-                        var outer = d3.select(selector);
-
-                        var highlighted = null;
-
-                        /* Various tabs */
-
-                        var tabs = {
-                            cpu: {
-                                label: _("CPU"),
-                                step: 1000 * 1000 * 1000 * 10,
-                                formatter: function(v) { return (v / (100 * 1000 * 1000)) + "%" }
-                            },
-                            memory: {
-                                label: _("Memory"),
-                                step: 1024 * 1024 * 64,
-                                formatter: function(v) { return KubeFormat.formatBytes(v) }
-                            },
-                            network: {
-                                label: _("Network"),
-                                step: 1000 * 1000 * 10,
-                                formatter: function(v) { return KubeFormat.formatBitsPerSec((v / 10), "Mbps") }
-                            }
-                        };
-
-                        outer.append("ul")
-                                .attr("class", "nav nav-tabs")
-                                .selectAll("li")
-                                .data(Object.keys(tabs))
-                                .enter()
-                                .append("li")
-                                .attr("data-metric", function(d) { return d })
-                                .append("a")
-                                .text(function(d) { return tabs[d].label });
-
-                        function metric_tab(tab) {
-                            outer.selectAll("ul li")
-                                    .attr("class", function(d) { return tab === d ? "active" : null });
-                            grid.metric(tab);
-                        }
-
-                        outer.selectAll("ul li")
-                                .on("click", function() {
-                                    metric_tab(d3.select(this).attr("data-metric"));
-                                });
-
-                        metric_tab("cpu");
-
-                        /* The main svg graph stars here */
-
-                        var margins = {
-                            top: 12,
-                            right: 15,
-                            bottom: 40,
-                            left: 60
-                        };
-
-                        var colors = d3.scale.category20();
-
-                        var element = d3.select(selector).append("svg");
-                        var stage = element.append("g")
-                                .attr("transform", "translate(" + margins.left + "," + margins.top + ")");
-
-                        var y = d3.scale.linear();
-                        var y_axis = d3.svg.axis()
-                                .scale(y)
-                                .ticks(5)
-                                .orient("left");
-                        var y_group = stage.append("g")
-                                .attr("class", "y axis");
-
-                        var x = d3.scale.linear();
-                        var x_axis = d3.svg.axis()
-                                .scale(x)
-                                .orient("bottom");
-                        var x_group = stage.append("g")
-                                .attr("class", "x axis");
-
-                        var offset = 0;
-
-                        var line = d3.svg.line()
-                                .defined(function(d) { return d !== undefined })
-                                .x(function(d, i) { return x((grid.beg + i) - offset) })
-                                .y(function(d, i) { return y(d) });
-
-                        /* Initial display: 1024 px, 5 minutes of data */
-                        var factor = 300000 / 1024;
-                        var width = 300;
-                        var height = 300;
-
-                        var rendered = false;
-                        window.setTimeout(function() {
-                            rendered = true;
-                            adjust();
-                        }, 1);
-
-                        function ceil(value, step) {
-                            var d = value % step;
-                            if (value === 0 || d !== 0)
-                                value += (step - d);
-                            return value;
-                        }
-
-                        function jump() {
-                            var interval = grid.interval;
-                            var w = (width - margins.right) - margins.left;
-                            /* This doesn't yet work for an arbitary ponit in time */
-                            var now = new Date().getTime();
-                            var end = Math.floor(now / interval);
-                            var beg = end - Math.floor((factor * w) / interval);
-                            offset = beg;
-                            grid.move(beg, end);
-                        }
-
-                        function adjust() {
-                            if (!rendered)
-                                return;
-
-                            element
-                                    .attr("width", width)
-                                    .attr("height", height);
-
-                            var w = (width - margins.right) - margins.left;
-                            var h = (height - margins.top) - margins.bottom;
-
-                            var metric = grid.metric();
-                            var interval = grid.interval;
-
-                            /* Calculate our maximum value, hopefully rows are tracking this for us */
-                            var rows = grid.rows;
-                            var maximum = 0;
-                            var i, max;
-                            var len = rows.length;
-                            for (i = 0; i < len; i++) {
-                                if (rows[i].maximum !== undefined)
-                                    max = rows[i].maximum;
-                                else
-                                    max = d3.max(rows[i]);
-                                if (max > maximum)
-                                    maximum = Math.ceil(max);
-                            }
-
-                            /* This doesn't yet work for an arbitary ponit in time */
-                            var end = Math.floor((factor * w) / interval);
-                            x.domain([0, end]).range([0, w]);
-                            y.domain([0, ceil(maximum, tabs[metric].step)]).range([h, 0]);
-
-                            /* The ticks are inverted backwards */
-                            var tsc = d3.scale.linear().domain([0, end])
-                                    .range([end, 0]);
-
-                            /* Calculate ticks every 60 seconds in past */
-                            var ticks = [];
-                            for (i = 6; i < end; i += 6)
-                                ticks.push(Math.round(tsc(i)));
-
-                            /* Make x-axis ticks into grid of right width */
-                            x_axis
-                                    .tickValues(ticks)
-                                    .tickSize(-h, -h)
-                                    .tickFormat(function(d) {
-                                        d = Math.round(tsc.invert(d));
-                                        return (d / 6) + " min";
-                                    });
-
-                            /* Re-render the X axis. Note that we also
-                     * bump down the labels a bit. */
-                            x_group
-                                    .attr("transform", "translate(0," + h + ")")
-                                    .call(x_axis)
-                                    .selectAll("text")
-                                    .attr("y", "10px");
-
-                            /* Turn the Y axis ticks into a grid */
-                            y_axis
-                                    .tickSize(-w, -w)
-                                    .tickFormat(tabs[metric].formatter);
-
-                            y_group
-                                    .call(y_axis)
-                                    .selectAll("text")
-                                    .attr("x", "-10px");
-
-                            jump();
-                        }
-
-                        function notified() {
-                            var rows = grid.rows;
-
-                            var series = stage.selectAll("path.line")
-                                    .data(rows, function(d, i) { return i });
-
-                            series
-                                    .style("stroke", function(d, i) { return colors(i) })
-                                    .attr("d", function(d) { return line(d) })
-                                    .classed("highlight", function(d) { return d.uid === highlighted });
-
-                            series.enter().append("path")
-                                    .attr("class", "line")
-                                    .on("mouseover", function() {
-                                        highlighter(d3.select(this).datum().uid);
-                                    })
-                                    .on("mouseout", function() {
-                                        highlighter(null);
-                                    });
-                            series.exit().remove();
-                        }
-
-                        grid.addEventListener('notify', notified);
-
-                        function changed() {
-                            adjust();
-                            notified();
-                        }
-
-                        grid.addEventListener('changed', changed);
-
-                        function resized() {
-                            width = selector.offsetWidth - 10;
-                            if (width < 0)
-                                width = 0;
-                            adjust();
-                        }
-
-                        window.addEventListener('resize', resized);
-                        resized();
-
-                        var timer = window.setInterval(function () {
-                            if (!width)
-                                resized();
-                            else
-                                jump();
-                        }, grid.interval);
-
-                        return {
-                            highlight: function highlight(uid) {
-                                highlighted = uid;
-                                notified();
-                            },
-                            close: function close() {
-                                if (timer)
-                                    window.clearInterval(timer);
-                                timer = null;
-                                window.removeEventListener('resize', resized);
-                                grid.removeEventListener('notify', notified);
-                                grid.removeEventListener('changed', changed);
-                                grid.close();
-                            }
-                        };
-                    }
-
-                    return {
-                        restrict: 'E',
-                        link: function($scope, element, attributes) {
-                            var graph = service_graph($scope, element[0], function(uid) {
-                                $scope.$broadcast('highlight', uid);
-                                $scope.$digest();
-                            });
-                            $scope.$on("highlight", function(ev, uid) {
-                                graph.highlight(uid);
-                            });
-                            element.on('$destroy', function() {
-                                graph.close();
-                                graph = null;
-                            });
-                        }
-                    };
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/images.js b/pkg/kubernetes/scripts/images.js
deleted file mode 100644
index d2403ab92..000000000
--- a/pkg/kubernetes/scripts/images.js
+++ /dev/null
@@ -1,723 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    require("angular-route");
-    require('angular-dialog.js');
-
-    require('./kube-client');
-    require('./date');
-    require('./tags');
-    require('./policy');
-
-    require('registry-image-widgets/dist/image-widgets.js');
-
-    require('../views/images-page.html');
-    require('../views/imagestream-page.html');
-    require('../views/image-page.html');
-    require('../views/imagestream-delete.html');
-    require('../views/imagestream-modify.html');
-    require('../views/imagestream-modify.html');
-    require('../views/image-delete.html');
-
-    /*
-     * Executes callback for each stream.status.tag[x].item[y]
-     * in a stream. Similar behavior to angular.forEach()
-     */
-    function imagestreamEachTagItem(stream, callback, context) {
-        var i, il, items;
-        var t, tl;
-        var tags = (stream.status || {}).tags || [];
-        for (t = 0, tl = tags.length; t < tl; t++) {
-            items = (tags[t].items) || [];
-            for (i = 0, il = items.length; i < il; i++)
-                callback.call(context || null, tags[t], items[i]);
-        }
-    }
-
-    function identifier(imagestream, tag) {
-        var id = imagestream.metadata.namespace + "/" + imagestream.metadata.name;
-        if (tag)
-            id += ":" + tag.name;
-        return id;
-    }
-
-    angular.module('registry.images', [
-        'ngRoute',
-        'ui.cockpit',
-        'kubeClient',
-        'kubernetes.date',
-        'registry.tags',
-        'registryUI.images',
-    ])
-
-            .config([
-                '$routeProvider',
-                function($routeProvider) {
-                    $routeProvider
-                            .when('/images/:namespace?', {
-                                templateUrl: 'views/images-page.html',
-                                controller: 'ImagesCtrl'
-                            })
-                            .when('/images/:namespace/:target', {
-                                controller: 'ImageCtrl',
-                                templateUrl: function(params) {
-                                    var target = params['target'] || '';
-                                    if (target.indexOf(':') === -1)
-                                        return 'views/imagestream-page.html';
-                                    else
-                                        return 'views/image-page.html';
-                                }
-                            });
-                }
-            ])
-
-            .factory('registryListingScopeSetup', [
-                'imageData',
-                'imageActions',
-                'projectData',
-                'kubeSelect',
-                '$location',
-                function (data, actions, projectData, select, $location) {
-                    return function($scope, inPage) {
-                        function imageByTag (tag) {
-                            if (tag && tag.items && tag.items.length)
-                                return select().kind("Image")
-                                        .name(tag.items[0].image)
-                                        .one();
-                        }
-
-                        function deleteImageStream(stream) {
-                            var promise = actions.deleteImageStream(stream);
-
-                            /* If the promise is successful, redirect to another page */
-                            promise.then(function() {
-                                $location.path($scope.viewUrl('images'));
-                            });
-
-                            return promise;
-                        }
-
-                        function deleteTag(stream, tag) {
-                            var promise = actions.deleteTag(stream, tag);
-
-                            /* If the promise is successful, redirect to another page */
-                            promise.then(function() {
-                                var parts = [ "images", stream.metadata.namespace, stream.metadata.name ];
-                                $location.path("/" + parts.map(encodeURIComponent).join("/"));
-                            });
-
-                            return promise;
-                        }
-
-                        /* All the actions available on the $scope */
-                        angular.extend($scope, actions);
-                        angular.extend($scope, data);
-
-                        $scope.sharedImages = projectData.sharedImages;
-                        $scope.imageTagNames = data.imageTagNames;
-                        $scope.imageByTag = imageByTag;
-
-                        if (inPage) {
-                            $scope.deleteTag = deleteTag;
-                            $scope.deleteImageStream = deleteImageStream;
-                        }
-
-                        $scope.actions = {
-                            modifyImageStream: $scope.modifyImageStream,
-                            deleteImageStream: $scope.deleteImageStream,
-                            deleteTag: $scope.deleteTag,
-                            modifyProject: $scope.modifyProject,
-                        };
-                    };
-                }
-            ])
-
-            .controller('ImagesCtrl', [
-                '$scope',
-                '$location',
-                'imageData',
-                'imageActions',
-                'projectData',
-                'kubeLoader',
-                'registryListingScopeSetup',
-                'filterService',
-                function($scope, $location, data, actions, projectData, loader, registryListingScopeSetup) {
-                    $scope.sharedImages = projectData.sharedImages;
-
-                    /* Watch all the images in current namespace */
-                    data.watchImages($scope);
-
-                    $scope.imagestreams = data.allStreams();
-                    loader.listen(function() {
-                        $scope.imagestreams = data.allStreams();
-                    }, $scope);
-
-                    $scope.$on("activate", function(ev, imagestream, tag) {
-                        ev.preventDefault();
-                        $location.path('/images/' + identifier(imagestream, tag));
-                    });
-
-                    registryListingScopeSetup($scope, false);
-                }
-            ])
-
-    /*
-     * Note that we use the same controller for both the ImageStream
-     * and the Image view. This is because ngRoute can't special case
-     * routes based on the colon we use to differentiate the two in
-     * the path.
-     *
-     * ie: cockpit/ws vs. cockpit/ws:latest
-     *
-     * The |kind| on the scope tells us which is which.
-     */
-            .controller('ImageCtrl', [
-                '$scope',
-                '$location',
-                '$routeParams',
-                'kubeSelect',
-                'kubeLoader',
-                'KubeDiscoverSettings',
-                'imageData',
-                'imageActions',
-                'projectData',
-                'projectPolicy',
-                'registryListingScopeSetup',
-                function($scope, $location, $routeParams, select, loader, discoverSettings, data, actions, projectData, projectPolicy, registryListingScopeSetup) {
-                    var target = $routeParams["target"] || "";
-                    var pos = target.indexOf(":");
-
-                    /* colon contains a tag name, only set if we're looking at an image */
-                    var namespace = $routeParams["namespace"] || "";
-                    var name, tagname;
-                    if (pos === -1) {
-                        $scope.kind = "ImageStream";
-                        name = target;
-                        tagname = null;
-                    } else {
-                        $scope.kind = "Image";
-                        name = target.substr(0, pos);
-                        tagname = target.substr(pos + 1);
-                    }
-
-                    registryListingScopeSetup($scope, true);
-
-                    /* There's no way to watch a single item ... so watch them all :( */
-                    data.watchImages($scope);
-
-                    loader.listen(function() {
-                        $scope.stream = select().kind("ImageStream")
-                                .namespace(namespace)
-                                .name(name)
-                                .one();
-                        $scope.image = $scope.config = $scope.layers = $scope.labels = $scope.tag = null;
-
-                        imagestreamEachTagItem($scope.stream || {}, function(tag, item) {
-                            if (tag.tag === tagname)
-                                $scope.tag = tag;
-                        });
-
-                        if ($scope.tag)
-                            $scope.image = $scope.imageByTag($scope.tag);
-                        if ($scope.image) {
-                            $scope.names = data.imageTagNames($scope.image);
-                            $scope.config = data.imageConfig($scope.image);
-                            $scope.layers = data.imageLayers($scope.image);
-                            $scope.labels = data.imageLabels($scope.image);
-                        }
-                    }, $scope);
-
-                    $scope.$on("activate", function(ev, imagestream, tag) {
-                        ev.preventDefault();
-                        $location.path('/images/' + identifier(imagestream, tag));
-                    });
-
-                    function updateShowDockerPushCommands() {
-                        discoverSettings().then(function(settings) {
-                            projectPolicy.subjectAccessReview(namespace, settings.currentUser, 'update', 'imagestreamimages')
-                                    .then(function(allowed) {
-                                        if (allowed != $scope.showDockerPushCommands) {
-                                            $scope.showDockerPushCommands = allowed;
-                                            $scope.$applyAsync();
-                                        }
-                                    });
-                        });
-                    }
-
-                    // watch for project changes to update showDockerPushCommands, and initialize it
-                    $scope.$on("$routeUpdate", updateShowDockerPushCommands);
-                    updateShowDockerPushCommands();
-                }
-            ])
-
-            .factory("imageData", [
-                'kubeSelect',
-                'kubeLoader',
-                function(select, loader) {
-                    var watching = false;
-
-                    /* Called when we have to load images via imagestreams */
-                    loader.listen(function(objects) {
-                        for (var link in objects) {
-                            if (objects[link].kind === "ImageStream")
-                                handle_imagestream(objects[link]);
-                            if (objects[link].kind === "Image")
-                                handle_image(objects[link]);
-                        }
-                    });
-
-                    function handle_imagestream(imagestream) {
-                        var meta = imagestream.metadata || { };
-                        var status = imagestream.status || { };
-                        angular.forEach(status.tags || [ ], function(tag) {
-                            angular.forEach(tag.items || [ ], function(item) {
-                                var link = loader.resolve("Image", item.image);
-                                if (link in loader.objects)
-                                    return;
-
-                                /* An interim object while we're loading */
-                                var interim = { kind: "Image", apiVersion: "v1", metadata: { name: item.image } };
-                                loader.handle(interim);
-
-                                if (!watching)
-                                    return;
-
-                                var name = meta.name + "@" + item.image;
-                                loader.load("ImageStreamImage", name, meta.namespace).then(function(resource) {
-                                    var image = resource.image;
-                                    if (image) {
-                                        image.kind = "Image";
-                                        loader.handle(image);
-                                        handle_image(image);
-                                    }
-                                }, function(response) {
-                                    var message = response.statusText || response.message || String(response);
-                                    console.warn("couldn't load image: " + message);
-                                    interim.metadata.resourceVersion = "invalid";
-                                });
-                            });
-                        });
-                    }
-
-                    /*
-             * Create a pseudo-item with kind DockerImageManifest for
-             * each image with a dockerImageManifest that we see. Identical
-             * name to the image itself.
-             */
-                    function handle_image(image) {
-                        var item;
-                        var manifest = image.dockerImageManifest;
-                        if (manifest) {
-                            manifest = JSON.parse(manifest);
-                            angular.forEach(manifest.history || [], function(item) {
-                                if (typeof item.v1Compatibility == "string")
-                                    item.v1Compatibility = JSON.parse(item.v1Compatibility);
-                            });
-                            item = {
-                                kind: "DockerImageManifest",
-                                metadata: {
-                                    name: image.metadata.name,
-                                    selfLink: "/internal/manifests/" + image.metadata.name
-                                },
-                                manifest: manifest,
-                            };
-                            loader.handle(item);
-                        }
-                    }
-
-                    /* Load images, but fallback to loading individually */
-                    function watchImages(until) {
-                        watching = true;
-                        var a = loader.watch("images", until);
-                        var b = loader.watch("imagestreams", until);
-
-                        return {
-                            cancel: function() {
-                                a.cancel();
-                                b.cancel();
-                            }
-                        };
-                    }
-
-                    /*
-             * Filters selection to those with names that is
-             * in the given TagEvent.
-             */
-                    select.register("taggedBy", function(tag) {
-                        var i, len;
-                        var results = { };
-                        // catch condition when tag.items is null due to imagestream import error
-                        if (!tag.items)
-                            return select(null);
-                        for (i = 0, len = tag.items.length; i < len; i++)
-                            this.name(tag.items[i].image).extend(results);
-                        return select(results);
-                    });
-
-                    /*
-             * Filters selection to those with names that is in the first
-             * item in the given TagEvent.
-             */
-                    select.register("taggedFirst", function(tag) {
-                        var results = { };
-                        if (!tag.items)
-                            return select(null);
-                        if (tag.items.length)
-                            this.name(tag.items[0].image).extend(results);
-                        return select(results);
-                    });
-
-                    /*
-             * Filter that gets image streams for the given tag.
-             */
-                    select.register({
-                        name: "containsTagImage",
-                        digests: function(arg) {
-                            var ret = [];
-                            if (typeof arg == "string") {
-                                ret.push(arg);
-                            } else {
-                                imagestreamEachTagItem(arg, function(tag, item) {
-                                    ret.push(item.image + "");
-                                });
-                            }
-                            return ret;
-                        }
-                    });
-
-                    select.register("listTagNames", function(image_name) {
-                        var names = [];
-                        angular.forEach(this.containsTagImage(image_name), function(stream) {
-                            imagestreamEachTagItem(stream, function(tag, item) {
-                                if (!image_name || item.image == image_name)
-                                    names.push(stream.metadata.namespace + "/" + stream.metadata.name + ":" + tag.tag);
-                            });
-                        });
-                        return names;
-                    });
-
-                    /*
-             * Filter that gets the config object for a docker based
-             * image.
-             */
-                    select.register("dockerImageConfig", function() {
-                        var results = { };
-                        angular.forEach(this, function(image, key) {
-                            var compat;
-                            var layers = imageLayers(image) || { };
-                            if (layers[0]) {
-                                compat = layers[0].v1Compatibility;
-                                if (compat && compat.config) {
-                                    results[key] = compat.config;
-                                    return;
-                                }
-                            }
-
-                            var meta = image.dockerImageMetadata || { };
-                            if (meta.Config)
-                                results[key] = meta.Config;
-                        });
-
-                        return select(results);
-                    });
-
-                    /*
-             * Filter that gets a dict of labels for a config
-             * image.
-             */
-                    select.register("dockerConfigLabels", function() {
-                        var results = { };
-                        angular.forEach(this, function(config, key) {
-                            var labels;
-                            if (config)
-                                labels = config.Labels;
-                            if (labels)
-                                results[key] = labels;
-                        });
-                        return select(results);
-                    });
-
-                    function imageLayers(image) {
-                        if (!image)
-                            return null;
-                        var item = select().kind("DockerImageManifest")
-                                .name(image.metadata.name)
-                                .one();
-                        if (item && item.manifest && item.manifest.schemaVersion === 1)
-                            return item.manifest.history;
-                        if (image.dockerImageLayers)
-                            return image.dockerImageLayers;
-                        return null;
-                    }
-
-                    /* HACK: We really want a metadata index here */
-                    function configCommand(config) {
-                        var result = [ ];
-                        if (!config)
-                            return "";
-                        if (config.Entrypoint)
-                            result.push.apply(result, config.Entrypoint);
-                        if (config.Cmd)
-                            result.push.apply(result, config.Cmd);
-                        var string = result.join(" ");
-                        if (config.User && config.User.split(":")[0] != "root")
-                            return "$ " + string;
-                        else
-                            return "# " + string;
-                    }
-
-                    return {
-                        watchImages: watchImages,
-                        allStreams: function allStreams() {
-                            return select().kind("ImageStream");
-                        },
-                        imageLayers: imageLayers,
-                        imageConfig: function imageConfig(image) {
-                            return select(image).dockerImageConfig()
-                                    .one() || { };
-                        },
-                        imageTagNames: function imageTagNames(image) {
-                            return select().kind("ImageStream")
-                                    .listTagNames(image.metadata.name);
-                        },
-                        imageLabels: function imageLabels(image) {
-                            var labels = select(image).dockerImageConfig()
-                                    .dockerConfigLabels()
-                                    .one();
-                            if (labels && angular.equals({ }, labels))
-                                labels = null;
-                            return labels;
-                        },
-                        configCommand: configCommand,
-                    };
-                }
-            ])
-
-            .factory('imageActions', [
-                '$modal',
-                '$location',
-                function($modal, $location) {
-                    function deleteImageStream(stream) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'ImageStreamDeleteCtrl',
-                            templateUrl: 'views/imagestream-delete.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { stream: stream };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function createImageStream() {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'ImageStreamModifyCtrl',
-                            templateUrl: 'views/imagestream-modify.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function modifyImageStream(stream) {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'ImageStreamModifyCtrl',
-                            templateUrl: 'views/imagestream-modify.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { stream: stream };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    function deleteTag(stream, tag) {
-                        var modal = $modal.open({
-                            animation: false,
-                            controller: 'ImageDeleteCtrl',
-                            templateUrl: 'views/image-delete.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { stream: stream, tag: tag };
-                                }
-                            },
-                        });
-
-                        return modal.result;
-                    }
-
-                    function modifyProject(project) {
-                        $location.path("/projects/" + project);
-                        return false;
-                    }
-
-                    return {
-                        createImageStream: createImageStream,
-                        modifyImageStream: modifyImageStream,
-                        deleteImageStream: deleteImageStream,
-                        deleteTag: deleteTag,
-                        modifyProject: modifyProject,
-                    };
-                }
-            ])
-
-            .controller("ImageStreamDeleteCtrl", [
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                function($scope, $instance, dialogData, methods) {
-                    angular.extend($scope, dialogData);
-
-                    $scope.performDelete = function performDelete() {
-                        return methods.delete($scope.stream);
-                    };
-                }
-            ])
-
-            .controller("ImageStreamModifyCtrl", [
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "imageTagData",
-                "kubeMethods",
-                "filterService",
-                "gettextCatalog",
-                function($scope, $instance, dialogData, tagData, methods, filter, gettextCatalog) {
-                    var stream = dialogData.stream || { };
-                    var meta = stream.metadata || { };
-                    var spec = stream.spec || { };
-                    const _ = gettextCatalog.getString.bind(gettextCatalog);
-
-                    var populate = "none";
-                    if (spec.dockerImageRepository)
-                        populate = "pull";
-                    if (spec.tags)
-                        populate = "tags";
-
-                    var fields = {
-                        name: meta.name || "",
-                        project: meta.namespace || filter.namespace() || "",
-                        populate: populate,
-                        pull: spec.dockerImageRepository || "",
-                        tags: tagData.parseSpec(spec),
-                        insecure: hasInsecureTag(spec),
-                    };
-
-                    $scope.fields = fields;
-                    $scope.labels = {
-                        populate: {
-                            none: _("Don't pull images automatically"),
-                            pull: _("Sync all tags from a remote image repository"),
-                            tags: _("Pull specific tags from another image repository"),
-                        }
-                    };
-
-                    $scope.placeholder = _("eg: my-image-stream");
-
-                    /* During creation we have a different label */
-                    if (!dialogData.stream)
-                        $scope.labels.populate.none = _("Create empty image stream");
-
-                    function performModify() {
-                        var data = {
-                            apiVersion: "v1",
-                            kind: "ImageStream",
-                            metadata: { annotations:  { "openshift.io/image.dockerRepositoryCheck" : null } }
-                        };
-
-                        if (fields.populate == "pull")
-                            data.spec = { dockerImageRepository: fields.pull.trim(), };
-                        else if (fields.populate == "tags")
-                            data.spec = tagData.buildSpec(fields.tags, data.spec, fields.insecure, fields.pull.trim());
-                        else
-                            data.spec = { dockerImageRepository: null, tags: null };
-
-                        return methods.patch(stream, data);
-                    }
-
-                    function performCreate() {
-                        var data = {
-                            apiVersion: "v1",
-                            kind: "ImageStream",
-                            metadata: {
-                                name: fields.name.trim(),
-                                namespace: fields.project.trim(),
-                            }
-                        };
-
-                        if (fields.populate == "pull")
-                            data.spec = { dockerImageRepository: fields.pull.trim(), };
-                        else if (fields.populate == "tags")
-                            data.spec = tagData.buildSpec(fields.tags, data.spec, fields.insecure, fields.pull.trim());
-
-                        return methods.check(data, {
-                            "metadata.name": "#imagestream-modify-name",
-                            "metadata.namespace": "#imagestream-modify-project",
-                        }).then(function() {
-                            return methods.create(data, fields.project);
-                        });
-                    }
-
-                    function hasInsecureTag(spec) {
-                        // loop through tags, check importPolicy.insecure boolean
-                        // if one tag is insecure the intent is the imagestream is insecure
-                        var insecure;
-                        if (spec) {
-                            for (var tag in spec.tags) {
-                                if (spec.tags[tag].importPolicy.insecure) {
-                                    insecure = spec.tags[tag].importPolicy.insecure;
-                                    break;
-                                }
-                            }
-                        }
-                        return insecure;
-                    }
-
-                    $scope.performCreate = performCreate;
-                    $scope.performModify = performModify;
-                    $scope.hasInsecureTag = hasInsecureTag;
-
-                    $scope.projects = filter.namespaces;
-                    angular.extend($scope, dialogData);
-                }
-            ])
-
-            .controller("ImageDeleteCtrl", [
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                function($scope, $instance, dialogData, methods) {
-                    angular.extend($scope, dialogData);
-
-                    $scope.performDelete = function performDelete() {
-                        var name = $scope.stream.metadata.name + ":" + $scope.tag.tag;
-                        return methods.delete("ImageStreamTag", name, $scope.stream.metadata.namespace);
-                    };
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/kube-client-cockpit.js b/pkg/kubernetes/scripts/kube-client-cockpit.js
deleted file mode 100644
index 6d1b6b0f6..000000000
--- a/pkg/kubernetes/scripts/kube-client-cockpit.js
+++ /dev/null
@@ -1,1229 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-    var cockpit = require('cockpit');
-
-    require('./kube-client');
-
-    function debug() {
-        if (window.debugging == "all" || window.debugging == "kube")
-            console.debug.apply(console, arguments);
-    }
-
-    function updateMessage(response) {
-        if (!response)
-            return;
-
-        var obj;
-        try {
-            obj = JSON.parse(response.data);
-        } catch (e) {
-            // Some kubernetes versions message up json reponses
-            if (response.data && response.headers &&
-                response.headers["Content-Type"] === "text/plain") {
-                obj = { message: response.data };
-            } else {
-                return;
-            }
-        }
-
-        if (obj && obj.message)
-            response.message = response.statusText = obj.message;
-    }
-
-    /*
-     * Currently we assume that the certificates in the kube config
-     * file are:
-     *
-     * base64(PEM(data))
-     *
-     * Since our http-stream2 expects PEM certificates (although they're
-     * nasty, they're better than all the alternatives) so we strip out
-     * the outer base64 layer.
-     */
-
-    function parseCertOption(object, option) {
-        var blob = object[option + "-data"];
-        if (blob !== undefined)
-            return { data: window.atob(blob) };
-
-        var file = object[option];
-        if (file !== undefined)
-            return { file: file };
-
-        return undefined;
-    }
-
-    function basicToken(user, pass) {
-        return window.btoa(window.unescape(encodeURIComponent(user + ":" + pass)));
-    }
-
-    angular.module("kubeClient.cockpit", [
-        "kubeClient",
-    ])
-
-            .factory("CockpitKubeWatch", [
-                "$q",
-                "KUBE_SCHEMA",
-                "cockpitKubeDiscover",
-                function($q, KUBE_SCHEMA, cockpitKubeDiscover) {
-                    return function CockpitKubeWatch(path, callback) {
-                        debug("creating watch:", path);
-
-                        /* Used to track the last resource for restarting query */
-                        var lastResource;
-
-                        /* Whether close has been called */
-                        var stopping = false;
-
-                        /* The current HTTP request */
-                        var channel = null;
-
-                        /* The http options */
-                        var http = null;
-
-                        /* Waiting to do the next http request */
-                        var wait = null;
-
-                        /*
-                 * Loading logic.
-                 *
-                 * For performance, we only use watches here. So we have
-                 * to guess when loading is finished and when updates begin.
-                 * There are several heuristics:
-                 *
-                 *  1) Receiving a MODIFY or DELETE means loading has finished.
-                 *  2) A timeout after last ADDED
-                 *  3) Error or connection closed.
-                 *
-                 * Remember that a watch object can restart its request for a number
-                 * of reasons, and so the loading/loaded state may go back and forth.
-                 *
-                 * When transitioning from a loading to a loaded state, we have to:
-                 *  a) Notify the caller if not already done
-                 *  b) See if any objects present before load need to be removed.
-                 */
-
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-                        var loaded = false;
-                        var objects = { };
-                        var previous;
-                        var loading;
-
-                        function loadBegin(full) {
-                            if (full) {
-                                previous = objects;
-                                objects = { };
-                            } else {
-                                previous = null;
-                            }
-                            loadPoke(true);
-                        }
-
-                        function loadPoke(force) {
-                            if (force || loading !== undefined) {
-                                window.clearTimeout(loading);
-                                loading = window.setTimeout(loadFinish, 100);
-                            }
-                        }
-
-                        function loadFinish(ex) {
-                            if (loaded)
-                                return;
-                            loaded = true;
-
-                            var key, prev;
-                            var frames = [];
-                            prev = previous;
-                            previous = null;
-                            for (key in prev) {
-                                if (!(key in objects))
-                                    frames.push({ type: "DELETED", object: prev[key] });
-                            }
-
-                            /* Simulated delete frames */
-                            if (frames.length)
-                                callback(frames);
-
-                            /* Tell callback to flush */
-                            callback([]);
-
-                            if (ex)
-                                defer.reject(ex);
-                            else
-                                defer.resolve();
-                        }
-
-                        /*
-                 * Each change is sent as an individual line from Kubernetes
-                 * but they may not arrive exactly that way, so we buffer
-                 * and split lines again.
-                 */
-
-                        var buffer;
-                        function handleWatch(data) {
-                            if (buffer)
-                                data = buffer + data;
-
-                            var lines = data.split("\n");
-                            var i;
-                            var length = lines.length - 1;
-
-                            /* Last line is incomplete save for later */
-                            buffer = lines[length];
-
-                            var frames = [];
-
-                            /* Process all the others */
-                            var frame, object;
-                            for (i = 0; i < length; i++) {
-                                try {
-                                    frame = JSON.parse(lines[i]);
-                                } catch (ex) {
-                                    console.warn(lines[i], ex);
-                                    channel.close();
-                                    continue;
-                                }
-
-                                object = frame.object;
-                                if (!object) {
-                                    console.warn("invalid watch without object", frame);
-                                    continue;
-                                }
-
-                                /* The watch failed, likely due to invalid resourceVersion */
-                                if (frame.type == "ERROR") {
-                                    if (lastResource) {
-                                        lastResource = null;
-                                        startWatch();
-                                    }
-                                    continue;
-                                }
-
-                                var meta = object.metadata;
-                                if (!meta || (!meta.uid && object.kind !== "Project") || !object.kind) {
-                                    console.warn("invalid kube object: ", object);
-                                    continue;
-                                }
-
-                                lastResource = meta.resourceVersion;
-
-                                /* We track objects here so we can restart watches */
-                                var uid = meta.uid;
-                                if (frame.type == "DELETED")
-                                    delete objects[uid];
-                                else
-                                    objects[uid] = object;
-
-                                debug(frame.type, object.kind, meta.uid);
-                                frames.push(frame);
-                            }
-
-                            callback(frames);
-                            loadPoke();
-                        }
-
-                        function startWatch() {
-                            if (channel)
-                                return;
-
-                            var full = true;
-                            var uri = path + "?watch=true";
-
-                            /*
-                     * If we have a last resource we can guarantee that we don't miss
-                     * any objects or changes to objects. If we don't have one, then we
-                     * have to list everything again. Still watch at the same time though.
-                     */
-                            if (lastResource) {
-                                uri += "&resourceVersion=" + encodeURIComponent(lastResource);
-                                full = false;
-                            }
-
-                            /*
-                     * As a precaution, watch must take at least 1 second
-                     * to complete. Otherwise we could be in a tight loop here.
-                     * eg: if the API of Kubernetes changes unpredictably.
-                     */
-                            var blocked = false;
-                            window.setTimeout(function() {
-                                blocked = true;
-                            }, 1000);
-
-                            var opts = angular.extend({ }, http, {
-                                path: uri,
-                                method: "GET"
-                            });
-
-                            channel = cockpit.channel(opts);
-
-                            var response = { };
-                            var failed = false;
-                            channel.addEventListener("control", function(ev, options) {
-                                if (options.command == "response") {
-                                    response = options;
-                                    if (response.status > 299)
-                                        failed = true;
-                                    loadBegin(full);
-                                }
-                            });
-
-                            channel.addEventListener("message", function(ev, payload) {
-                                if (failed)
-                                    response.data = (response.data || "") + payload;
-                                else
-                                    handleWatch(payload);
-                            });
-
-                            channel.addEventListener("close", function(ev, options) {
-                                channel = null;
-                                loading = false;
-                                if (stopping)
-                                    return;
-
-                                var msg = "watching " + path + " failed: ";
-                                var problem = options.problem;
-                                var status = response.status;
-
-                                if (problem) {
-                                    msg += problem;
-                                    if (problem == "disconnected")
-                                        debug(msg);
-                                    else
-                                        console.warn(msg);
-                                    response.problem = problem;
-                                    response.status = 999;
-                                    loadFinish(response);
-                                } else if (failed) {
-                                    updateMessage(response);
-                                    msg += (response.message || response.reason || status);
-                                    if (status === 404 || status === 410 || status === 403) {
-                                        debug(msg);
-                                        loadFinish(response);
-                                        return; /* don't try watch again if we get a 404/410/403 */
-                                    } else {
-                                        console.warn(msg);
-                                    }
-                                    loadFinish(response);
-                                } else if (!blocked) {
-                                    console.warn("watching kube " + path + " didn't block");
-                                } else {
-                                    startWatch();
-                                    return;
-                                }
-
-                                startWatchLater();
-                            });
-
-                            /* No http request body */
-                            channel.control({ command: "done" });
-                        }
-
-                        function startWatchLater() {
-                            if (!wait) {
-                                wait = window.setTimeout(function() {
-                                    wait = null;
-                                    startWatch();
-                                }, 5000);
-                            }
-                        }
-
-                        $q.when(cockpitKubeDiscover(), function(options) {
-                            http = options;
-                            startWatch();
-                        }, function(resp) {
-                            loadFinish(resp);
-                        });
-
-                        promise.cancel = function cancel(ex) {
-                            stopping = true;
-                            var problem;
-                            if (channel) {
-                                if (ex)
-                                    problem = ex.problem;
-                                channel.close(problem || "disconnected");
-                                channel = null;
-                            }
-                            window.clearTimeout(wait);
-                            wait = null;
-                            http = null;
-                            loadFinish(ex);
-                        };
-
-                        return promise;
-                    };
-                }
-            ])
-
-    /*
-     * A WebSocket factory for the kubernetes-container-terminal
-     * that uses the kubectl command with a fake websocket
-     */
-            .factory("CockpitKubectlWebSocket", [
-                function() {
-                    function decode(href, options) {
-                        var pos = href.indexOf('?');
-                        var first = href;
-                        var path;
-                        if (pos === -1)
-                            first = href;
-                        else
-                            first = href.substr(0, pos);
-
-                        path = first.split('/').map(decodeURIComponent);
-
-                        if (pos !== -1) {
-                            angular.forEach(href.substring(pos + 1).split("&"), function(opt) {
-                                var last;
-                                var parts = opt.split('=');
-                                var name = decodeURIComponent(parts[0]);
-                                var value = decodeURIComponent(parts[1]);
-                                if (options.hasOwnProperty(name)) {
-                                    last = options[name];
-                                    if (!angular.isArray(last))
-                                        last = options[name] = [ last ];
-                                    last.push(value);
-                                } else {
-                                    options[name] = value;
-                                }
-                            });
-                        }
-
-                        return path;
-                    }
-
-                    function parser(url) {
-                        var options = { };
-                        var path = decode(url, options);
-
-                        var command = [ ];
-                        var args = [ ];
-                        var namespace = "default";
-                        var container = null;
-                        var cmd = "log";
-                        var pod = "";
-
-                        var i, len;
-                        for (i = 0, len = path.length; i < len; i++) {
-                            if (path[i] === "namespaces") {
-                                namespace = path[++i];
-                            } else if (path[i] === "pods") {
-                                pod = path[++i];
-                                if (path[i + 1] == "exec")
-                                    cmd = "exec";
-                                else if (path[i + 1] == "log")
-                                    cmd = "logs";
-                            }
-                        }
-
-                        for (i in options) {
-                            if (i == "container") {
-                                container = options[i];
-                            } else if (i == "command") {
-                                if (angular.isArray(options[i]))
-                                    command = options[i];
-                                else
-                                    command.push(options[i]);
-                            } else if (i == "stdin" || i == "tty" || i == "follow") {
-                                args.push("--" + i);
-                            }
-                        }
-
-                        var ret = [ "kubectl", cmd, "--namespace=" + namespace ];
-                        if (container)
-                            ret.push("--container=" + container);
-                        ret.push.apply(ret, args);
-                        ret.push(pod, "--");
-                        ret.push.apply(ret, command);
-                        return ret;
-                    }
-
-                    return function KubeFakeWebSocket(url, protocols) {
-                        var cmd = parser(url);
-                        var base64 = false;
-
-                        /* A fake WebSocket */
-                        var channel;
-                        var state = 0; /* CONNECTING */
-                        var ws = { };
-                        cockpit.event_target(ws);
-
-                        function open() {
-                            channel = cockpit.channel({
-                                payload: "stream",
-                                spawn: cmd,
-                                pty: true
-                            });
-
-                            channel.addEventListener("close", function(ev, options) {
-                                channel = null;
-
-                                state = 3;
-                                var cev = new Event("close", { bubbles: false, cancelable: false });
-                                ws.dispatchEvent(cev);
-                            });
-
-                            channel.addEventListener("message", function(ev, data) {
-                                if (base64)
-                                    data = "1" + window.btoa(data);
-                                var mev = new window.MessageEvent('message', { data: data });
-                                ws.dispatchEvent(mev);
-                            });
-
-                            state = 1;
-                            var oev = new Event("open", { bubbles: false, cancelable: false });
-                            ws.dispatchEvent(oev);
-                        }
-
-                        function fail() {
-                            var ev = new Event("close", { bubbles: false, cancelable: false });
-                            ws.dispatchEvent(ev);
-                        }
-
-                        function close(code, reason) {
-                            if (channel)
-                                channel.close(reason);
-                        }
-
-                        function send(data) {
-                            if (base64) {
-                                /*
-                         * HACK: container-terminal sends Width/Height commands but
-                         * many of the kubernetes implementations don't yet support
-                         * that. So filter them out here for now.
-                         */
-                                if (data[0] === "4")
-                                    return;
-                                data = window.atob(data.slice(1));
-                            }
-
-                            if (channel)
-                                channel.send(data);
-                        }
-
-                        var valid = true;
-                        if (protocols) {
-                            if (angular.isArray(protocols))
-                                valid = base64 = protocols.indexOf("base64.channel.k8s.io") !== -1;
-                            else
-                                valid = base64 = protocols === "base64.channel.k8s.io";
-                        }
-
-                        /* A fake WebSocket */
-                        Object.defineProperties(ws, {
-                            binaryType: { value: "arraybuffer" },
-                            bufferedAmount: { value: 0 },
-                            extensions: { value: "" },
-                            protocol: { value: base64 ? "base64.channel.k8s.io" : "" },
-                            readyState: { get: function() { return state } },
-                            url: { value: url },
-                            close: { value: close },
-                            send: { value: send },
-                        });
-
-                        if (valid) {
-                            window.setTimeout(open);
-                        } else {
-                            console.warn("Unsupported kubernetes container WebSocket subprotocol: " + protocols);
-                            window.setTimeout(fail);
-                        }
-
-                        return ws;
-                    };
-                }
-            ])
-
-            .factory("CockpitKubeSocket", [
-                "$q",
-                "$injector",
-                function($q, $injector) {
-                    return function CockpitKubeSocket(url, config) {
-                        var base64 = false;
-                        var connect;
-                        var state = 0; /* CONNECTING */
-                        var ws = { };
-                        var channel;
-
-                        var protocols = [];
-                        if (config && config.protocols) {
-                            protocols = config.protocols;
-                            if (!angular.isArray(protocols))
-                                protocols = [ String(config.protocols) ];
-                        }
-
-                        /*
-                 * If we're called with fully formed options, then don't do
-                 * connect discovery stuff. Otherwise ask our connect service
-                 * for connection info, and do discovery.
-                 */
-                        if (config && config.port)
-                            connect = config;
-                        else
-                            connect = $injector.get('cockpitKubeDiscover')();
-
-                        function close(code, reason) {
-                            if (channel)
-                                channel.close(reason);
-                        }
-
-                        function send(data) {
-                            /*
-                     * HACK: container-terminal sends Width/Height commands but
-                     * many of the kubernetes implementations don't yet support
-                     * that. So filter them out here for now.
-                     */
-                            if (base64 && data[0] === "4")
-                                return;
-
-                            if (channel)
-                                channel.send(data);
-                        }
-
-                        /* A fake WebSocket */
-                        Object.defineProperties(ws, {
-                            binaryType: { value: "arraybuffer" },
-                            bufferedAmount: { value: 0 },
-                            extensions: { value: "" },
-                            protocol: { value: protocols[0] },
-                            readyState: { get: function() { return state } },
-                            url: { value: url },
-                            close: { value: close },
-                            send: { value: send },
-                        });
-
-                        base64 = protocols.indexOf("base64.channel.k8s.io") !== -1;
-
-                        $q.when(connect, function connected(options) {
-                            cockpit.event_target(ws);
-
-                            channel = cockpit.channel(angular.extend({ }, options, {
-                                payload: "websocket-stream1",
-                                path: url,
-                                protocols: protocols.length > 0 ? protocols : undefined,
-                            }));
-
-                            channel.addEventListener("close", function(ev, options) {
-                                channel = null;
-
-                                state = 3;
-                                var cev = new Event("close", { bubbles: false, cancelable: false });
-                                ws.dispatchEvent(cev);
-                            });
-
-                            channel.addEventListener("message", function(ev, data) {
-                                var mev = new window.MessageEvent('message', { data: data });
-                                ws.dispatchEvent(mev);
-                            });
-
-                            state = 1;
-                            var oev = new Event("open", { bubbles: false, cancelable: false });
-                            ws.dispatchEvent(oev);
-                        });
-
-                        return ws;
-                    };
-                }
-            ])
-
-            .factory("CockpitKubeRequest", [
-                "$q",
-                "$injector",
-                function($q, $injector) {
-                    var CONTENT_TYPE = "Content-Type";
-                    var JSON_TYPE = "application/json";
-                    return function CockpitKubeRequest(method, path, body, config) {
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-                        var connect, channel;
-
-                        var heads = { };
-                        if (body && typeof body == "object") {
-                            body = JSON.stringify(body);
-                            heads[CONTENT_TYPE] = JSON_TYPE;
-                        }
-
-                        if (!config)
-                            config = { };
-
-                        /*
-                 * If we're called with fully formed options, then don't do
-                 * connect discovery stuff. Otherwise ask our connect service
-                 * for connection info, and do discovery.
-                 */
-                        if (config && config.port)
-                            connect = config;
-                        else
-                            connect = $injector.get('cockpitKubeDiscover')();
-
-                        $q.when(connect, function connected(options) {
-                            var opts = angular.extend({ }, config, options, {
-                                path: path,
-                                method: method,
-                                payload: "http-stream2"
-                            });
-
-                            opts.headers = angular.extend(heads, config.headers || { }, options.headers || { });
-
-                            debug("request:", method, path, opts);
-                            channel = cockpit.channel(opts);
-
-                            var response = { };
-                            channel.addEventListener("control", function(ev, options) {
-                                if (options.command == "response") {
-                                    response = options;
-                                    response.statusText = response.reason;
-                                }
-                            });
-
-                            channel.addEventListener("message", function(ev, payload) {
-                                response.data = (response.data || "") + payload;
-                            });
-
-                            channel.addEventListener("close", function(ev, options) {
-                                channel = null;
-
-                                response.options = options;
-                                if (options.problem) {
-                                    response.problem = response.statusText = options.problem;
-                                    response.status = 999;
-                                }
-
-                                var headers = response.headers || { };
-                                var content_type = headers[CONTENT_TYPE] || headers[CONTENT_TYPE.toLowerCase()] || "";
-                                if (content_type.lastIndexOf(JSON_TYPE, 0) === 0) {
-                                    try {
-                                        response.data = JSON.parse(response.data);
-                                    } catch (ex) {
-                                        /* it's not JSON, just leave as text */
-                                    }
-                                }
-
-                                if (response.status > 299) {
-                                    updateMessage(response);
-                                    defer.reject(response);
-                                } else {
-                                    defer.resolve(response);
-                                }
-                            });
-
-                            if (body)
-                                channel.send(body);
-                            channel.control({ command: "done" });
-
-                            /* Failed to connect */
-                        }, function failed(response) {
-                            defer.reject(response);
-                        });
-
-                        /* Helpful function on the promise */
-                        promise.cancel = function cancel() {
-                            if (connect.cancel)
-                                connect.cancel();
-                            if (channel)
-                                channel.close("cancelled");
-                        };
-
-                        return promise;
-                    };
-                }
-            ])
-
-            .factory("cockpitRunCommand", [
-                '$q',
-                function($q) {
-                    return function runCommand(args) {
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-                        var channel = cockpit.channel({
-                            "payload": "stream",
-                            "spawn": args,
-                            "err": "message"
-                        });
-
-                        var result = "";
-                        channel.addEventListener("message", function(ev, payload) {
-                            result += payload;
-                        });
-                        channel.addEventListener("close", function(ev, options) {
-                            channel = null;
-                            if (options.problem)
-                                defer.reject(options);
-                            else
-                                defer.resolve(result);
-                        });
-
-                        promise.cancel = function cancel(options) {
-                            if (channel)
-                                channel.close(options || "cancelled");
-                        };
-
-                        promise.send = function send(data) {
-                            if (channel)
-                                channel.send(data);
-                        };
-
-                        return promise;
-                    };
-                }
-            ])
-
-            .factory("cockpitKubectlConfig", [
-                '$q',
-                'cockpitRunCommand',
-                function($q, runCommand) {
-                    function generateKubeOptions(cluster, user) {
-                        var parser, token, provider;
-                        var options = { port: 8080, headers: { } };
-
-                        if (cluster && cluster.server) {
-                            parser = document.createElement('a');
-                            parser.href = cluster.server;
-                            if (parser.hostname)
-                                options.address = parser.hostname;
-                            if (parser.port)
-                                options.port = parseInt(parser.port, 10);
-                            if (parser.protocol == 'https:') {
-                                if (!parser.port || parser.port === "0")
-                                    options.port = parser.href == cluster.server ? 6443 : 443;
-
-                                options.tls = { };
-                                options.tls.authority = parseCertOption(cluster, "certificate-authority");
-                                options.tls.validate = !cluster["insecure-skip-tls-verify"];
-                            }
-                        }
-
-                        if (user) {
-                            token = user.token;
-                            provider = user["auth-provider"] || {};
-                            if (provider.config) {
-                                if (provider.config['access-token'])
-                                    token = provider.config['access-token'];
-                                else if (provider.config['token'])
-                                    token = provider.config['token'];
-                            }
-
-                            if (token)
-                                options.headers["Authorization"] = "Bearer " + token;
-                            if (user.username)
-                                options.headers["Authorization"] = "Basic " + basicToken(user.username, user.password || "");
-                            if (options.tls) {
-                                options.tls.certificate = parseCertOption(user, "client-certificate");
-                                options.tls.key = parseCertOption(user, "client-key");
-                            }
-                        }
-
-                        return options;
-                    }
-
-                    function parseKubeConfig(data, contextName) {
-                        var config, options;
-
-                        try {
-                            config = JSON.parse(data);
-                        } catch (ex) {
-                            console.warn("received invalid kubectl config", ex);
-                            return null;
-                        }
-
-                        if (!contextName)
-                            contextName = config["current-context"];
-                        var contexts = config["contexts"] || [];
-
-                        /* Find the cluster info */
-                        var userName, clusterName;
-                        contexts.forEach(function(info) {
-                            if (info.name === contextName) {
-                                var context = info.context || { };
-                                userName = context.user;
-                                clusterName = context.cluster;
-                            }
-                        });
-
-                        /* Find the user info */
-                        var user;
-                        var users = config["users"] || [];
-                        users.forEach(function(info) {
-                            if (info.name === userName)
-                                user = info.user;
-                        });
-
-                        /* Find the cluster info */
-                        var cluster;
-                        var clusters = config["clusters"] || [];
-                        clusters.forEach(function(info) {
-                            if (info.name == clusterName)
-                                cluster = info.cluster;
-                        });
-
-                        options = generateKubeOptions(cluster, user);
-                        debug("parsed kube config", options);
-                        return options;
-                    }
-
-                    function read() {
-                        var cmd = ["kubectl", "config", "view", "--output=json", "--raw"];
-
-                        /* Call kubectl minified config view. That only outputs
-                 * the objects that would be used by a connection */
-                        return runCommand(["kubectl", "config", "view", "--minify", "--output=json"])
-                                .then(function (data) {
-                                    var p;
-                                    var auth_provider;
-                                    var user;
-
-                                    /* If the default data has a 'auth-provider'
-                         * section then call kubectl version to try to
-                         * get it to fill in any token data.
-                         */
-                                    try {
-                                        user = JSON.parse(data)["users"][0];
-                                        if (user && user['user'])
-                                            auth_provider = user['user']['auth-provider'];
-                                    } catch (ex) {
-                                        console.warn("received invalid kubectl config", ex);
-                                    }
-
-                                    if (auth_provider) {
-                                        p = runCommand(["kubectl", "version"])
-                                                .then(function () {
-                                                    return runCommand(cmd);
-                                                }, function () {
-                                                    return runCommand(cmd);
-                                                });
-                                    } else {
-                                        p = runCommand(cmd);
-                                    }
-
-                                    return p;
-                                });
-                    }
-
-                    return {
-                        read: read,
-                        parseKubeConfig: parseKubeConfig,
-                        generateKubeOptions: generateKubeOptions,
-                    };
-                }
-            ])
-
-            .factory("cockpitKubeDiscover", [
-                "$q",
-                "CockpitKubeRequest",
-                "cockpitKubectlConfig",
-                "cockpitConnectionInfo",
-                "cockpitBrowserStorage",
-                function($q, CockpitKubeRequest, cockpitKubectlConfig, info, browser) {
-                    var defer = null;
-
-                    return function cockpitKubeDiscover(force) {
-                        if (!force && defer)
-                            return defer.promise;
-
-                        var last, req, kubectl, loginOptions;
-                        var loginData = browser.localStorage.getItem('login-data', true);
-                        defer = $q.defer();
-
-                        var schemes = [
-                            { port: 8080 },
-                            { port: 8443, tls: { } },
-                            { port: 6443, tls: { } },
-                        ];
-
-                        function step(options, kubeConfig) {
-                            if (!options)
-                                options = schemes.shift();
-
-                            /* No further ports to try? */
-                            if (!options) {
-                                last.statusText = cockpit.gettext("Couldn't find running API server");
-                                last.problem = "not-found";
-                                defer.reject(last);
-                                return;
-                            }
-
-                            /* If options is a function call it, the function is
-                     * responsible to call step again when ready */
-                            if (typeof options === "function") {
-                                options();
-                                return;
-                            }
-
-                            options.payload = "http-stream2";
-                            debug("trying kube at:", options);
-                            req = new CockpitKubeRequest("GET", "/api", "", options);
-                            req.then(function(response) {
-                                req = null;
-                                var resp = response.data;
-                                if (resp && resp.versions) {
-                                    debug("discovered kube api", resp);
-                                    if (kubeConfig) {
-                                        info.kubeConfig = kubeConfig;
-                                        if (kubectl)
-                                            info.type = "kubectl";
-                                        else
-                                            info.type = "sessionData";
-                                    } else {
-                                        info.type = "open";
-                                    }
-
-                                    defer.resolve(options);
-                                } else {
-                                    debug("not an api endpoint:", options);
-                                    last = response;
-                                    kubectl = null;
-                                    step();
-                                }
-                            })
-                                    .catch(function(response) {
-                                        req = null;
-                                        kubectl = null;
-                                        last = response;
-
-                                        if (response.problem === "not-found") {
-                                            debug("api endpoint not found on:", options);
-                                            step();
-                                        } else {
-                                            debug("connecting to kube failed:", response);
-                                            defer.reject(response);
-                                        }
-                                    });
-                        }
-
-                        function kubectlStep() {
-                            kubectl = cockpitKubectlConfig.read()
-                                    .then(function(data) {
-                                        var options = cockpitKubectlConfig.parseKubeConfig(data);
-                                        step(options, options ? JSON.parse(data) : null);
-                                    })
-                                    .catch(function(options) {
-                                        console.warn("kubectl failed: " + (options.message || options.problem));
-                                        step();
-                                    });
-                        }
-
-                        if (force && typeof force === 'object') {
-                            schemes = [ force ];
-                            step();
-                        } else if (force === "kubectl") {
-                            schemes = [ kubectlStep ];
-                            step();
-                        } else {
-                            schemes.unshift(kubectlStep);
-                            if (loginData)
-                                loginOptions = cockpitKubectlConfig.parseKubeConfig(loginData);
-                            step(loginOptions, loginOptions ? JSON.parse(loginData) : null);
-                        }
-
-                        defer.promise.cancel = function cancel() {
-                            if (kubectl && kubectl.cancel)
-                                kubectl.cancel("cancelled");
-
-                            if (req)
-                                req.close("cancelled");
-                        };
-                        return defer.promise;
-                    };
-                }
-            ])
-
-            .factory("CockpitEnvironment", [
-                "$q",
-                function($q) {
-                    var defer = $q.defer();
-                    var settings = null;
-                    return function cockpitKubeSettings() {
-                        if (settings !== null)
-                            return defer.promise;
-                        var channel = cockpit.channel({ payload: "dbus-json3", bus: "internal" });
-                        channel.addEventListener("close", function(ev, options) {
-                            if (options.problem) {
-                                console.warn("couldn't retrieve environment:", options.problem);
-                                defer.reject(options);
-                            } else {
-                                defer.resolve(settings);
-                            }
-                        });
-                        channel.addEventListener("message", function(ev, data) {
-                            var result = JSON.parse(data);
-                            if (result.reply) {
-                                settings = result.reply[0][0].Variables.v;
-                                channel.close(null);
-                            } else if (result.error) {
-                                console.warn("error retrieving environment:", result.error);
-                                channel.close("internal-error");
-                            }
-                        });
-                        channel.send(JSON.stringify({
-                            id: "cookie",
-                            call: [ "/environment", "org.freedesktop.DBus.Properties", "GetAll",
-                                [ "cockpit.Environment" ] ]
-                        }));
-                        return defer.promise;
-                    };
-                }
-            ])
-
-            .factory("cockpitKubeDiscoverSettings", [
-                "$q",
-                "CockpitKubeRequest",
-                "cockpitKubeDiscover",
-                "CockpitEnvironment",
-                'kubeLoader',
-                'cockpitConnectionInfo',
-                function($q, CockpitKubeRequest, cockpitKubeDiscover,
-                    CockpitEnvironment, loader, info) {
-                    var promise = null;
-                    return function kubeDiscoverSettings(force) {
-                        if (!force && promise)
-                            return promise;
-
-                        var settings = {
-                            registry: {
-                                host: "registry",
-                                host_explicit: false
-                            },
-                            flavor: "kubernetes",
-                            isAdmin: false,
-                            currentUser: null,
-                            canChangeConnection: false
-                        };
-
-                        var env_p = CockpitEnvironment()
-                                .then(function(result) {
-                                    var regHost = result["REGISTRY_HOST"];
-                                    if (regHost) {
-                                        settings.registry.host = regHost;
-                                        settings.registry.host_explicit = true;
-                                    }
-                                    var openshifthost = result["OPENSHIFT_OAUTH_PROVIDER_URL"];
-                                    if (openshifthost) {
-                                        settings.registry.openshifthost = openshifthost.replace(/^http(s?):\/\//i, "");
-                                        settings.registry.openshifthost_explicit = true;
-                                    }
-                                }, function(ex) {});
-
-                        var discover_p = cockpitKubeDiscover(force)
-                                .then(function(options) {
-                                    var req = new CockpitKubeRequest("GET", "/oapi/v1/users/~", "", options)
-                                            .then(function(response) {
-                                                settings.flavor = "openshift";
-                                                if (response)
-                                                    settings.currentUser = response.data;
-                                            }, function () {
-                                                settings.flavor = "kubernetes";
-                                            });
-
-                                    var watch = loader.watch("namespaces")
-                                            .then(function () {
-                                                settings.isAdmin = true;
-                                            }, function () {
-                                                settings.isAdmin = false;
-                                            });
-
-                                    var authorization;
-                                    /* See if we have a bearer token to use */
-                                    if (options.headers) {
-                                        authorization = (options.headers['Authorization'] || "").trim();
-                                        if (authorization.toLowerCase().indexOf("bearer ") === 0)
-                                            settings.registry.password = authorization.substr(7).trim();
-                                    }
-                                    return $q.all([watch, req]);
-                                });
-
-                        promise = $q.all([discover_p, env_p])
-                                .then(function() {
-                                    settings.canChangeConnection = info.type == "kubectl";
-                                    return settings;
-                                });
-
-                        return promise;
-                    };
-                }
-            ])
-
-            .factory("cockpitBrowserStorage", [
-                "$window",
-                function($window) {
-                    var base = $window;
-                    if (cockpit && cockpit.sessionStorage && cockpit.localStorage)
-                        base = cockpit;
-
-                    /* Some browsers fail localStorage access due to corruption, preventing Cockpit login */
-                    var localStorage;
-                    try {
-                        localStorage = base.localStorage;
-                    } catch (ex) {
-                        localStorage = base.sessionStorage;
-                        console.warn(String(ex));
-                    }
-
-                    return {
-                        sessionStorage: base.sessionStorage,
-                        localStorage: localStorage
-                    };
-                }
-            ])
-
-            .factory('cockpitConnectionInfo', function () {
-                return {
-                    type: null,
-                    kubeConfig: null,
-                };
-            })
-
-            .factory('cockpitContainerWebSocket', [
-                'CockpitKubeSocket',
-                'CockpitKubectlWebSocket',
-                'cockpitConnectionInfo',
-                function (socket, kubectlSocket, info) {
-                    return function(url, protocols) {
-                        /* config retrieved from kubectl? */
-                        if (info.type == "kubectl")
-                            return kubectlSocket(url, protocols);
-                        else
-                            return socket(url, { protocols: protocols });
-                    };
-                }
-            ])
-
-            .factory('CockpitFormat', function() {
-                return {
-                    formatBytes: cockpit.format_bytes,
-                    formatBitsPerSec: cockpit.format_bits_per_sec,
-                    format: cockpit.format
-                };
-            })
-
-            .factory('CockpitMetrics', function() {
-                return {
-                    grid: cockpit.grid,
-                    series: cockpit.series,
-                };
-            })
-
-            .factory('CockpitTranslate', function() {
-                return {
-                    gettext: cockpit.gettext,
-                    ngettext: cockpit.ngettext,
-                };
-            });
-}());
diff --git a/pkg/kubernetes/scripts/kube-client-mock.js b/pkg/kubernetes/scripts/kube-client-mock.js
deleted file mode 100644
index 4c614b2ec..000000000
--- a/pkg/kubernetes/scripts/kube-client-mock.js
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-var angular = require("angular");
-
-(function() {
-    var kubeLast = 100;
-
-    var kubeData = { };
-    var handlers = [ ];
-
-    function addNotify(handler) {
-        handlers.push(handler);
-    }
-
-    function removeNotify(handler) {
-        var i;
-        var len = handlers.length;
-        for (i = 0; i < len; i++) {
-            if (handlers[i] === handler)
-                handlers[i] = null;
-        }
-    }
-
-    function dispatchNotify() {
-        var i;
-        var len = handlers.length;
-        for (i = 0; i < len; i++) {
-            if (handlers[i])
-                handlers[i].apply(kubeData, arguments);
-        }
-    }
-
-    function guid() {
-        function s4() {
-            return Math.floor((1 + Math.random()) * 0x10000)
-                    .toString(16)
-                    .substring(1);
-        }
-        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
-               s4() + '-' + s4() + s4() + s4();
-    }
-
-    function deparam(query) {
-        var parsed = { };
-        var vars = query.split("&");
-        for (var i = 0; i < vars.length; i++) {
-            var pair = vars[i].split("=");
-            var k = decodeURIComponent(pair[0]);
-            var v = decodeURIComponent(pair[1]);
-            if (typeof parsed[k] === "undefined" ||
-              typeof parsed[k] === "function") {
-                if (k.substr(k.length - 2) != '[]')
-                    parsed[k] = v;
-                else
-                    parsed[k] = [v];
-            } else if (typeof parsed[k] === "string") {
-                parsed[k] = v;
-            } else {
-                parsed[k].push(v);
-            }
-        }
-
-        return parsed;
-    }
-
-    function kubeApiserver(req, defer) {
-        var path;
-        var query;
-
-        var pos = req.path.indexOf('?');
-        if (pos === -1) {
-            path = req.path;
-            query = { };
-        } else {
-            path = req.path.substring(0, pos);
-            query = deparam(req.path.substring(pos + 1));
-        }
-
-        var parts = path.substring(1).split("/");
-
-        /* The API check */
-        if (parts.length == 1 && (parts[0] == "api" || parts[0] != "oapi")) {
-            req.mockRespond(200, "OK", { }, JSON.stringify({
-                versions: [ "v1" ]
-            }));
-        }
-
-        if (parts[0] != "api" && parts[0] != "oapi" && parts[1] != "v1") {
-            req.mockRespond(404, "Not API");
-            return;
-        }
-
-        var baseUri = "/" + parts.slice(0, 2).join("/");
-        parts = parts.slice(2);
-
-        var ret = false;
-        if (req.method === "POST") {
-            ret = kubeApiPost(req, parts, query, baseUri);
-        } else if (req.method === "PUT") {
-            ret = kubeApiPut(req, parts, query, baseUri);
-        } else if (req.method === "GET") {
-            ret = kubeApiGet(req, parts, query, baseUri);
-        } else if (req.method === "DELETE") {
-            ret = kubeApiDelete(req, parts, query, baseUri);
-        } else if (req.method === "PATCH") {
-            ret = kubeApiPatch(req, parts, query, baseUri);
-        } else {
-            req.mockRespond(405, "Unsupported method");
-            ret = true;
-        }
-
-        if (!ret)
-            req.mockRespond(404, "Not found", { "Content-Type": "application/json" }, { code: 404, message: "Not found here" });
-    }
-
-    function kubeUpdate(key, object) {
-        var type;
-        if (!object) {
-            if (kubeData[key]) {
-                type = "DELETED";
-                object = kubeData[key];
-                delete kubeData[key];
-            } else {
-                return null;
-            }
-        } else {
-            if (kubeData[key])
-                type = "MODIFIED";
-            else
-                type = "ADDED";
-            kubeData[key] = object;
-        }
-
-        if (!object.metadata)
-            object.metadata = { };
-        if (!object.metadata.uid)
-            object.metadata.uid = guid();
-        object.metadata.resourceVersion = kubeLast;
-        kubeLast += 1;
-
-        dispatchNotify(type, key, object);
-        return object;
-    }
-
-    function kubeApiGet(req, parts, query, baseUri) {
-        var resourceVersion = null;
-        var namespaceRe = ".+";
-
-        /* Figure out if this is a watch */
-        var watch = false;
-        if (query.hasOwnProperty("watch")) {
-            watch = true;
-            if (query.resourceVersion) {
-                resourceVersion = parseInt(query.resourceVersion, 10);
-                if (isNaN(resourceVersion))
-                    throw Error("invalid resourceVersion");
-            }
-        }
-
-        /* Figure out if namespace api was used */
-        var what = parts.shift();
-        if (what == "namespaces" && parts.length > 1) {
-            namespaceRe = parts.shift();
-            what = parts.shift();
-        }
-
-        var specific = parts.join("/");
-        var kind = null;
-        var regexp = null;
-
-        function prepare(key, object) {
-            if (resourceVersion) {
-                if (!object.metadata || !object.metadata.resourceVersion ||
-                    object.metadata.resourceVersion < resourceVersion)
-                    return null;
-            }
-            if (specific) {
-                if (key != specific)
-                    return null;
-            }
-            if (regexp) {
-                if (!key.match(regexp))
-                    return null;
-            }
-
-            var copy = JSON.parse(JSON.stringify(object));
-            copy.metadata.selfLink = baseUri + "/" + key;
-            copy.apiVersion = "v1";
-            return copy;
-        }
-
-        /* Various lists */
-        if (what == "namespaces") {
-            regexp = /namespaces\/[a-z0-9-_]+$/;
-            kind = "NamespaceList";
-        } else if (what == "nodes") {
-            regexp = /nodes\//;
-            kind = "NodeList";
-        } else if (what == "pods") {
-            regexp = RegExp("namespaces/" + namespaceRe + "/pods/");
-            kind = "PodList";
-        } else if (what == "services") {
-            regexp = RegExp("namespaces/" + namespaceRe + "/services/");
-            kind = "ServiceList";
-        } else if (what == "replicationcontrollers") {
-            regexp = RegExp("namespaces/" + namespaceRe + "/replicationcontrollers/");
-            kind = "ReplicationControllerList";
-        } else if (what == "events") {
-            regexp = RegExp("namespaces/" + namespaceRe + "/events/");
-            kind = "EventList";
-        } else if (what == "images") {
-            req.mockRespond(404, "OK", { "Content-Type": "text/plain; charset=utf-8" });
-            return;
-        } else if (what == "imagestreams") {
-            regexp = RegExp("namespaces/" + namespaceRe + "/imagestreams/");
-            kind = "ImageStreamList";
-        /* Nothing found */
-        } else {
-            return false;
-        }
-
-        function respondGet() {
-            var items = [ ];
-            var result = {
-                kind: kind,
-                creationTimestamp: null,
-                items: items
-            };
-
-            angular.forEach(kubeData, function(value, key) {
-                var object = prepare(key, value);
-                if (object)
-                    items.push(object);
-            });
-
-            req.mockRespond(200, "OK", { "Content-Type": "application/json" }, JSON.stringify(result));
-            return true;
-        }
-
-        function respondWatch() {
-            req.mockRespond(200, "OK", { "Content-Type": "text/plain; charset=utf-8" }, null);
-
-            var body = "";
-            angular.forEach(kubeData, function(value, key) {
-                var object = prepare(key, value);
-                if (object)
-                    body += JSON.stringify({ type: "ADDED", object: object }) + "\n";
-            });
-
-            function streamWatch(type, key, value) {
-                var object = prepare(key, value);
-                if (object)
-                    req.mockData(JSON.stringify({ type: type, object: object }) + "\n", true);
-            }
-
-            addNotify(streamWatch);
-            req.mockData(body, true);
-
-            window.setTimeout(function() {
-                removeNotify(streamWatch);
-                req.mockData("", false);
-            }, 5000);
-
-            return true;
-        }
-
-        if (watch)
-            return respondWatch();
-        else
-            return respondGet();
-    }
-
-    function kubeApiPost(req, parts, query, baseUri) {
-        var section;
-
-        if (parts.length === 3) {
-            if (parts[0] != "namespaces")
-                return false;
-            section = parts[2];
-        } else if (parts.length === 1) {
-            section = parts[0];
-        } else {
-            return false;
-        }
-
-        var object;
-        try {
-            object = JSON.parse(req.body);
-        } catch (ex) {
-            req.mockRespond(400, "Bad JSON");
-            return true;
-        }
-
-        var kind = object.kind;
-        var meta = object.metadata || { };
-        var name = meta.name;
-
-        if (!kind || !meta || !name) {
-            req.mockRespond(400, "Bad fields in JSON");
-            return true;
-        }
-
-        if (kind.toLowerCase() + "s" != section) {
-            req.mockRespond(400, "Bad section of URI");
-            return true;
-        }
-
-        parts.push(name);
-        var key = parts.join("/");
-
-        if (kubeData[key]) {
-            req.mockRespond(409, "Already exists", { "Content-Type": "application/json" },
-                            JSON.stringify({ code: 409, message: "Already exists" }));
-            return true;
-        }
-
-        kubeUpdate(key, object);
-        req.mockRespond(200, "OK", { "Content-Type": "application/json" }, JSON.stringify(object));
-        return true;
-    }
-
-    function kubeApiPut(req, parts, query, baseUri) {
-        var object;
-        try {
-            object = JSON.parse(req.body);
-        } catch (ex) {
-            req.mockRespond(400, "Bad JSON");
-            return true;
-        }
-
-        var key = parts.join("/");
-        kubeUpdate(key, object);
-        req.mockRespond(200, "OK", { "Content-Type": "application/json" }, JSON.stringify(object));
-        return true;
-    }
-
-    function kubeApiDelete(req, parts, query, baseUri) {
-        if (parts.length === 4) {
-            if (parts[0] != "namespaces")
-                return false;
-        } else if (parts.length !== 2) {
-            return false;
-        }
-
-        var key = parts.join("/");
-
-        var resp = kubeUpdate(key, null);
-        req.mockRespond(200, "OK", { "Content-Type": "application/json" }, JSON.stringify(resp));
-        return true;
-    }
-
-    function kubeApiPatch(req, parts, query, baseUri) {
-        if (parts.length === 4) {
-            if (parts[0] != "namespaces")
-                return false;
-        } else if (parts.length !== 2) {
-            return false;
-        }
-
-        if (req.headers["Content-Type"] != "application/strategic-merge-patch+json") {
-            req.mockRespond(400, "Bad Content Type");
-            return true;
-        }
-
-        var key = parts.join("/");
-        var patch;
-        try {
-            patch = JSON.parse(req.body);
-        } catch (ex) {
-            req.mockRespond(400, "Bad JSON");
-            return true;
-        }
-
-        var data = angular.extend({ }, kubeData[key] || { }, patch);
-        var resp = kubeUpdate(key, data);
-        req.mockRespond(200, "OK", { "Content-Type": "application/json" }, JSON.stringify(resp));
-        return true;
-    }
-
-    var unique = 0;
-
-    angular.module("kubeClient.mock", [
-        "kubeClient",
-    ])
-
-            .value("MockKubeData", {
-                load: function load(data) {
-                    kubeData = JSON.parse(JSON.stringify(data));
-                },
-                update: kubeUpdate
-            })
-
-            .factory("MockKubeWatch", [
-                "$q",
-                "KUBE_SCHEMA",
-                "MockKubeRequest",
-                function($q, KUBE_SCHEMA, MockKubeRequest) {
-                    return function CockpitKubeWatch(path, callback) {
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-
-                        unique += 1;
-
-                        var request = new MockKubeRequest("GET", path + "?watch=true", "", {
-                            streamer: handleStream,
-                            unique: unique,
-                        });
-
-                        var buffer;
-                        function handleStream(data, response) {
-                            if (buffer)
-                                data = buffer + data;
-
-                            var lines = data.split("\n");
-                            var i;
-                            var length = lines.length - 1;
-
-                            /* Last line is incomplete save for later */
-                            buffer = lines[length];
-
-                            /* Process all the others */
-                            var frame;
-                            var frames = [];
-                            for (i = 0; i < length; i++) {
-                                frame = JSON.parse(lines[i]);
-                                if (!frame.object)
-                                    throw Error("invalid watch without object");
-
-                                /* The watch failed, likely due to invalid resourceVersion */
-                                if (frame.type == "ERROR")
-                                    throw frame;
-
-                                frames.push(frame);
-                            }
-
-                            callback(frames);
-
-                            var df = defer;
-                            if (df) {
-                                callback([]);
-                                defer = null;
-                                df.resolve(response);
-                            }
-                        }
-
-                        request.then(function(response) {
-                            var df = defer;
-                            defer = null;
-                            if (df)
-                                df.resolve(response);
-                        }, function(response) {
-                            var df = defer;
-                            defer = null;
-                            if (df)
-                                df.reject(response);
-                        });
-
-                        promise.cancel = function cancel() {
-                            var df = defer;
-                            if (request)
-                                request.cancel();
-                            if (df) {
-                                defer = null;
-                                df.reject({
-                                    status: 999,
-                                    statusText: "Cancelled",
-                                    problem: "cancelled",
-                                });
-                            }
-                        };
-                        return promise;
-                    };
-                }
-            ])
-
-            .factory("MockKubeRequest", [
-                "$q",
-                function($q) {
-                    return function MockKubeRequest(method, path, data, config) {
-                        var req = angular.extend({ }, config, { method: method, path: path, body: data });
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-                        var response;
-                        function finish() {
-                            var df = defer;
-                            defer = null;
-                            if (response.headers["Content-Type"] == "application/json")
-                                response.data = JSON.parse(response.data);
-                            if (response.status < 300)
-                                df.resolve(response);
-                            else
-                                df.reject(response);
-                        }
-
-                        req.mockRespond = function(status, reason, headers, body) {
-                            if (!defer)
-                                return;
-                            response = {
-                                status: status,
-                                statusText: reason,
-                                headers: headers || { },
-                                data: "",
-                                unique: req.unique,
-                            };
-                            if (body !== null)
-                                req.mockData(body || "", false);
-                        };
-
-                        req.mockData = function(body, stream) {
-                            if (!defer)
-                                return;
-                            if (typeof (body) !== "string")
-                                body = JSON.stringify(body);
-                            if (req.streamer)
-                                req.streamer(body, response);
-                            else
-                                response.data += body;
-                            if (!stream)
-                                finish();
-                        };
-
-                        promise.cancel = function cancel() {
-                            if (!defer)
-                                return;
-                            defer.reject({
-                                status: 999,
-                                statusText: "Cancelled",
-                                problem: "cancelled",
-                            });
-                            defer = null;
-                        };
-
-                        window.setTimeout(function() {
-                            kubeApiserver(req);
-                        });
-
-                        return promise;
-                    };
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/kube-client.js b/pkg/kubernetes/scripts/kube-client.js
deleted file mode 100644
index 833994b79..000000000
--- a/pkg/kubernetes/scripts/kube-client.js
+++ /dev/null
@@ -1,1582 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-
-    /*
-     * Some notes on the create fields.
-     *
-     * Namespaces should be created first, as they must exist before objects in
-     * them are created.
-     *
-     * Services should be created before pods (or replication controllers that
-     * make pods. This is because of the environment variables that pods get
-     * when they want to access a service.
-     *
-     * Create pods before replication controllers ... corner case, but keeps
-     * things sane.
-     */
-
-    var KUBE = "/api/v1";
-    var OPENSHIFT = "/oapi/v1";
-    var DEFAULT = { api: KUBE, create: 0 };
-    var SCHEMA = flatSchema([
-        { kind: "DeploymentConfig", type: "deploymentconfigs", api: OPENSHIFT },
-        { kind: "Endpoints", type: "endpoints", api: KUBE },
-        { kind: "Group", type: "groups", api: OPENSHIFT, global: true },
-        { kind: "Image", type: "images", api: OPENSHIFT, global: true },
-        { kind: "ImageStream", type: "imagestreams", api: OPENSHIFT },
-        { kind: "ImageStreamImage", type: "imagestreamimages", api: OPENSHIFT },
-        { kind: "ImageStreamTag", type: "imagestreamtags", api: OPENSHIFT },
-        { kind: "LocalResourceAccessReview", type: "localresourceaccessreviews", api: OPENSHIFT },
-        { kind: "Namespace", type: "namespaces", api: KUBE, global: true, create: -100 },
-        { kind: "Node", type: "nodes", api: KUBE, global: true },
-        { kind: "Pod", type: "pods", api: KUBE, create: -20 },
-        { kind: "PolicyBinding", type: "policybindings", api: OPENSHIFT },
-        { kind: "RoleBinding", type: "rolebindings", api: OPENSHIFT },
-        { kind: "Route", type: "routes", api: OPENSHIFT },
-        { kind: "PersistentVolume", type: "persistentvolumes", api: KUBE, global: true, create: -100 },
-        { kind: "PersistentVolumeClaim", type: "persistentvolumeclaims", api: KUBE, create: -50 },
-        { kind: "Project", type: "projects", api: OPENSHIFT, global: true, create: -90 },
-        { kind: "ProjectRequest", type: "projectrequests", api: OPENSHIFT, global: true, create: -90 },
-        { kind: "ReplicationController", type: "replicationcontrollers", api: KUBE, create: -60 },
-        { kind: "Service", type: "services", api: KUBE, create: -80 },
-        { kind: "SubjectAccessReview", type: "subjectaccessreviews", api: OPENSHIFT },
-        { kind: "User", type: "users", api: OPENSHIFT, global: true },
-    ]);
-
-    var NAME_RE = /^[a-z0-9]([-a-z0-9_.]*[a-z0-9])?$/;
-    var USER_NAME_RE = /^[a-zA-Z0-9_.]([-a-zA-Z0-9 ,=@._:]*[a-zA-Z0-9._:])?$/;
-
-    /* Timeout for non-GET requests */
-    var REQ_TIMEOUT = "120s";
-
-    function debug() {
-        if (window.debugging == "all" || window.debugging == "kube")
-            console.debug.apply(console, arguments);
-    }
-
-    function hash(str) {
-        var h, i, chr, len;
-        if (str.length === 0)
-            return 0;
-        for (h = 0, i = 0, len = str.length; i < len; i++) {
-            chr = str.charCodeAt(i);
-            h = ((h << 5) - h) + chr;
-            h |= 0; // Convert to 32bit integer
-        }
-        return Math.abs(h);
-    }
-
-    function search(arr, val) {
-        var low = 0;
-        var high = arr.length - 1;
-        var mid, v;
-
-        while (low <= high) {
-            mid = (low + high) / 2 | 0;
-            v = arr[mid];
-            if (v < val)
-                low = mid + 1;
-            else if (v > val)
-                high = mid - 1;
-            else
-                return mid; /* key found */
-        }
-        return low;
-    }
-
-    /**
-     * HashIndex
-     *
-     * A probablisting hash index, where items are added with
-     * various keys, and probable matches are returned. Similar
-     * to bloom filters, false positives are possible, but never
-     * false negatives.
-     */
-    function HashIndex(size) {
-        var self = this;
-        var array = [];
-
-        self.add = function add(keys, value) {
-            var i, j, p, x;
-            var length = keys.length;
-            for (j = 0; j < length; j++) {
-                i = hash("" + keys[j]) % size;
-                p = array[i];
-                if (p === undefined)
-                    p = array[i] = [];
-                x = search(p, value);
-                if (p[x] != value)
-                    p.splice(x, 0, value);
-            }
-        };
-
-        self.get = function get(key) {
-            var p = array[hash("" + key) % size];
-            if (!p)
-                return [];
-            return p.slice();
-        };
-
-        self.all = function all(keys) {
-            var i, j, p, result, n;
-            var rl, rv, pv, ri, px;
-
-            for (j = 0, n = keys.length; j < n; j++) {
-                i = hash("" + keys[j]) % size;
-                p = array[i];
-
-                /* No match for this key, short cut out */
-                if (!p) {
-                    result = [];
-                    break;
-                }
-
-                /* First key */
-                if (!result) {
-                    result = p.slice();
-
-                /* Calculate intersection */
-                } else {
-                    for (ri = 0, px = 0, rl = result.length; ri < rl;) {
-                        rv = result[ri];
-                        pv = p[ri + px];
-                        if (pv < rv) {
-                            px += 1;
-                        } else if (rv !== pv) {
-                            result.splice(ri, 1);
-                            rl -= 1;
-                        } else {
-                            ri += 1;
-                        }
-                    }
-                }
-            }
-
-            return result || [];
-        };
-    }
-
-    /*
-     * A WeakMap implementation
-     *
-     * This works on ES5 browsers, with the caveat that the mapped
-     * items are discoverable with enough work.
-     *
-     * To be clear, the principal use of a WeakMap is to associate
-     * an value with an object, the object is the key. And then have
-     * that value go away when the object does. This is very, very
-     * similar to properties.
-     *
-     * The main difference is that any assigned values are not
-     * garbage collected if the *weakmap* itself is collected,
-     * and of course one can actually access the non-enumerable
-     * property that makes this work.
-     */
-
-    var weak_property = Math.random().toString(36)
-            .slice(2);
-    var local_seed = 1;
-
-    function SimpleWeakMap() {
-        var local_property = "weakmap" + local_seed;
-        local_seed += 1;
-
-        var self = this;
-
-        self.delete = function delete_(obj) {
-            var map = obj[weak_property];
-            if (map)
-                delete map[local_property];
-        };
-
-        self.has = function has(obj) {
-            var map = obj[weak_property];
-            return (map && local_property in map);
-        };
-
-        self.get = function has(obj) {
-            var map = obj[weak_property];
-            if (!map)
-                return undefined;
-            return map[local_property];
-        };
-
-        self.set = function set(obj, value) {
-            var map = obj[weak_property];
-            if (!map) {
-                map = function WeakMapData() { };
-                Object.defineProperty(obj, weak_property, {
-                    enumerable: false, configurable: false,
-                    writable: false, value: map,
-                });
-            }
-
-            map[local_property] = value;
-        };
-    }
-
-    function flatSchema(items) {
-        var i, len;
-        var ret = { "": DEFAULT };
-        for (i = 0, len = items.length; i < len; i++) {
-            ret[items[i].type] = items[i];
-            ret[items[i].kind] = items[i];
-        }
-        return ret;
-    }
-
-    /*
-     * Accepts:
-     *  1. an object
-     *  2. an involved object
-     *  2. a path string
-     *  3. type/kind, name, namespace
-     */
-    function resourcePath(args) {
-        var one = args[0];
-        if (one && typeof one === "object") {
-            if (one.metadata) {
-                /* An object with a link */
-                if (one.metadata.selfLink)
-                    return one.metadata.selfLink;
-
-                /* Pull out the arguments */
-                args = [ one.kind, one.metadata.name, one.metadata.namespace ];
-            } else if (one.name && one.kind) {
-                /* An involved object */
-                args = [ one.kind, one.name, one.namespace ];
-            }
-
-        /* Already a path */
-        } else if (one && one[0] == '/') {
-            return one;
-        }
-
-        /*
-         * Combine into a path.
-         */
-        var schema = SCHEMA[args[0]] || SCHEMA[""];
-        var path = schema.api;
-        if (!schema.global && args[2])
-            path += "/namespaces/" + args[2];
-        path += "/" + schema.type;
-        if (args[1])
-            path += "/" + encodeURIComponent(args[1]);
-
-        return path;
-    }
-
-    /*
-     * Angular definitions start here
-     */
-
-    angular.module("kubeClient", [])
-
-    /**
-     * KUBE_SCHEMA
-     *
-     * A dict of schema information. The keys are both object types
-     * and resource kinds. The values are objects with the following
-     * properties:
-     *
-     *  schema.kind    The object kind
-     *  schema.type    The resource type (ie: used in urls)
-     *  schema.api     The api endpoint to use
-     *  schema.global  Set to true if resource is not namespaced.
-     */
-
-            .value("KUBE_SCHEMA", SCHEMA)
-
-    /**
-     * KUBE_NAME_RE
-     *
-     * Regular Expression that names in kubernetes must match.
-     */
-            .value("KUBE_NAME_RE", NAME_RE)
-
-    /**
-     * kubeLoader
-     *
-     * Loads kubernetes objects either by watching them or loading
-     * objects explicitly. The loaded objects are available at
-     * the .objects property, although you probably want to
-     * use kubeSelect() to interact with these objects.
-     *
-     * loader.handle(objects, [removed])
-     *
-     * Tell the loader about a objects that has been loaded
-     * or removed elsewhere.
-     *
-     * loader.listen(callback, until)
-     *
-     * Register a callback to be invoked some time after new
-     * objects have been loaded. Returns an object with a
-     * .cancel() method, that can be used to stop listening.
-     *
-     * promise = loader.load(path)
-     * promise = loader.load(involvedObject)
-     * promise = loader.load(resource)
-     * promise = loader.load(kind, [name], [namespace])
-     *
-     * Load the resource at the path. Returns a promise that will
-     * resolve with the resource or an array of objects at the
-     * given path.
-     *
-     * loader.limits
-     *
-     * Contains various limits that govern what the loader loads
-     * from watches. Of note is loader.limits.namespace which is set
-     * to null for the loader to load all objects, or a namespace
-     * string or array of namespace strings for the loader to watch
-     * objects from specific namespaces.
-     *
-     * loader.limit(options)
-     *
-     * Adjust the loader limits that govern what the loader loads
-     * from watches. Options can contain a "namespace" field to
-     * set the namespace or namespaces to limit watching to.
-     *
-     * loader.reset()
-     *
-     * Clear out all loaded objects, and clear all watches. Also
-     * clears the limits and other state.
-     *
-     * loader.objects
-     *
-     * A dict of all loaded objects.
-     *
-     * promise = loader.watch(type, until)
-     *
-     * Start watching the given resource type. The returned promise
-     * will be resolved when an initial set of objects have been
-     * loaded for the watch, or rejected if the watch has failed.
-     */
-
-            .factory("kubeLoader", [
-                "$q",
-                "$timeout",
-                "KubeWatch",
-                "KubeRequest",
-                "KUBE_SCHEMA",
-                function($q, $timeout, KubeWatch, KubeRequest, KUBE_SCHEMA) {
-                    var self;
-
-                    var callbacks = [];
-                    var limits = { namespace: null };
-
-                    /* All the current watches */
-                    var watching = { };
-
-                    /* All the loaded objects */
-                    var objects = { };
-
-                    /* Timeout batching */
-                    var batch = null;
-                    var batchTimeout = null;
-
-                    function ensureWatch(what, namespace, increment) {
-                        var schema = SCHEMA[what] || SCHEMA[""];
-                        var watch;
-                        var path = schema.api;
-                        if (!schema.global && namespace)
-                            path += "/namespaces/" + namespace;
-                        path += "/" + schema.type;
-
-                        if (!(path in watching)) {
-                            watch = new KubeWatch(path, handleFrames);
-                            watch.what = what;
-                            watch.global = schema.global;
-                            watch.namespace = namespace;
-                            watch.cancelWatch = watch.cancel;
-
-                            /* Replace the cancel function with one that does ref counting */
-                            watch.cancel = function() {
-                                var w = watching[path];
-                                if (w) {
-                                    w.references -= 1;
-                                    if (w.references <= 0) {
-                                        w.cancelWatch();
-                                        delete watching[path];
-                                    }
-                                }
-                            };
-                            watching[path] = watch;
-                        }
-
-                        /* Increase the references here */
-                        watching[path].references += increment;
-                        return watching[path];
-                    }
-
-                    function ensureWatches(what, increment) {
-                        var namespace = limits.namespace;
-                        if (!angular.isArray(namespace))
-                            return ensureWatch(what, namespace, increment);
-
-                        var parts = [];
-                        angular.forEach(namespace, function(val) {
-                            parts.push(ensureWatch(what, val, increment));
-                        });
-                        var ret = $q.all(parts);
-                        ret.cancel = function() {
-                            angular.forEach(parts, function(val) {
-                                val.cancel();
-                            });
-                        };
-                        return ret;
-                    }
-
-                    function handleFrames(frames) {
-                        if (batch === null)
-                            batch = frames;
-                        else
-                            batch.push.apply(batch, frames);
-
-                        /* When called with empty data, flush, don't wait */
-                        if (frames.length > 0) {
-                            if (batchTimeout === null)
-                                batchTimeout = window.setTimeout(handleTimeout, 150);
-                            else
-                                return; /* called again later */
-                        }
-
-                        handleFlush(invokeCallbacks);
-                    }
-
-                    function resourceVersion(resource) {
-                        var version;
-                        if (resource && resource.metadata)
-                            version = parseInt(resource.metadata.resourceVersion, 10);
-
-                        if (!isNaN(version))
-                            return version;
-                    }
-
-                    function handleFlush(invoke) {
-                        var drain = batch;
-                        batch = null;
-
-                        if (!drain)
-                            return;
-
-                        var present = { };
-                        var removed = { };
-                        var i, len, link, resource;
-                        var cVersion, lVersion;
-                        for (i = 0, len = drain.length; i < len; i++) {
-                            resource = drain[i].object;
-                            if (resource) {
-                                link = decodeURIComponent(resourcePath([resource]));
-                                if (drain[i].type == "DELETED") {
-                                    delete objects[link];
-                                    delete present[link];
-                                    removed[link] = resource;
-                                } else if (drain[i].checkResourceVersion) {
-                                    /* There is a race between items loaded from
-                             * watchers and items loaded other ways such as
-                             * from KubeMethods callbacks, where we might
-                             * end up saving the older item if loader.load is
-                             * called after the watcher has already loaded fresher
-                             * data. Look at the resourceVersion and only add
-                             * if it is the same or newer than what we already have.
-                             */
-                                    cVersion = resourceVersion(resource);
-                                    lVersion = resourceVersion(objects[link]);
-                                    if (!cVersion || !lVersion || cVersion >= lVersion) {
-                                        present[link] = resource;
-                                        objects[link] = resource;
-                                    }
-                                } else {
-                                    present[link] = resource;
-                                    objects[link] = resource;
-                                }
-                            }
-                        }
-
-                        /* Run all the listeners and then digest */
-                        invoke(present, removed);
-                    }
-
-                    function invokeCallbacks(/* ... */) {
-                        var i, len, func;
-                        for (i = 0, len = callbacks.length; i < len; i++) {
-                            func = callbacks[i];
-                            if (func)
-                                func.apply(self, arguments);
-                        }
-                    }
-
-                    function handleTimeout() {
-                        batchTimeout = null;
-                        handleFlush(invokeCallbacks);
-                    }
-
-                    function resetLoader() {
-                        var link;
-
-                        /* We drop any batched objects in flight */
-                        window.clearTimeout(batchTimeout);
-                        batchTimeout = null;
-                        batch = null;
-
-                        /* Cancel all the watches  */
-                        var old = watching;
-                        watching = { };
-                        angular.forEach(old, function(w) {
-                            w.cancelWatch();
-                        });
-
-                        /* Clear out everything */
-                        for (link in objects)
-                            delete objects[link];
-
-                        for (link in limits)
-                            delete limits[link];
-                        limits.namespace = null;
-
-                        /* Tell the callbacks we're resetting */
-                        invokeCallbacks();
-                    }
-
-                    function handleObjects(objects, removed, kind) {
-                        handleFrames(objects.map(function(resource) {
-                            if (kind)
-                                resource.kind = kind;
-
-                            return {
-                                type: removed ? "DELETED" : "ADDED",
-                                object: resource,
-                                checkResourceVersion: true
-                            };
-                        }));
-                        handleFlush(invokeCallbacks);
-                    }
-
-                    function loadObjects(/* ... */) {
-                        var path = resourcePath(arguments);
-                        var req = new KubeRequest("GET", path);
-                        var promise = req.then(function(response) {
-                            req = null;
-                            var resource = response.data;
-                            if (!resource || !resource.kind) {
-                                return null;
-                            } else if (resource.kind.indexOf("List") === resource.kind.length - 4) {
-                                handleObjects(resource.items, false, resource.kind.slice(0, -4));
-                                return resource.items;
-                            } else {
-                                handleObjects([resource]);
-                                return resource;
-                            }
-                        }, function(response) {
-                            req = null;
-                            var resp = response.data;
-                            return $q.reject(resp || response);
-                        });
-                        promise.cancel = function cancel(ex) {
-                            req.cancel(ex);
-                        };
-                        return promise;
-                    }
-
-                    function adjustNamespace(value) {
-                        window.clearTimeout(batchTimeout);
-                        batchTimeout = null;
-
-                        /* Convert this to our native format */
-                        var only = { };
-                        if (value === null) {
-                            only = null;
-                        } else if (angular.isArray(value)) {
-                            angular.forEach(value, function(namespace) {
-                                only[namespace] = true;
-                            });
-                        } else {
-                            only[value] = true;
-                        }
-                        limits.namespace = value;
-
-                        /* Flush everything that's outstanding */
-                        var present = { };
-                        var removed = { };
-                        handleFlush(function(a, b) {
-                            present = a;
-                            removed = b;
-                        });
-
-                        /* Remove objects that are not in these namespaces */
-                        var meta, link;
-                        for (link in objects) {
-                            meta = objects[link].metadata;
-                            if (only && meta.namespace && !(meta.namespace in only)) {
-                                removed[link] = objects[link];
-                                delete objects[link];
-                                delete present[link];
-                            }
-                        }
-
-                        /* Cancel any watches not applicable to these namespaces */
-                        var path, w;
-                        var reconnect = [ ];
-                        for (path in watching) {
-                            w = watching[path];
-                            if ((!only && w.namespace) || (only && !w.global && !(w.namespace in only))) {
-                                w.cancelWatch();
-                                delete watching[path];
-                                reconnect.push(w);
-                            }
-                        }
-
-                        /* Tell the world what we did */
-                        invokeCallbacks(present, removed);
-
-                        /* Reconnect all the watches we cancelled with proper namespace */
-                        angular.forEach(reconnect, function(w) {
-                            ensureWatches(w.what, w.references);
-                        });
-                    }
-
-                    function connectUntil(ret, until) {
-                        if (until) {
-                            if (until.$on) {
-                                until.$on("$destroy", function() {
-                                    ret.cancel();
-                                });
-                            } else {
-                                console.warn("invalid until passed to watch", until);
-                            }
-                        }
-                    }
-
-                    self = {
-                        watch: function watch(what, until) {
-                            var ret = ensureWatches(what, 1);
-                            connectUntil(ret, until);
-                            return ret;
-                        },
-                        load: function load(/* ... */) {
-                            return loadObjects.apply(this, arguments);
-                        },
-                        limit: function limit(options) {
-                            if ("namespace" in options)
-                                adjustNamespace(options.namespace);
-                        },
-                        reset: resetLoader,
-                        listen: function listen(callback, until) {
-                            if (callback.early)
-                                callbacks.unshift(callback);
-                            else
-                                callbacks.push(callback);
-                            var timeout = $timeout(function() {
-                                timeout = null;
-                                callback.call(self, objects);
-                            }, 0);
-                            var ret = {
-                                cancel: function() {
-                                    var i, len;
-                                    $timeout.cancel(timeout);
-                                    timeout = null;
-                                    for (i = 0, len = callbacks.length; i < len; i++) {
-                                        if (callbacks[i] === callback)
-                                            callbacks[i] = null;
-                                    }
-                                }
-                            };
-                            connectUntil(ret, until);
-                            return ret;
-                        },
-                        handle: function handle(objects, removed, kind) {
-                            if (!angular.isArray(objects))
-                                objects = [ objects ];
-                            handleObjects(objects, removed, kind);
-                        },
-                        resolve: function resolve(/* ... */) {
-                            return resourcePath(arguments);
-                        },
-                        objects: objects,
-                        limits: limits,
-                    };
-
-                    return self;
-                }
-            ])
-
-    /**
-     * kubeSelect
-     *
-     * Allows selecting loaded objects based on various criteria. The
-     * goal here is to allow selection to be fast enough that it can be
-     * done repeatedly and regularly, without keeping caches of objects
-     * all over the place.
-     *
-     * Resources may be filtered in a chain by calling various filter
-     * functions. Lets start with an example that finds a pod:
-     *
-     *   pod = kubeSelect()
-     *      .kind("Pod")
-     *      .namespace("default")
-     *      .name("docker-registry")
-     *      .one();
-     *
-     * Calling kubeSelect() will return a dict with all loaded objects,
-     * containing unique keys, and then various filters can be called to
-     * further narrow results.
-     *
-     * You can also pass a dict of objects into kubeSelect() and then
-     * perform actions on it.
-     *
-     * The following filters are available by default:
-     *
-     *  .kind(kind)       Limit to specified kind
-     *  .namespace(ns)    Limit to specified namespace
-     *  .name(name)       Limit to this name
-     *  .host(name)       Limit to this host
-     *  .label(selector)  Limit to objects whose label match selector
-     *  .one()            Choose one of results, or null
-     *  .extend(obj)      Extend obj with the results
-     *
-     * Additional filters can be registered by calling the function:
-     *
-     *   kubeSelect.register(name, function)
-     *   kubeSelect.register(filterobj)
-     *
-     * Ask on FreeNode #cockpit for documentation on filters.
-     */
-
-            .factory("kubeSelect", [
-                "kubeLoader",
-                function(loader) {
-                    /* A list of all registered filters */
-                    var filters = { };
-
-                    /* A hash index */
-                    var index = null;
-
-                    /* The filter prototype for functions available on selector */
-                    var proto = null;
-
-                    /* Cache data */
-                    var weakmap = new SimpleWeakMap();
-                    var version = 1;
-
-                    function listener(present, removed) {
-                        version += 1;
-
-                        /* Get called like this when reset */
-                        if (!present) {
-                            index = null;
-
-                            /* Called like this when more objects arrive */
-                        } else if (index) {
-                            indexObjects(present);
-                        }
-                    }
-
-                    listener.early = true;
-                    loader.listen(listener);
-
-                    /* Create a new index and populate */
-                    function indexCreate() {
-                        /* TODO: Derive this value from cluster size */
-                        index = new HashIndex(262139);
-
-                        /* And index all the objects */
-                        indexObjects(loader.objects);
-                    }
-
-                    /* Populate index for the given objects and current filters */
-                    function indexObjects(objects) {
-                        var link, object, name, key, keys, filter;
-                        for (link in objects) {
-                            object = objects[link];
-                            for (name in filters) {
-                                filter = filters[name];
-                                if (filter.digest) {
-                                    key = filter.digest.call(null, object);
-                                    if (key)
-                                        index.add([ key ], link);
-                                } else if (filter.digests) {
-                                    keys = filter.digests.call(null, object);
-                                    if (keys.length)
-                                        index.add(keys, link);
-                                }
-                            }
-                        }
-                    }
-
-                    /* Return a place to cache data related to obj */
-                    function cached(obj) {
-                        var data = weakmap.get(obj);
-                        if (!data || data.version !== version) {
-                            data = { version: version, length: data ? data.length : undefined };
-                            weakmap.set(obj, data);
-                        }
-                        return data;
-                    }
-
-                    function makePrototypeCall(filter) {
-                        return function() {
-                            var cache = cached(this);
-
-                            /*
-                     * Do this early, since some browsers cannot pass
-                     * arguments to JSON.stringify()
-                     */
-                            var args = Array.prototype.slice.call(arguments);
-
-                            /* Fast path, already calculated results */
-                            var desc = filter.name + ": " + JSON.stringify(args);
-                            if (desc in cache)
-                                return cache[desc];
-
-                            var results;
-                            if (filter.filter) {
-                                results = filter.filter.apply(this, args);
-                            } else {
-                                if (!index)
-                                    indexCreate();
-                                if (!cache.indexed) {
-                                    indexObjects(this);
-                                    cache.indexed = true;
-                                }
-                                if (filter.digests) {
-                                    results = digestsFilter(filter, this, args);
-                                } else if (filter.digest) {
-                                    results = digestFilter(filter, this, args);
-                                } else {
-                                    console.warn("invalid filter: " + filter.name);
-                                    results = { };
-                                }
-                            }
-
-                            cache[desc] = results;
-                            return results;
-                        };
-                    }
-
-                    function makePrototype() {
-                        var name;
-                        var ret = {
-                            length: {
-                                enumerable: false,
-                                configurable: true,
-                                get: function() { return cached(this).length }
-                            }
-                        };
-                        for (name in filters) {
-                            ret[name] = {
-                                enumerable: false,
-                                configurable: true,
-                                value: makePrototypeCall(filters[name])
-                            };
-                        }
-                        return ret;
-                    }
-
-                    function mixinSelection(results, length, indexed) {
-                        var data;
-                        if (length === undefined)
-                            length = Object.keys(results).length;
-                        proto = proto || makePrototype();
-                        Object.defineProperties(results, proto);
-                        data = cached(results);
-                        data.length = length;
-                        data.selection = results;
-                        data.indexed = indexed;
-                        return results;
-                    }
-
-                    function digestFilter(filter, what, criteria) {
-                        var p, pl, key, possible, link, object;
-                        var results = { };
-                        var count = 0;
-
-                        key = filter.digest.apply(null, criteria);
-                        if (key !== null && key !== undefined) {
-                            possible = index.get(key);
-                        } else {
-                            possible = [];
-                        }
-
-                        for (p = 0, pl = possible.length; p < pl; p++) {
-                            link = possible[p];
-                            object = what[link];
-                            if (object) {
-                                if (key === filter.digest.call(null, object)) {
-                                    results[link] = object;
-                                    count += 1;
-                                }
-                            }
-                        }
-
-                        return mixinSelection(results, count, true);
-                    }
-
-                    function digestsFilter(filter, what, criteria) {
-                        var keys, keyn, keyo, k, link, match, object, possible;
-                        var p, pl, j, jl;
-                        var results = { };
-                        var count = 0;
-
-                        keys = filter.digests.apply(null, criteria);
-                        keyn = keys.length;
-                        if (keyn > 0) {
-                            possible = index.all(keys);
-                            keys.sort();
-                        } else {
-                            possible = [];
-                        }
-
-                        for (p = 0, pl = possible.length; p < pl; p++) {
-                            link = possible[p];
-                            object = what[link];
-                            if (object) {
-                                keyo = filter.digests.call(null, object);
-                                keyo.sort();
-                                match = false;
-
-                                /* Search for first key */
-                                for (j = 0, jl = keyo.length; !match && j < jl; j++) {
-                                    if (keys[0] === keyo[j]) {
-                                        match = true;
-                                        for (k = 0; match && k < keyn; k++) {
-                                            if (keys[k] !== keyo[j + k])
-                                                match = false;
-                                        }
-                                    }
-                                }
-
-                                if (match) {
-                                    results[link] = object;
-                                    count += 1;
-                                }
-                            }
-                        }
-
-                        return mixinSelection(results, count, true);
-                    }
-
-                    function registerFilter(filter, optional) {
-                        if (typeof (optional) == "function") {
-                            filter = {
-                                name: filter,
-                                filter: optional,
-                            };
-                        }
-
-                        filters[filter.name] = filter;
-                        index = null;
-                        proto = null;
-                        version += 1;
-                    }
-
-                    /* The one filter */
-                    registerFilter("one", function() {
-                        var link;
-                        for (link in this)
-                            return this[link];
-                        return null;
-                    });
-
-                    /* The extend filter */
-                    registerFilter("extend", function(target) {
-                        var link;
-                        for (link in this)
-                            target[link] = this[link];
-                        return target;
-                    });
-
-                    /* The label filter */
-                    registerFilter({
-                        name: "label",
-                        digests: function(arg) {
-                            var ret = [];
-                            if (!arg)
-                                return ret;
-                            var i;
-                            var meta = arg.metadata;
-                            var labels = meta ? meta.labels : arg;
-                            for (i in labels || [])
-                                ret.push(i + "=" + labels[i]);
-                            return ret;
-                        }
-                    });
-
-                    /* The namespace filter */
-                    registerFilter({
-                        name: "namespace",
-                        digest: function(arg) {
-                            if (!arg)
-                                return null;
-                            if (typeof arg === "string")
-                                return arg;
-                            var meta = arg.metadata;
-                            return meta ? meta.namespace : null;
-                        }
-                    });
-
-                    /* The name filter */
-                    registerFilter({
-                        name: "name",
-                        digest: function(arg) {
-                            if (!arg)
-                                return null;
-                            if (typeof arg === "string")
-                                return arg;
-                            var meta = arg.metadata;
-                            return meta ? meta.name : null;
-                        }
-                    });
-
-                    /* The kind filter */
-                    registerFilter({
-                        name: "kind",
-                        digest: function(arg) {
-                            if (!arg)
-                                return null;
-                            if (typeof arg === "string")
-                                return arg;
-                            return arg.kind;
-                        }
-                    });
-
-                    /* The host filter */
-                    registerFilter({
-                        name: "host",
-                        digest: function(arg) {
-                            if (!arg)
-                                return null;
-                            if (typeof arg === "string")
-                                return arg;
-                            var spec = arg.spec;
-                            return spec ? spec.nodeName : null;
-                        }
-                    });
-
-                    /* The namespace filter */
-                    registerFilter({
-                        name: "uid",
-                        digest: function(arg) {
-                            if (!arg)
-                                return null;
-                            if (typeof arg === "string")
-                                return arg;
-                            var meta = arg.metadata;
-                            return meta ? meta.uid : null;
-                        }
-                    });
-
-                    /* The statusPhase filter */
-                    registerFilter({
-                        name: "statusPhase",
-                        digest: function(arg) {
-                            var status;
-                            if (typeof arg == "string") {
-                                return arg;
-                            } else {
-                                status = arg.status || { };
-                                return status.phase ? status.phase : null;
-                            }
-                        }
-                    });
-
-                    var empty = { };
-
-                    function select(arg) {
-                        var cache;
-                        var indexed = false;
-                        if (arg === undefined) {
-                            arg = loader.objects;
-                            indexed = true;
-                        } else if (!arg) {
-                            arg = empty;
-                        }
-
-                        /* Next the specific object */
-                        if (typeof arg !== "object") {
-                            console.warn("Pass resources or resource dicts or null to kubeSelect()");
-                            arg = empty;
-                        }
-
-                        cache = cached(arg);
-                        if (cache.selection)
-                            return cache.selection;
-
-                        /* A single resource object */
-                        var meta, single;
-                        if (typeof arg.kind === "string") {
-                            if (!cache.single) {
-                                meta = arg.meta || { };
-                                single = { };
-                                single[meta.selfLink || 1] = arg;
-                                cache.single = mixinSelection(single, undefined, false);
-                            }
-                            return cache.single;
-                        }
-
-                        return mixinSelection(arg, undefined, indexed);
-                    }
-
-                    /* A seldom used 'static' method */
-                    select.register = registerFilter;
-
-                    return select;
-                }
-            ])
-
-    /**
-     * kubeMethods
-     *
-     * Methods that operate on kubernetes objects.
-     *
-     * promise = methods.create(objects, namespace)
-     *
-     * Create the given resource or objects in the specified namespace.
-     *
-     * promise = methods.remove(resource)
-     * promise = methods.remove(path)
-     * promise = methods.remove(type, name, namespace)
-     *
-     * Delete the given resource from kubernetes.
-     */
-            .factory("kubeMethods", [
-                "$q",
-                "KUBE_SCHEMA",
-                "KubeRequest",
-                "kubeLoader",
-                function($q, KUBE_SCHEMA, KubeRequest, loader) {
-                    function createCompare(a, b) {
-                        var sa = KUBE_SCHEMA[a.kind].create || 0;
-                        var sb = KUBE_SCHEMA[b.kind].create || 0;
-                        return sa - sb;
-                    }
-
-                    function createObjects(objects, namespace) {
-                        var defer = $q.defer();
-                        var promise = defer.promise;
-                        var request = null;
-
-                        if (!angular.isArray(objects)) {
-                            if (objects.kind == "List")
-                                objects = objects.items;
-                            else
-                                objects = [ objects ];
-                        }
-
-                        var haveNs = false;
-                        var wantNs = false;
-
-                        objects.forEach(function(resource) {
-                            var meta = resource.metadata || { };
-                            if ((resource.kind == "Namespace" || resource.kind == "Project") && meta.name === namespace)
-                                haveNs = true;
-                            var schema = SCHEMA[resource.kind] || SCHEMA[""];
-                            if (!schema.global)
-                                wantNs = true;
-                        });
-
-                        /* Shallow copy of the array, we modify it below */
-                        objects = objects.slice();
-
-                        /* Create the namespace  */
-                        if (namespace && wantNs && !haveNs) {
-                            objects.unshift({
-                                apiVersion : "v1",
-                                kind : "Namespace",
-                                metadata : { name: namespace }
-                            });
-                        }
-
-                        /* Now sort the array with create preference */
-                        objects.sort(createCompare);
-
-                        function step() {
-                            var resource = objects.shift();
-                            if (!resource) {
-                                defer.resolve();
-                                return;
-                            }
-
-                            var path = resourcePath([resource.kind, null, namespace || "default"]);
-                            path += "?timeout=" + REQ_TIMEOUT;
-
-                            request = new KubeRequest("POST", path, JSON.stringify(resource))
-                                    .then(function(response) {
-                                        var meta;
-
-                                        debug("created resource:", path, response.data);
-                                        if (response.data.kind) {
-                                            /* HACK: https://github.com/openshift/origin/issues/8167 */
-                                            if (response.data.kind == "Project") {
-                                                meta = response.data.metadata || { };
-                                                delete meta.selfLink;
-                                            }
-                                            loader.handle(response.data);
-                                        }
-                                        step();
-                                    }, function(response) {
-                                        var resp = response.data;
-                                        var code = response.status;
-                                        if (resp && resp.code)
-                                            code = resp.code;
-
-                                        /* Ignore failures creating the namespace if it already exists */
-                                        if (resource.kind == "Namespace" && (code === 409 || code === 403)) {
-                                            debug("skipping namespace creation");
-                                            step();
-                                        } else {
-                                            debug("create failed:", path, resp || response);
-                                            defer.reject(resp || response);
-                                        }
-                                    });
-                        }
-
-                        step();
-
-                        promise.cancel = function cancel() {
-                            if (request)
-                                request.cancel();
-                        };
-                        return promise;
-                    }
-
-                    function deleteResource(/* ... */) {
-                        var path = resourcePath(arguments);
-                        var resource = loader.objects[path];
-                        path += "?timeout=" + REQ_TIMEOUT;
-                        var promise = new KubeRequest("DELETE", path);
-                        return promise.then(function() {
-                            debug("deleted resource:", path, resource);
-                            if (resource)
-                                loader.handle(resource, true);
-                        }, function(response) {
-                            var resp = response.data;
-                            return $q.reject(resp || response);
-                        });
-                    }
-
-                    function patchResource(resource, patch) {
-                        var path = resourcePath([resource]);
-                        path += "?timeout=" + REQ_TIMEOUT;
-                        var body = JSON.stringify(patch);
-                        var config = { headers: { "Content-Type": "application/strategic-merge-patch+json" } };
-                        var promise = new KubeRequest("PATCH", path, body, config);
-                        return promise.then(function(response) {
-                            debug("patched resource:", path, response.data);
-                            if (response.data.kind)
-                                loader.handle(response.data);
-                        }, function(response) {
-                            var resp = response.data;
-                            return $q.reject(resp || response);
-                        });
-                    }
-
-                    function generalMethodRequest(method, resource, body, config) {
-                        var path = resourcePath([resource]);
-                        if (method != "GET")
-                            path += "?timeout=" + REQ_TIMEOUT;
-                        var promise = new KubeRequest(method, path, JSON.stringify(body), config);
-                        return promise.then(function(response) {
-                            var resp = response.data;
-                            return resp || response;
-                        }, function(response) {
-                            var resp = response.data;
-                            return $q.reject(resp || response);
-                        });
-                    }
-
-                    function putResource(resource, body, config) {
-                        return generalMethodRequest("PUT", resource, body, config);
-                    }
-
-                    function postResource(resource, body, config) {
-                        return generalMethodRequest("POST", resource, body, config);
-                    }
-
-                    function checkResource(resource, targets) {
-                        var defer = $q.defer();
-                        var ex;
-                        var exs = [];
-
-                        if (!targets)
-                            targets = { };
-
-                        /* Some simple metadata checks */
-                        var meta = resource.metadata;
-                        if (meta) {
-                            ex = null;
-                            if (meta.name !== undefined) {
-                                var check_re = (resource.kind == "User" || resource.kind == "Group") ? USER_NAME_RE : NAME_RE;
-                                if (!meta.name)
-                                    ex = new Error("The name cannot be empty");
-                                else if (!check_re.test(meta.name))
-                                    if (check_re == NAME_RE) {
-                                        ex = new Error("The name contains invalid characters. Only letters, numbers and dashes are allowed");
-                                    } else {
-                                        ex = new Error("The name contains invalid characters. Only letters, numbers, spaces and the following symbols are allowed: , = @  . _ - :");
-                                    }
-                            }
-                            if (ex) {
-                                ex.target = targets["metadata.name"];
-                                exs.push(ex);
-                            }
-
-                            ex = null;
-                            if (meta.namespace !== undefined) {
-                                if (!meta.namespace)
-                                    ex = new Error("The namespace cannot be empty");
-                                else if (!NAME_RE.test(meta.namespace))
-                                    ex = new Error("The name contains invalid characters. Only letters, numbers and dashes are allowed");
-                            }
-                            if (ex) {
-                                ex.target = targets["metadata.namespace"];
-                                exs.push(ex);
-                            }
-                        }
-
-                        if (exs.length)
-                            defer.reject(exs);
-                        else
-                            defer.resolve();
-                        return defer.promise;
-                    }
-
-                    return {
-                        "create": createObjects,
-                        "delete": deleteResource,
-                        "check": checkResource,
-                        "patch": patchResource,
-                        post: postResource,
-                        put: putResource,
-                    };
-                }
-            ])
-
-    /**
-     * KubeRequest
-     *
-     * Create a new low level kubernetes request. These are instantiated
-     * by kubeLoader or kubeMethods, and typically not used directly.
-     *
-     * An implementation of KubeRequest must be provided. It has the
-     * following characteristics.
-     *
-     * promise = KubeRequest(method, path, [body, [config]])
-     *
-     * Creates a new request, for the given HTTP method and path. If body
-     * is present it will be sent as the request body. If it an object or
-     * array it will be encoded as JSON before being sent.
-     *
-     * If present the config object may include the following properties:
-     *
-     *  headers    An dict of headers to include
-     *
-     * In addition the config object can include implementation specific
-     * settings or data.
-     *
-     * If successful the promise will resolve with a response object that
-     * includes the following:
-     *
-     * status      Status code
-     * statusText  Status reason or message
-     * data        Response body, JSON decoded if response is json
-     * headers     Response headers
-     *
-     * Implementation specific fields may also be present
-     */
-
-            .provider("KubeRequest", [
-                function() {
-                    var self = this;
-
-                    /* Until we come up with a good default implementation, must be provided */
-                    self.KubeRequestFactory = "MissingKubeRequest";
-
-                    function load(injector, name) {
-                        if (angular.isString(name))
-                            return injector.get(name, "KubeRequest");
-                        else
-                            return injector.invoke(name);
-                    }
-
-                    self.$get = [
-                        "$injector",
-                        function($injector) {
-                            return load($injector, self.KubeRequestFactory);
-                        }
-                    ];
-                }
-            ])
-
-            .factory("MissingKubeRequest", [
-                function() {
-                    return function MissingKubeRequest(path, callback) {
-                        throw new Error("no KubeRequestFactory set");
-                    };
-                }
-            ])
-
-    /**
-     * KubeSocket
-     *
-     * Create a new low level kubernetes websocket request
-     *
-     * An implementation of KubeSocket must be provided. It has the
-     * following characteristics.
-     *
-     * ws = KubeSocket(path, [config])
-     *
-     * Creates a new websocket request, for the given path.
-     *
-     *  headers    An dict of headers to include
-     *  protocals  An list or string of websocket protocols
-     *
-     * In addition the config object can include implementation specific
-     * settings or data.
-     *
-     * A object is returned that implements the Web API
-     * Websocket interface. Specifically it should
-     * expose a 'readyState' attribute, provide
-     * open and close functions, and emit open, close and
-     * message events.
-     *
-     * Implementation specific fields may also be present
-     */
-
-            .provider("KubeSocket", [
-                function() {
-                    var self = this;
-
-                    /* Until we come up with a good default implementation, must be provided */
-                    self.KubeSocketFactory = "MissingKubeSocket";
-
-                    function load(injector, name) {
-                        if (angular.isString(name))
-                            return injector.get(name, "KubeSocket");
-                        else
-                            return injector.invoke(name);
-                    }
-
-                    self.$get = [
-                        "$injector",
-                        function($injector) {
-                            return load($injector, self.KubeSocketFactory);
-                        }
-                    ];
-                }
-            ])
-
-            .factory("MissingKubeSocket", [
-                function() {
-                    return function MissingKubeSocket(path, callback) {
-                        throw Error("no KubeSocketFactory set");
-                    };
-                }
-            ])
-
-    /**
-     * KubeWatch
-     *
-     * Create a new low level kubernetes watch. These are instantiated
-     * by kubeLoader, and typically not used directly.
-     *
-     * An implementation of the KubeWatch must be provided. It has the
-     * following characteristics:
-     *
-     * promise = KubeWatch(path, callback)
-     *
-     * The watch is given two arguments. The first is the kube resource
-     * url to watch (without query string) a callback to invoke with
-     * watch frames.
-     *
-     * The watch returns a deferred promise which will resolve when the initial
-     * set of items has loaded, it will fail if the watch fails. The promise
-     * should also have a promise.cancel() method which is invoked when the
-     * watch should be stopped.
-     *
-     * callback(frames)
-     *
-     * The callback is invoked with an array of kubernetes watch frames that
-     * look like: { type: "ADDED", object: { ... } }
-     */
-
-            .provider("KubeWatch", [
-                function() {
-                    var self = this;
-
-                    /* Until we come up with a good default implementation, must be provided */
-                    self.KubeWatchFactory = "MissingKubeWatch";
-
-                    function load(injector, name) {
-                        if (angular.isString(name))
-                            return injector.get(name, "KubeWatch");
-                        else
-                            return injector.invoke(name);
-                    }
-
-                    self.$get = [
-                        "$injector",
-                        function($injector) {
-                            return load($injector, self.KubeWatchFactory);
-                        }
-                    ];
-                }
-            ])
-
-            .factory("MissingKubeWatch", [
-                function() {
-                    return function MissingKubeWatch(path, callback) {
-                        throw Error("no KubeWatchFactory set");
-                    };
-                }
-            ])
-
-            .provider("KubeDiscoverSettings", [
-                function() {
-                    var self = this;
-
-                    /* Until we come up with a good default implementation, must be provided */
-                    self.KubeDiscoverSettingsFactory = "MissingKubeDiscoverSettings";
-
-                    function load(injector, name) {
-                        if (angular.isString(name))
-                            return injector.get(name, "KubeDiscoverSettings");
-                        else
-                            return injector.invoke(name);
-                    }
-
-                    self.$get = [
-                        "$injector",
-                        function($injector) {
-                            return load($injector, self.KubeDiscoverSettingsFactory);
-                        }
-                    ];
-                }
-            ])
-
-            .factory("MissingKubeDiscoverSettings", [
-                function() {
-                    return function MissingKubeDiscoverSettings(path, callback) {
-                        throw Error("no KubeDiscoverSettingsFactory set");
-                    };
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/listing.js b/pkg/kubernetes/scripts/listing.js
deleted file mode 100644
index 0a2a5ccfb..000000000
--- a/pkg/kubernetes/scripts/listing.js
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    var angular = require('angular');
-
-    require('../views/user-panel.html');
-    require('../views/service-panel.html');
-    require('../views/pod-panel.html');
-    require('../views/route-panel.html');
-    require('../views/pv-panel.html');
-    require('../views/default-panel.html');
-    require('../views/node-panel.html');
-    require('../views/project-panel.html');
-    require('../views/container-panel.html');
-    require('../views/deploymentconfig-panel.html');
-    require('../views/group-panel.html');
-    require('../views/replicationcontroller-panel.html');
-
-    function inClassOrTag(el, cls, tag) {
-        return (el && el.classList && el.classList.contains(cls)) ||
-               (el && el.tagName === tag) ||
-               (el && inClassOrTag(el.parentNode, cls, tag));
-    }
-
-    angular.module('kubernetes.listing', [])
-
-            .directive('listingTable', [
-                function() {
-                    return {
-                        restrict: 'A',
-                        link: function(scope, element, attrs) {
-                        }
-                    };
-                }
-            ])
-
-            .factory('ListingState', [
-                function() {
-                    return function ListingState(scope) {
-                        var self = this;
-                        var data = { };
-
-                        self.selected = { };
-                        self.enableActions = false;
-
-                        /* Check that either .btn or li were not clicked */
-                        function checkBrowserEvent(ev) {
-                            return !(ev && inClassOrTag(ev.target, "btn", "li"));
-                        }
-
-                        self.hasSelected = function hasSelected(id) {
-                            return !angular.equals({}, self.selected);
-                        };
-
-                        self.expanded = function expanded(id) {
-                            if (angular.isUndefined(id)) {
-                                for (id in data)
-                                    return true;
-                                return false;
-                            } else {
-                                return id in data;
-                            }
-                        };
-
-                        self.toggle = function toggle(id, ev) {
-                            var value;
-                            if (self.enableActions) {
-                                ev.stopPropagation();
-                                return;
-                            }
-
-                            if (id) {
-                                value = !(id in data);
-                                if (value)
-                                    self.expand(id, ev);
-                                else
-                                    self.collapse(id, ev);
-                            }
-                        };
-
-                        self.expand = function expand(id, ev) {
-                            data[id] = true;
-                            if (ev)
-                                ev.stopPropagation();
-                        };
-
-                        self.activate = function activate(id, ev) {
-                            if (checkBrowserEvent(ev)) {
-                                if (self.expanded(id))
-                                    self.collapse(id);
-                                else
-                                    scope.$emit("activate", id);
-                            }
-                        };
-
-                        self.collapse = function collapse(id, ev) {
-                            if (id) {
-                                delete data[id];
-                            } else {
-                                Object.keys(data).forEach(function(old) {
-                                    delete data[old];
-                                });
-                            }
-                            if (ev)
-                                ev.stopPropagation();
-                        };
-                    };
-                }
-            ])
-
-            .directive('listingPanel', [
-                function() {
-                    return {
-                        restrict: 'A',
-                        scope: true,
-                        link: function(scope, element, attrs) {
-                            var tab = 'main';
-                            scope.tab = function(name, ev) {
-                                if (ev) {
-                                    tab = name;
-                                    ev.stopPropagation();
-                                }
-                                return tab === name;
-                            };
-                        },
-                        templateUrl: function(element, attrs) {
-                            var kind = attrs.kind;
-                            return "views/" + kind.toLowerCase() + "-panel.html";
-                        }
-                    };
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/main.js b/pkg/kubernetes/scripts/main.js
deleted file mode 100644
index 0c141ffa7..000000000
--- a/pkg/kubernetes/scripts/main.js
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-(function() {
-    /* Tell webpack what to bundle here */
-    var angular = require('angular');
-    require('angular-route');
-    require('angular-gettext/dist/angular-gettext.js');
-    require('angular-bootstrap-npm/dist/angular-bootstrap.js');
-    require('kubernetes-container-terminal/dist/container-terminal.js');
-    require('object-describer/dist/object-describer.js');
-    require('kubernetes-object-describer/dist/object-describer.js');
-
-    /* The kubernetes client */
-    require('./kube-client');
-    require('./kube-client-cockpit');
-
-    /* The other angular modules */
-    require('./containers');
-    require('./dashboard');
-    require('./details');
-    require('./graphs');
-    require('./policy');
-    require('./projects');
-    require('./images');
-    require('./nodes');
-    require('./topology');
-    require('./volumes');
-
-    /* And the actual application */
-    require('./app');
-
-    angular.module('kubernetes', [
-        'ngRoute',
-        'ui.bootstrap',
-        'gettext',
-        'kubeClient',
-        'kubeClient.cockpit',
-        'kubernetes.app',
-        'kubernetes.graph',
-        'kubernetes.dashboard',
-        'kubernetes.containers',
-        'kubernetes.details',
-        'kubernetes.topology',
-        'kubernetes.volumes',
-        'kubernetes.nodes',
-        'kubernetes.date',
-        'registry.images',
-        'registry.policy',
-        'registry.projects',
-        'registryUI.date',
-        'kubernetesUI'
-    ])
-
-            .config([
-                '$routeProvider',
-                'KubeWatchProvider',
-                'KubeRequestProvider',
-                'KubeSocketProvider',
-                'KubeTranslateProvider',
-                'KubeFormatProvider',
-                'kubernetesContainerSocketProvider',
-                'KubeDiscoverSettingsProvider',
-                'KubeBrowserStorageProvider',
-                'MomentLibProvider',
-                '$provide',
-                function($routeProvider, KubeWatchProvider, KubeRequestProvider,
-                    KubeSocketProvider, KubeTranslateProvider, KubeFormatProvider,
-                    kubernetesContainerSocketProvider, KubeDiscoverSettingsProvider,
-                    KubeBrowserStorageProvider, MomentLibProvider, $provide) {
-                    $routeProvider.otherwise({ redirectTo: '/' });
-
-                    /* Tell the kube-client code to use cockpit watches and requests */
-                    KubeWatchProvider.KubeWatchFactory = "CockpitKubeWatch";
-                    KubeRequestProvider.KubeRequestFactory = "CockpitKubeRequest";
-                    KubeSocketProvider.KubeSocketFactory = "CockpitKubeSocket";
-                    KubeTranslateProvider.KubeTranslateFactory = "CockpitTranslate";
-                    KubeFormatProvider.KubeFormatFactory = "CockpitFormat";
-                    KubeDiscoverSettingsProvider.KubeDiscoverSettingsFactory = "cockpitKubeDiscoverSettings";
-                    KubeBrowserStorageProvider.KubeBrowserStorageFactory = "cockpitBrowserStorage";
-                    MomentLibProvider.MomentLibFactory = "momentLib";
-
-                    /* Tell the container-terminal that we want to be involved in WebSocket creation */
-                    kubernetesContainerSocketProvider.WebSocketFactory = 'cockpitContainerWebSocket';
-
-                    $provide.decorator("$exceptionHandler",
-                                       ['$delegate',
-                                           '$log',
-                                           function($delegate, $log) {
-                                               return function (exception, cause) {
-                                                   /* Displays an oops if we're running in cockpit */
-                                                   if (window.parent !== window && window.name.indexOf("cockpit1:") === 0)
-                                                       window.parent.postMessage("\n{ \"command\": \"oops\" }", "*");
-
-                                                   $delegate(exception, cause);
-                                               };
-                                           }]);
-                }
-            ]);
-}());
diff --git a/pkg/kubernetes/scripts/nodes.js b/pkg/kubernetes/scripts/nodes.js
deleted file mode 100644
index bd15e30f9..000000000
--- a/pkg/kubernetes/scripts/nodes.js
+++ /dev/null
@@ -1,898 +0,0 @@
-/*
- * This file is part of Cockpit.
- *
- * Copyright (C) 2016 Red Hat, Inc.
- *
- * Cockpit is free software; you can redistribute it and/or modify it
- * under the terms of the GNU Lesser General Public License as published by
- * the Free Software Foundation; either version 2.1 of the License, or
- * (at your option) any later version.
- *
- * Cockpit is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with Cockpit; If not, see .
- */
-
-/* This is here to support cockpit.jump
- * If this ever needs to be used outsite of cockpit
- * then we'll need abstract this away in kube-client-cockpit
- */
-/* globals cockpit */
-
-(function() {
-    var angular = require('angular');
-    var d3 = require('d3');
-    require('angular-route');
-    require('angular-dialog.js');
-
-    require('./charts');
-    require('./date');
-    require('./kube-client');
-    require('./listing');
-    require('./utils');
-
-    require('../views/nodes-page.html');
-    require('../views/node-page.html');
-    require('../views/node-body.html');
-    require('../views/node-capacity.html');
-    require('../views/node-stats.html');
-    require('../views/node-add.html');
-    require('../views/node-delete.html');
-    require('../views/node-alerts.html');
-
-    angular.module('kubernetes.nodes', [
-        'ngRoute',
-        'kubeClient',
-        'kubernetes.date',
-        'kubernetes.listing',
-        'kubeUtils',
-        'ui.cockpit',
-        'ui.charts',
-    ])
-
-            .config([
-                '$routeProvider',
-                function($routeProvider) {
-                    $routeProvider
-                            .when('/nodes', {
-                                templateUrl: 'views/nodes-page.html',
-                                controller: 'NodeCtrl'
-                            })
-
-                            .when('/nodes/:target', {
-                                controller: 'NodeCtrl',
-                                templateUrl: 'views/node-page.html'
-                            });
-                }
-            ])
-
-    /*
-     * The controller for the node view.
-     */
-            .controller('NodeCtrl', [
-                '$scope',
-                'kubeLoader',
-                'kubeSelect',
-                'ListingState',
-                'filterService',
-                '$routeParams',
-                '$location',
-                'nodeActions',
-                'nodeData',
-                'nodeStatsSummary',
-                '$timeout',
-                'KubeBrowserStorage',
-                function($scope, loader, select, ListingState, filterService,
-                    $routeParams, $location, actions, nodeData, statsSummary,
-                    $timeout, browser) {
-                    var target = $routeParams["target"] || "";
-                    $scope.target = target;
-
-                    $scope.stats = statsSummary.newNodeStatsSummary();
-
-                    loader.listen(function() {
-                        var selection;
-                        $scope.nodes = select().kind("Node");
-                        if (target) {
-                            selection = select().kind("Node")
-                                    .name(target);
-                            $scope.item = selection.one();
-                        } else {
-                            selection = $scope.nodes;
-                        }
-                        if ($scope.stats)
-                            $scope.stats.trackNodes(selection);
-                    }, $scope);
-
-                    loader.watch("Node", $scope);
-
-                    $scope.$on("$destroy", function() {
-                        if ($scope.stats)
-                            $scope.stats.close();
-                        $scope.stats = null;
-                    });
-
-                    $scope.listing = new ListingState($scope);
-
-                    /* All the actions available on the $scope */
-                    angular.extend($scope, actions);
-                    angular.extend($scope, nodeData);
-
-                    $scope.$on("activate", function(ev, id) {
-                        $location.path('/nodes/' + encodeURIComponent(id));
-                        $scope.$applyAsync();
-                    });
-
-                    $scope.nodePods = function node_pods(item) {
-                        var meta = item.metadata || {};
-                        return select().kind("Pod")
-                                .host(meta.name);
-                    };
-
-                    $scope.deleteSelectedNodes = function() {
-                        var k;
-                        var selected = [];
-                        for (k in $scope.listing.selected) {
-                            if ($scope.nodes[k] && $scope.listing.selected[k])
-                                selected.push($scope.nodes[k]);
-                        }
-
-                        if (!selected.length)
-                            return;
-
-                        return actions.deleteNodes(selected).then(function() {
-                            $scope.listing.selected = {};
-                        });
-                    };
-
-                    /* Redirect after a delete */
-                    $scope.deleteNode = function(val) {
-                        var promise = actions.deleteNodes(val);
-
-                        /* If the promise is successful, redirect to another page */
-                        promise.then(function() {
-                            if ($scope.target)
-                                $location.path("/nodes");
-                        });
-
-                        return promise;
-                    };
-
-                    $scope.jump = function (node) {
-                        var host, ip;
-                        if (!node || !node.metadata)
-                            return;
-
-                        host = node.metadata.name;
-                        ip = nodeData.nodeIPAddress(node);
-
-                        if (ip == "127.0.0.1" || ip == "::1") {
-                            ip = "localhost";
-                        } else {
-                            browser.sessionStorage.setItem(
-                                "v1-session-machine/" + ip,
-                                JSON.stringify({ "address": ip,
-                                                 "label": host,
-                                                 visible: true })
-                            );
-                        }
-
-                        cockpit.jump("/", ip);
-                    };
-                }
-            ])
-
-            .directive('nodeBody',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/node-body.html',
-                           };
-                       }
-            )
-
-            .directive('nodeCapacity',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/node-capacity.html',
-                           };
-                       }
-            )
-
-            .directive('nodeStats',
-                       function() {
-                           return {
-                               restrict: 'A',
-                               templateUrl: 'views/node-stats.html',
-                           };
-                       }
-            )
-
-            .factory('nodeActions', [
-                '$modal',
-                function($modal) {
-                    function addNode() {
-                        return $modal.open({
-                            animation: false,
-                            controller: 'AddNodeCtrl',
-                            templateUrl: 'views/node-add.html',
-                            resolve: {},
-                        }).result;
-                    }
-
-                    function deleteNodes(val) {
-                        var nodes;
-                        if (angular.isArray(val))
-                            nodes = val;
-                        else
-                            nodes = [ val ];
-
-                        return $modal.open({
-                            animation: false,
-                            controller: 'NodeDeleteCtrl',
-                            templateUrl: 'views/node-delete.html',
-                            resolve: {
-                                dialogData: function() {
-                                    return { nodes: nodes };
-                                }
-                            },
-                        }).result;
-                    }
-
-                    return {
-                        addNode: addNode,
-                        deleteNodes: deleteNodes
-                    };
-                }
-            ])
-
-            .controller("NodeDeleteCtrl", [
-                "$q",
-                "$scope",
-                "$modalInstance",
-                "dialogData",
-                "kubeMethods",
-                "kubeSelect",
-                function($q, $scope, $instance, dialogData, methods, select) {
-                    angular.extend($scope, dialogData);
-
-                    $scope.performDelete = function performDelete() {
-                        var k;
-                        var errors = [];
-                        var nodes = {};
-                        var promises = [];
-
-                        function handleError(ex) {
-                            errors.push(ex.message || ex.statusText);
-                            nodes[k] = $scope.nodes[k];
-                            return $q.reject();
-                        }
-
-                        for (k in $scope.nodes) {
-                            var p = methods.delete($scope.nodes[k])
-                                    .catch(handleError);
-                            promises.push(p);
-                        }
-
-                        return $q.all(promises).catch(function () {
-                            $scope.nodes = select(nodes);
-                            return $q.reject(errors);
-                        });
-                    };
-                }
-            ])
-
-            .factory('nodeData', [
-                "KubeMapNamedArray",
-                "KubeTranslate",
-                function (mapNamedArray, translate) {
-                    const _ = translate.gettext;
-
-                    function nodeConditions(node) {
-                        var status;
-                        if (!node)
-                            return;
-
-                        if (!node.conditions) {
-                            status = node.status || { };
-                            node.conditions = mapNamedArray(status.conditions, "type");
-                        }
-                        return node.conditions;
-                    }
-
-                    function nodeCondition(node, type) {
-                        var conditions = nodeConditions(node) || {};
-                        return conditions[type] || {};
-                    }
-
-                    function nodeStatus(node) {
-                        var spec = node ? node.spec : {};
-                        if (!nodeCondition(node, "Ready").status)
-                            return _("Unknown");
-
-                        if (nodeCondition(node, "Ready").status != 'True')
-                            return _("Not Ready");
-
-                        if (spec && spec.unschedulable)
-                            return _("Scheduling Disabled");
-
-                        return _("Ready");
-                    }
-
-                    function nodeStatusIcon(node) {
-                        var state = "";
-                        /* If no status.conditions then it hasn't even started */
-                        if (!nodeCondition(node, "Ready").status) {
-                            state = "wait";
-                        } else {
-                            if (nodeCondition(node, "Ready").status != 'True') {
-                                state = "fail";
-                            } else if (nodeCondition(node, "OutOfDisk").status == "True" ||
-                             nodeCondition(node, "OutOfMemory").status == "True") {
-                                state = "warn";
-                            }
-                        }
-                        return state;
-                    }
-
-                    function nodeIPAddress(node) {
-                        if (!node || !node.status)
-                            return;
-
-                        var addresses = node.status.addresses;
-                        var address;
-                        var internal;
-                        /* If no addresses then it hasn't even started */
-                        if (addresses) {
-                            addresses.forEach(function(a) {
-                                if (a.type == "LegacyHostIP" || a.type == "ExternalIP") {
-                                    address = a.address;
-                                    return false;
-                                } else if (a.type == "InternalIP") {
-                                    internal = a.address;
-                                }
-                            });
-                        }
-
-                        return address || internal;
-                    }
-
-                    return {
-                        nodeStatusIcon: nodeStatusIcon,
-                        nodeCondition: nodeCondition,
-                        nodeConditions: nodeConditions,
-                        nodeStatus: nodeStatus,
-                        nodeIPAddress: nodeIPAddress
-                    };
-                }
-            ])
-
-            .controller("AddNodeCtrl", [
-                "$q",
-                "$scope",
-                "$modalInstance",
-                "kubeMethods",
-                "KubeTranslate",
-                function($q, $scope, $instance, methods, translate) {
-                    const _ = translate.gettext;
-                    var fields = {
-                        "address" : "",
-                        "name" : "",
-                    };
-                    var dirty = false;
-
-                    $scope.fields = fields;
-
-                    function validate() {
-                        var regex = /^[a-z0-9.-]+$/i;
-                        var defer = $q.defer();
-                        var address = fields.address.trim();
-                        var name = fields.name.trim();
-                        var ex;
-                        var failures = [];
-                        var item;
-
-                        if (!address)
-                            ex = new Error(_("Please type an address"));
-                        else if (!regex.test(address))
-                            ex = new Error(_("The address contains invalid characters"));
-
-                        if (ex) {
-                            ex.target = "#node-address";
-                            failures.push(ex);
-                        }
-
-                        if (name && !regex.test(name)) {
-                            ex = new Error(_("The name contains invalid characters"));
-                            ex.target = "#node-name";
-                            failures.push(ex);
-                        }
-
-                        if (failures.length > 0) {
-                            defer.reject(failures);
-                        } else {
-                            item = {
-                                "kind": "Node",
-                                "apiVersion": "v1",
-                                "metadata": {
-                                    "name": name || address,
-                                }
-                            };
-                            defer.resolve(item);
-                        }
-
-                        return defer.promise;
-                    }
-
-                    $scope.nameKeyUp = function nameKeyUp(event) {
-                        dirty = true;
-                        if (event.keyCode == 13)
-                            $scope.performAdd();
-                    };
-
-                    $scope.addressKeyUp = function addressKeyUp(event) {
-                        if (event.keyCode == 13)
-                            $scope.performAdd();
-                        else if (!dirty)
-                            fields.name = event.target.value;
-                    };
-
-                    $scope.performAdd = function performAdd() {
-                        return validate().then(function(item) {
-                            return methods.create(item);
-                        });
-                    };
-                }
-            ])
-
-            .directive('kubernetesStatusIcon', function() {
-                return {
-                    restrict: 'A',
-                    link: function($scope, element, attributes) {
-                        $scope.$watch(attributes["status"], function(status) {
-                            element
-                                    .toggleClass("spinner spinner-xs", status == "wait")
-                                    .toggleClass("pficon pficon-error-circle-o", status == "fail")
-                                    .toggleClass("pficon pficon-warning-triangle-o", status == "warn");
-                        });
-                    }
-                };
-            })
-
-            .directive('nodeAlerts', function() {
-                return {
-                    restrict: 'A',
-                    templateUrl: 'views/node-alerts.html'
-                };
-            })
-
-            .factory('nodeStatsSummary', [
-                "$q",
-                "$interval",
-                "$exceptionHandler",
-                "KubeRequest",
-                "nodeData",
-                "KubeStringToBytes",
-                "KubeFormat",
-                function ($q, $interval, $exceptionHandler, KubeRequest, nodeData,
-                    kubeStringToBytes, format) {
-                    function NodeStatsSummary() {
-                        var self = this;
-
-                        var requests = {};
-                        var statData = {};
-                        var callbacks = [];
-                        var interval;
-
-                        function request(name) {
-                            if (requests[name])
-                                return $q.when([]);
-
-                            var path = "/api/v1/nodes/" + encodeURIComponent(name) + "/proxy/stats/summary/";
-                            var req = KubeRequest("GET", path);
-                            requests[name] = req;
-
-                            return req.then(function(data) {
-                                delete requests[name];
-                                statData[name] = data.data;
-                            })
-                                    .catch(function(ex) {
-                                        delete requests[name];
-                                        delete statData[name];
-                                        if (ex.status != 503)
-                                            console.warn(ex);
-                                    });
-                        }
-
-                        function invokeCallbacks(/* ... */) {
-                            var i, len, func;
-                            for (i = 0, len = callbacks.length; i < len; i++) {
-                                func = callbacks[i];
-                                try {
-                                    if (func)
-                                        func.apply(self, arguments);
-                                } catch (e) {
-                                    $exceptionHandler(e);
-                                }
-                            }
-                        }
-
-                        function fetchForNames(names) {
-                            var q = [];
-                            angular.forEach(names, function(name) {
-                                q.push(request(name));
-                            });
-
-                            $q.all(q).then(invokeCallbacks, invokeCallbacks);
-                        }
-
-                        interval = $interval(function () {
-                            fetchForNames(Object.keys(statData));
-                        }, 5000);
-
-                        self.watch = function watch(callback) {
-                            callbacks.push(callback);
-
-                            return {
-                                cancel: function() {
-                                    var i, len;
-                                    for (i = 0, len = callbacks.length; i < len; i++) {
-                                        if (callbacks[i] === callback)
-                                            callbacks[i] = null;
-                                    }
-                                }
-                            };
-                        };
-
-                        self.close = function close() {
-                            var name;
-                            if (interval)
-                                $interval.cancel(interval);
-
-                            for (name in requests) {
-                                var req = requests[name];
-                                if (req && req.cancel)
-                                    req.cancel();
-                            }
-                        };
-
-                        self.trackNodes = function trackNodes(selection) {
-                            var names = [];
-                            angular.forEach(selection, function(node) {
-                                var ready = nodeData.nodeCondition(node, "Ready");
-                                var meta = node ? node.metadata : {};
-                                var name = meta ? meta.name : "";
-
-                                if (ready && ready.status === 'True') {
-                                    if (!statData[name])
-                                        names.push(name);
-                                } else {
-                                    // Unfortunally i'm seen some requests
-                                    // not error so clean them out.
-                                    delete statData[name];
-                                    if (request[name]) {
-                                        request[name].cancel();
-                                        delete request[name];
-                                    }
-                                }
-                            });
-                            fetchForNames(names);
-                        };
-
-                        self.getSimpleUsage = function getSimpleUsage(node, section) {
-                            var meta = node ? node.metadata : {};
-                            var status = node ? node.status : {};
-                            var name = meta ? meta.name : "";
-
-                            var nodeData = statData[name] ? statData[name].node : {};
-                            var result = nodeData[section];
-
-                            if (!result)
-                                return;
-
-                            var allocatable = status ? status.allocatable : {};
-                            if (!allocatable)
-                                return;
-
-                            switch (section) {
-                            case "cpu":
-                                if (!allocatable.cpu)
-                                    return;
-                                return {
-                                    used: result.usageNanoCores,
-                                    total: allocatable.cpu * 1000000000
-                                };
-                            case "memory":
-                                if (!allocatable.memory)
-                                    return;
-                                return {
-                                    used: result.usageBytes,
-                                    total: kubeStringToBytes(allocatable.memory)
-                                };
-                            case "fs":
-                                return {
-                                    used: result.usedBytes,
-                                    total: result.capacityBytes
-                                };
-                            default:
-                            }
-                        };
-                    }
-
-                    return {
-                        newNodeStatsSummary: function(interval) {
-                            return new NodeStatsSummary(interval);
-                        },
-                    };
-                }
-            ])
-
-            .directive('nodeOsGraph', [
-                "KubeTranslate",
-                function(translate) {
-                    const _ = translate.gettext;
-
-                    return {
-                        scope: {
-                            'nodes' : '='
-                        },
-                        template: '
', - restrict: 'A', - link: function($scope, element, attributes) { - $scope.data = []; - $scope.largeTitle = 0; - - function refresh(items) { - items = items || []; - var data = {}; - angular.forEach(items, function(node) { - var os; - var color; - if (node.status && node.status.nodeInfo) - os = node.status.nodeInfo.osImage; - - if (!os) { - os = _("Unknown"); - color = "#bbbbbb"; - } - - if (data[os]) - data[os].value++; - else - data[os] = { value: 1, label: os, color: color }; - }); - - var arr = Object.keys(data).map(function(k) { - return data[k]; - }); - - arr.sort(function (a, b) { - if (a.label < b.label) - return -1; - if (a.label > b.label) - return 1; - return 0; - }); - - $scope.data = arr; - $scope.largeTitle = items.length; - } - - $scope.$watchCollection('nodes', function(nodes) { - refresh(nodes); - }); - } - }; - } - ]) - - .directive('nodeHeatMap', [ - "KubeTranslate", - "KubeFormat", - function(translate, format) { - const _ = translate.gettext; - return { - restrict: 'A', - scope: { - 'nodes' : '=', - 'stats' : '=' - }, - template: '
', - link: function($scope, element, attributes) { - var outer = d3.select(element[0]); - var currentTab; - var tabs = { - cpu: { - label: _("CPU"), - tooltip: function(r) { return format.format(_("CPU Utilization: $0%"), Math.round((r.used / r.total) * 100)) } - }, - memory: { - label: _("Memory"), - tooltip: function(r) { return format.format(_("Memory Utilization: $0%"), Math.round((r.used / r.total) * 100)) } - }, - fs: { - label: _("Disk"), - tooltip: function(r) { return format.format(_("Disk Utilization: $0%"), Math.round((r.used / r.total) * 100)) } - } - }; - - outer.select("ul.nav-tabs") - .selectAll("li") - .data(Object.keys(tabs)) - .enter() - .append("li") - .attr("data-metric", function(d) { return d }) - .append("a") - .text(function(d) { return tabs[d].label }); - - function changeTab(tab) { - currentTab = tab; - outer.selectAll("ul.nav-tabs li") - .attr("class", function(d) { return tab === d ? "active" : null }); - refreshData(); - } - - outer.selectAll("ul.nav-tabs li") - .on("click", function() { - changeTab(d3.select(this).attr("data-metric")); - }); - - function refreshData() { - var nodes = $scope.nodes; - var data = []; - - if (!nodes) - nodes = []; - - angular.forEach(nodes, function(node) { - var result, value, name; - var tooltip = _("Unknown"); - if (node && node.metadata) - name = node.metadata.name; - - if (!name) - return; - - result = $scope.stats.getSimpleUsage(node, currentTab); - if (result) - value = result.used / result.total; - - if (value === undefined) - value = -1; - else - tooltip = tabs[currentTab].tooltip(result); - - data.push({ value: value, name: name, - tooltip: tooltip }); - }); - - data.sort(function (a, b) { - return b.value - a.value; - }); - - $scope.$applyAsync(function() { - $scope.data = data; - }); - return true; - } - - $scope.$on("boxClick", function (ev, name) { - $scope.$emit("activate", name); - }); - - var sw = $scope.stats.watch(refreshData); - $scope.$on("$destroy", function() { - sw.cancel(); - }); - - changeTab("cpu"); - } - }; - } - ]) - - .directive('nodeUsageDonutChart', [ - "KubeTranslate", - "KubeFormat", - function(translate, format) { - const _ = translate.gettext; - return { - restrict: 'A', - scope: { - 'node' : '=', - 'stats' : '=', - }, - template: '
{{ title }}
', - link: function($scope, element, attributes) { - var colorFunc = d3.scale.threshold() - .domain([0.7, 0.8, 0.9]) - .range(['#d4f0fa', '#F9D67A', '#EC7A08', '#CE0000']); - - var types = { - cpu: { - label: _("CPU"), - smallTitle: function () {}, - largeTitle: function (result) { - var r = result.used / result.total; - var p = Math.round(r * 100); - return format.format("$0%", p); - }, - }, - memory: { - label: _("Memory"), - smallTitle: function (result) { - return _("Used"); - }, - largeTitle: function (result) { - return format.formatBytes(result.used); - }, - }, - fs: { - label: _("Disk"), - smallTitle: function (result) { - return _("Used"); - }, - largeTitle: function (result) { - return format.formatBytes(result.used); - }, - } - }; - - var type = attributes['type']; - $scope.title = types[type].label; - - function clear() { - $scope.$applyAsync(function() { - $scope.data = null; - $scope.smallTitle = null; - $scope.largeTitle = null; - }); - } - - function refreshData() { - var node = $scope.node; - var result; - - if (!node) - return clear(); - - result = $scope.stats.getSimpleUsage(node, type); - if (result) { - $scope.$applyAsync(function() { - $scope.smallTitle = types[type].smallTitle(result); - $scope.largeTitle = types[type].largeTitle(result); - var u = Math.round((result.used / result.total) * 100); - var l = 100 - u; - var freeText = translate.ngettext("$0% Free", - "$0% Free", u); - var usedText = translate.ngettext("$0% Used", - "$0% Used", u); - $scope.data = [ - { value: result.total - result.used, - tooltip : format.format(freeText, l), - color: "#bbbbbb" }, - { value: result.used, - tooltip : format.format(usedText, u), - color: colorFunc(result.used / result.total) } - ]; - }); - } else { - clear(); - } - return true; - } - - var sw = $scope.stats.watch(refreshData); - $scope.$on("$destroy", function() { - sw.cancel(); - }); - } - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/policy.js b/pkg/kubernetes/scripts/policy.js deleted file mode 100644 index d91f6c174..000000000 --- a/pkg/kubernetes/scripts/policy.js +++ /dev/null @@ -1,412 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('./kube-client'); - - angular.module('registry.policy', [ - 'kubeClient', - ]) - - .factory("projectPolicy", [ - '$q', - '$rootScope', - 'kubeLoader', - 'kubeMethods', - 'kubeSelect', - 'KubeWatch', - 'KubeRequest', - 'KUBE_SCHEMA', - function($q, $rootScope, loader, methods, select, watch, KubeRequest, KUBE_SCHEMA) { - var apiGroup; - var RBAC_GROUP = "rbac.authorization.k8s.io"; - var RBAC_API = "/apis/rbac.authorization.k8s.io/v1beta1"; - var POLICY_BINDING_API = KUBE_SCHEMA["RoleBinding"]["api"]; - var watchPromise; - - function setupRoleBinding(group) { - KUBE_SCHEMA["RoleBinding"]["api"] = group ? RBAC_API : POLICY_BINDING_API; - KUBE_SCHEMA["rolebindings"]["api"] = group ? RBAC_API : POLICY_BINDING_API; - apiGroup = group; - expireSAR(null); - expireWhoCan(null); - return group ? "rolebindings" : "policybindings"; - } - - function ensureWatchType() { - if (!watchPromise) { - watchPromise = new KubeRequest("GET", "/oapi/v1") - .then(function(response) { - var data = response.data || {}; - var i; - var l = data.resources || []; - for (i = 0; i < l.length; i++) { - if (l[i].kind == "PolicyBinding") - return setupRoleBinding(); - } - return setupRoleBinding(RBAC_GROUP); - }, function(err) { - console.warn("Error getting API", err); - return setupRoleBinding(); - }); - } - return watchPromise; - } - - /* - * Data loading hacks: - * - * We would like to watch rolebindings, but not all versions support - * that. So we have to watch policybindings and then infer the - * rolebindings from there. - * - * In addition we would like to be able to load User and Group objects, - * even if only for a certain project. However, non-cluster admins - * fail to do this, so we simulate these objects from the role bindings. - */ - loader.listen(function(present, removed) { - var link; - var expire = { }; - - /* If reseting clear status */ - if (!present && !removed) { - expireSAR(null); - expireWhoCan(null); - watchPromise = null; - return; - } - - for (link in removed) { - if (removed[link].kind == "PolicyBinding") { - update_rolebindings(removed[link].roleBindings, true); - expire[removed[link].metadata.namespace] = true; - } - } - for (link in present) { - if (present[link].kind == "PolicyBinding") { - update_rolebindings(present[link].roleBindings, false); - expire[present[link].metadata.namespace] = true; - } else if (present[link].kind == "RoleBinding") { - ensure_subjects(present[link].subjects || []); - expire[present[link].metadata.namespace] = true; - } - } - - var namespace; - for (namespace in expire) { - expireWhoCan(namespace); - expireSAR(namespace); - } - }); - - function update_rolebindings(bindings, removed) { - angular.forEach(bindings || [], function(wrapper) { - loader.handle(wrapper.roleBinding, removed, "RoleBinding"); - }); - } - - function ensure_subjects(subjects) { - angular.forEach(subjects, function(subject) { - var link = loader.resolve(subject.kind, subject.name, subject.namespace); - if (link in loader.objects) - return; - - /* Don't show system groups */ - if (subject.kind == "Group" && subject.name.indexOf("system:") === 0) - return; - - /* An interim object, until perhaps the real thing can be loaded */ - var interim = { kind: subject.kind, apiVersion: "v1", metadata: { name: subject.name } }; - if (subject.namespace) - interim.metadata.namespace = subject.namespace; - loader.handle(interim); - }); - } - - /* - * Cached localresourceaccessreviews responses, and expired data - * Each one has a project key, containing an object with verb:resource keys. - */ - var cached = { }; - var expired = { }; - - function fillWhoCan(namespace, verb, resource, result) { - var key = verb + ":" + resource; - - if (!(namespace in cached)) - cached[namespace] = { }; - cached[namespace][key] = result; - - if (result) { - if (namespace in expired) { - delete expired[namespace][key]; - } - } - - $rootScope.$applyAsync(); - } - - function expireWhoCan(namespace) { - if (namespace) { - expired[namespace] = angular.extend({ }, cached[namespace]); - delete cached[namespace]; - } else { - expired = cached; - cached = { }; - } - - $rootScope.$applyAsync(); - } - - function lookupWhoCan(namespace, verb, resource) { - var key = verb + ":" + resource; - - var ask = true; - var result = null; - - var data = cached[namespace]; - if (data) { - if (key in data) { - result = data[key]; - ask = false; - } - } - - if (!result) { - data = expired[namespace]; - if (data) { - if (key in data) - result = data[key]; - } - } - - if (!ask) - return result; - - /* Perform a request */ - var request = { - kind: "LocalResourceAccessReview", - apiVersion: "v1", - namespace: "", - verb: verb, - resource: resource, - resourceName: "", - content: null - }; - - /* Fill in null info while looking up */ - fillWhoCan(namespace, verb, resource, null); - - var path = loader.resolve("localresourceaccessreviews", null, namespace); - methods.post(path, request) - .then(function(response) { - fillWhoCan(namespace, verb, resource, response); - }, function(response) { - console.warn("failed to lookup access:", namespace, verb, resource + ":", - response.message || JSON.stringify(response)); - }); - - return result; - } - - var sarCache = { }; - - function subjectAccessReview(namespace, user, verb, resource) { - var key = namespace + ':' + (user ? user.metadata.name : "") + ':' + verb + ':' + resource; - var defer = $q.defer(); - - if (key in sarCache) { - defer.resolve(sarCache[key]); - } else { - var request = { - kind: "SubjectAccessReview", - apiVersion: "v1", - namespace: namespace, - verb: verb, - resource: resource - }; - - methods.post(loader.resolve("subjectaccessreviews"), request) - .then(function(response) { - sarCache[key] = response.allowed; - defer.resolve(response.allowed); - }, function(response) { - console.warn("failed to review subject access:", response.message || JSON.stringify(response)); - defer.reject(response.message || JSON.stringify(response)); - }); - } - - return defer.promise; - } - - function expireSAR(namespace) { - if (namespace) { - for (var key in sarCache) { - if (key.lastIndexOf(namespace + ':', 0) === 0) - delete sarCache[key]; - } - } else { - sarCache = { }; - } - - $rootScope.$applyAsync(); - } - - /* - * HACK: There's no way to PATCH subjects in or out - * of a role, so we have to use this race prone mechanism. - */ - function modifyRole(namespace, role, callback) { - var path = loader.resolve("RoleBinding", role, namespace); - return loader.load(path) - .then(function(resource) { - callback(resource); - return methods.put(path, resource); - }); - } - - function createRole(namespace, role, subjects) { - var name = toName(role); - var binding = { - kind: "RoleBinding", - metadata: { - name: name, - namespace: namespace, - creationTimestamp: null, - }, - userNames: [], - groupNames: [], - subjects: [], - roleRef: { - name: role, - kind: "ClusterRole", - } - }; - addToArray(roleArray(binding, "subjects"), subjects); - addToArray(roleArrayKind(binding, subjects.kind), subjects.name); - return methods.create(binding, namespace); - } - - function removeFromRole(project, role, subject) { - subject.apiGroup = apiGroup; - var namespace = toName(project); - return modifyRole(namespace, role, function(data) { - removeFromArray(roleArray(data, "subjects"), subject); - removeFromArray(roleArrayKind(data, subject.kind), subject.name); - }).then(function() { - expireWhoCan(namespace); - }, function(resp) { - /* If the role doesn't exist consider removed to work */ - if (resp.code !== 404) - return $q.reject(resp); - }); - } - - function removeMemberFromProject(project, subjectRoleBindings, subject) { - var registryRoles = ["registry-admin", "registry-editor", "registry-viewer"]; - var chain = $q.when(); - subject.apiGroup = apiGroup; - - angular.forEach(subjectRoleBindings, function(role) { - // Since we only added registry roles - // remove ONLY registry roles - if (indexOf(registryRoles, role.roleRef.name) !== -1) { - chain = chain.then(function() { - return removeFromRole(project, role.roleRef.name, subject); - }); - } - }); - return chain; - } - function indexOf(array, value) { - var i, len; - for (i = 0, len = array.length; i < len; i++) { - if (angular.equals(array[i], value)) - return i; - } - return -1; - } - - function addToArray(array, value) { - var index = indexOf(array, value); - if (index < 0) - array.push(value); - } - - function removeFromArray(array, value) { - var index = indexOf(array, value); - if (index >= 0) - array.splice(index, 1); - } - - function roleArray(data, field) { - var array = data[field] || []; - data[field] = array; - return array; - } - - function roleArrayKind(data, kind) { - if (kind == "Group" || kind == "SystemGroup") - return roleArray(data, "groupNames"); - else - return roleArray(data, "userNames"); - } - - function toName(object) { - if (typeof object == "object") - return object.metadata.name; - else - return object; - } - - return { - watch: function watch(until) { - ensureWatchType().then(function (what) { - loader.watch(what, until) - .then(function() { - expireWhoCan(null); - }); - }); - }, - whoCan: function whoCan(project, verb, resource) { - return lookupWhoCan(toName(project), verb, resource); - }, - addToRole: function addToRole(project, role, subject) { - subject.apiGroup = apiGroup; - var namespace = toName(project); - return modifyRole(namespace, role, function(data) { - addToArray(roleArray(data, "subjects"), subject); - addToArray(roleArrayKind(data, subject.kind), subject.name); - }).then(function() { - expireWhoCan(namespace); - }, function(resp) { - /* If the role doesn't exist create it */ - if (resp.code === 404) - return createRole(namespace, role, subject); - return $q.reject(resp); - }); - }, - removeFromRole: removeFromRole, - removeMemberFromProject: removeMemberFromProject, - subjectAccessReview: subjectAccessReview - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/projects.js b/pkg/kubernetes/scripts/projects.js deleted file mode 100644 index f808d70a1..000000000 --- a/pkg/kubernetes/scripts/projects.js +++ /dev/null @@ -1,1411 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-route'); - require('angular-dialog.js'); - - require('./kube-client'); - require('./listing'); - require('./policy'); - - require('../views/projects-page.html'); - require('../views/project-page.html'); - require('../views/user-page.html'); - require('../views/group-page.html'); - require('../views/project-panel.html'); - require('../views/project-body.html'); - require('../views/user-body.html'); - require('../views/group-panel.html'); - require('../views/user-panel.html'); - require('../views/project-listing.html'); - require('../views/project-modify.html'); - require('../views/project-modify.html'); - require('../views/project-delete.html'); - require('../views/add-group-dialog.html'); - require('../views/user-group-add.html'); - require('../views/user-group-remove.html'); - require('../views/group-delete.html'); - require('../views/add-user-dialog.html'); - require('../views/user-modify.html'); - require('../views/user-add-membership.html'); - require('../views/user-remove-membership.html'); - require('../views/user-delete.html'); - require('../views/add-member-role-dialog.html'); - require('../views/remove-role-dialog.html'); - require('../views/add-role-dialog.html'); - - function toName(object) { - if (object && typeof object == "object") - return object.metadata.name; - else - return object; - } - - angular.module('registry.projects', [ - 'ngRoute', - 'ui.cockpit', - 'kubeClient', - 'kubernetes.listing', - 'registry.policy', - ]) - - .config(['$routeProvider', - function($routeProvider) { - $routeProvider - .when('/projects/:namespace?', { - controller: 'ProjectsCtrl', - templateUrl: function(params) { - if (!params['namespace']) - return 'views/projects-page.html'; - else - return 'views/project-page.html'; - } - }) - .when('/users/:user', { - controller: 'UserCtrl', - templateUrl: function(params) { - return 'views/user-page.html'; - } - }) - .when('/groups/:group', { - controller: 'GroupCtrl', - templateUrl: function(params) { - return 'views/group-page.html'; - } - }); - } - ]) - - .controller('ProjectsCtrl', [ - '$scope', - '$routeParams', - '$location', - 'kubeSelect', - 'kubeLoader', - 'projectData', - 'projectActions', - 'ListingState', - 'roleActions', - 'projectPolicy', - function($scope, $routeParams, $location, select, loader, projectData, projectAction, ListingState, roleAction, projectPolicy) { - loader.watch("users", $scope); - loader.watch("groups", $scope); - projectPolicy.watch($scope); - var namespace = $routeParams["namespace"] || ""; - $scope.projName = namespace; - if (namespace) { - $scope.listing = new ListingState($scope); - $scope.project = function() { - return select().kind("Project") - .name(namespace) - .one(); - }; - } else { - $scope.listing = new ListingState($scope); - $scope.projects = function() { - return select().kind("Project"); - }; - } - $scope.$on("activate", function(ev, id) { - ev.preventDefault(); - $location.path(id); - }); - angular.extend($scope, projectData); - angular.extend($scope, roleAction); - angular.extend($scope, projectAction); - $scope.users = function() { - return select().kind("User"); - }; - $scope.groups = function() { - return select().kind("Group"); - }; - } - ]) - - .controller('UserCtrl', [ - '$scope', - '$routeParams', - '$location', - 'kubeSelect', - 'kubeLoader', - 'projectData', - 'projectActions', - 'roleActions', - 'ListingState', - 'projectPolicy', - function($scope, $routeParams, $location, select, loader, projectData, projectAction, roleActions, ListingState, projectPolicy) { - loader.watch("users", $scope); - loader.watch("groups", $scope); - projectPolicy.watch($scope); - var user = $routeParams["user"] || ""; - $scope.userName = user; - if (user) { - $scope.user = function() { - return select().kind("User") - .name(user) - .one(); - }; - $scope.listing = new ListingState($scope); - $scope.$on("activate", function(ev, id) { - ev.preventDefault(); - $location.path(id); - }); - } else { - $scope.listing = new ListingState($scope); - $location.path("/projects"); - } - $scope.projects = function() { - return select().kind("Project"); - }; - $scope.groups = function() { - return select().kind("Group"); - }; - $scope.users = function() { - return select().kind("User"); - }; - angular.extend($scope, projectData); - angular.extend($scope, projectAction); - angular.extend($scope, roleActions); - } - ]) - - .controller('GroupCtrl', [ - '$scope', - '$routeParams', - '$location', - 'kubeSelect', - 'kubeLoader', - 'projectData', - 'projectActions', - 'roleActions', - 'ListingState', - 'projectPolicy', - function($scope, $routeParams, $location, select, loader, projectData, projectAction, roleActions, ListingState, projectPolicy) { - loader.watch("users", $scope); - loader.watch("groups", $scope); - projectPolicy.watch($scope); - var group = $routeParams["group"] || ""; - $scope.groupName = group; - if (group) { - $scope.group = function() { - return select().kind("Group") - .name(group) - .one(); - }; - $scope.listing = new ListingState($scope); - $scope.$on("activate", function(ev, id) { - ev.preventDefault(); - $location.path(id); - }); - } else { - $scope.listing = new ListingState($scope); - $location.path("/projects"); - } - $scope.projects = function() { - return select().kind("Project"); - }; - $scope.groups = function() { - return select().kind("Group"); - }; - $scope.users = function() { - return select().kind("User"); - }; - angular.extend($scope, projectData); - angular.extend($scope, projectAction); - angular.extend($scope, roleActions); - } - ]) - - .factory("projectData", [ - '$q', - 'kubeSelect', - 'kubeLoader', - 'projectPolicy', - function($q, select, loader, policy) { - var registryRoles = [{ ocRole: "registry-admin", displayRole :"Admin" }, - { ocRole:"registry-editor", displayRole :"Push" }, - { ocRole:"registry-viewer", displayRole :"Pull" }]; - - function getRegistryRolesMap() { - return registryRoles; - } - function getDisplayRole(ocRole) { - var i; - var displayRole; - for (i = registryRoles.length - 1; i >= 0; i--) { - if (registryRoles[i].ocRole === ocRole) { - displayRole = registryRoles[i].displayRole; - break; - } - } - return displayRole; - } - function getOcRolesList() { - var ocRoles = []; - angular.forEach(registryRoles, function(r) { - ocRoles.push(r.ocRole); - }); - return ocRoles; - } - function getAllRoles(member, project) { - if (!member && !project) - return []; - var projectName = toName(project); - var roleBinds = subjectRoleBindings(member, projectName); - var meta; - var ret = []; - angular.forEach(roleBinds, function(roleBind) { - meta = roleBind.metadata || { }; - if (meta.name) - ret.push(meta.name); - }); - return ret; - } - function getRegistryRoles(member, project) { - if (!member && !project) - return []; - var projectName = toName(project); - var roleBinds = subjectRoleBindings(member, projectName); - var ocRegistryRoles = getOcRolesList(); - var roles = []; - var meta; - angular.forEach(roleBinds, function(roleBind) { - meta = roleBind.metadata || { }; - if (meta.name && ocRegistryRoles.indexOf(meta.name) !== -1) { - if (roles.indexOf(getDisplayRole(meta.name) === -1)) - roles.push(getDisplayRole(meta.name)); - } - }); - return roles; - } - function isRegistryRole(member, displayRole, project) { - var oc_roles = getRegistryRoles(member, project); - if (oc_roles.indexOf(displayRole) !== -1) { - return true; - } - return false; - } - function hasRegistryRole(member, project) { - var oc_roles = getRegistryRoles(member, project); - if (oc_roles.length === 0) { - return false; - } - return true; - } - function isRoles(member, namespace) { - var oc_roles = getAllRoles(member, namespace); - if (oc_roles.length === 0) { - return false; - } - return true; - } - function getProjectsWithMember(projects, member) { - if (!projects && !member) - return []; - var projList = []; - if (member) { - angular.forEach(projects, function(project) { - if (project && subjectIsMember(member, project.metadata.name)) - projList.push(project); - }); - } - return projList; - } - - function getGroupsWithMember(groups, member) { - if (!groups && !member) - return []; - var grpList = []; - if (member) { - angular.forEach(groups, function(group) { - if (group && group.users && group.users.indexOf(member) != -1) - grpList.push(group); - }); - } - return grpList; - } - function getMembershipOfUser(projects, groups, user) { - var members = []; - var userProjects = getProjectsWithMember(projects, user); - angular.forEach(userProjects, function(project) { - members.push(project.metadata.name); - }); - var userGroups = getGroupsWithMember(groups, user); - angular.forEach(userGroups, function(group) { - members.push(group.metadata.name); - }); - return members; - } - /* - * To use this you would have a user or group, and do: - * - * rolebindings = select().kind("RoleBindings").containsSubject(user_name); - * rolebindings = select().kind("RoleBindings").containsSubject(user_object); - * rolebindings = select().kind("RoleBindings").containsSubject(group_object); - */ - select.register({ - name: "containsSubject", - digests: function(arg) { - var meta, i, len, subjects; - var ret = []; - if (typeof arg == "string") { - ret.push(arg); - } else if (arg.kind == "User" || arg.kind == "Group") { - meta = arg.metadata || { }; - ret.push(meta.name + ":" + arg.kind); - } else if (arg.kind == "RoleBinding") { - subjects = arg.subjects || []; - for (i = 0, len = subjects.length; i < len; i++) { - ret.push(subjects[i].name); - ret.push(subjects[i].name + ":" + subjects[i].kind); - } - } - return ret; - } - }); - - function subjectRoleBindings(subject, namespace) { - return select().kind("RoleBinding") - .namespace(namespace) - .containsSubject(subject); - } - - function subjectIsMember(subject, namespace) { - if (!subject || !namespace) - return null; - namespace = toName(namespace); - return !!subjectRoleBindings(subject, namespace).one(); - } - - function formatMembers(members, kind) { - var mlist = ""; - var i; - if (!members || members.length === 0) - return mlist; - if (members.length <= 3) { - for (i = members.length - 1; i >= 0; i--) { - if (i > 0) - mlist += ","; - mlist += members[i]; - } - } else { - if (kind === "Groups") { - mlist = members.length + " " + kind; - } else if (kind === "Users") { - mlist = members.length + " " + kind; - } - } - return mlist; - } - - var sharedVerb = "get"; - var sharedResource = "imagestreams/layers"; - var sharedRole = "registry-viewer"; - var sharedKind = "Group"; - var anonymousGroup = "system:unauthenticated"; - var sharedGroup = "system:authenticated"; - var registryAdmin = "registry-admin"; - - function shareImages(project, accessPolicy) { - var anonSubject = { - kind: sharedKind, - name: anonymousGroup, - }; - var sharedSubject = { - kind: sharedKind, - name: sharedGroup, - }; - if (accessPolicy === "anonymous") { - return policy.addToRole(project, sharedRole, anonSubject) - .then(function() { - return policy.addToRole(project, sharedRole, sharedSubject); - }); - } else if (accessPolicy === "shared") { - return policy.removeFromRole(project, sharedRole, anonSubject) - .then(function() { - return policy.addToRole(project, sharedRole, sharedSubject); - }); - } else { - return policy.removeFromRole(project, sharedRole, anonSubject) - .then(function() { - return policy.removeFromRole(project, sharedRole, sharedSubject); - }); - } - } - - function sharedImages(project) { - if (!project) - return null; - - var response = policy.whoCan(project, sharedVerb, sharedResource); - if (!response) - return null; - - var projState = {}; - projState[anonymousGroup] = null; - projState[sharedGroup] = null; - - var i, len; - var groups = response.groups || []; - for (i = 0, len = groups.length; i < len; i++) { - if (projState.hasOwnProperty(groups[i])) - projState[groups[i]] = true; - } - - if (projState[anonymousGroup]) - return "anonymous"; - else if (projState[sharedGroup]) - return "shared"; - return "private"; - } - - function makeRegistryAdmin(project, currentUser) { - var subject = { - kind: 'User', - name: toName(currentUser), - }; - // if system:admin then return - if (currentUser && currentUser.groups && - currentUser.groups.indexOf("system:cluster-admins") !== -1) { - return $q.when({ }); - } - var oc_roles = getRegistryRoles(currentUser, project); - if (oc_roles.indexOf(registryAdmin) !== -1) { - // for templates with registryAdmin - // if registryAdmin role exists then return - return $q.when({ }); - } - return policy.addToRole(project, registryAdmin, subject); - } - - function isSameUser(currUser, userName) { - return currUser ? toName(currUser) === toName(userName) : false; - } - - return { - subjectRoleBindings: subjectRoleBindings, - subjectIsMember: subjectIsMember, - formatMembers: formatMembers, - shareImages: shareImages, - sharedImages: sharedImages, - getAllRoles: getAllRoles, - isRegistryRole: isRegistryRole, - isRoles: isRoles, - getRegistryRolesMap: getRegistryRolesMap, - getRegistryRoles: getRegistryRoles, - getGroupsWithMember: getGroupsWithMember, - getProjectsWithMember: getProjectsWithMember, - getMembershipOfUser: getMembershipOfUser, - isSameUser: isSameUser, - makeRegistryAdmin: makeRegistryAdmin, - hasRegistryRole: hasRegistryRole, - }; - } - ]) - - .directive('projectPanel', [ - 'kubeLoader', - 'kubeSelect', - 'projectData', - 'roleActions', - function(loader, select, projectData, roleActions) { - return { - restrict: 'A', - scope: true, - link: function(scope, element, attrs) { - var tab = 'main'; - scope.tab = function(name, ev) { - if (ev) { - tab = name; - ev.stopPropagation(); - } - return tab === name; - }; - var currProject = scope.id; - angular.extend(scope, projectData); - angular.extend(scope, roleActions); - loader.load("Project", null, currProject); - scope.project = function() { - return select().kind("Project") - .name(currProject) - .one(); - }; - }, - templateUrl: "views/project-panel.html" - }; - } - ]) - - .directive('projectBody', [ - 'projectData', - function(data) { - return { - restrict: 'A', - templateUrl: 'views/project-body.html', - link: function(scope, element, attrs) { - scope.sharedImages = data.sharedImages; - }, - }; - } - ]) - - .directive('userBody', [ - function() { - return { - restrict: 'A', - templateUrl: 'views/user-body.html', - link: function(scope, element, attrs) { - }, - }; - } - ]) - - .directive('groupPanel', [ - 'kubeLoader', - 'kubeSelect', - 'projectData', - function(loader, select, projectData) { - return { - restrict: 'A', - scope: true, - link: function(scope, element, attrs) { - var tab = 'main'; - scope.tab = function(name, ev) { - if (ev) { - tab = name; - ev.stopPropagation(); - } - return tab === name; - }; - - var currGroup = scope.id; - loader.load("Groups"); - scope.group = function() { - return select().kind("Group") - .name(currGroup) - .one(); - }; - scope.projects = function() { - return select().kind("Project"); - }; - angular.extend(scope, projectData); - }, - templateUrl: "views/group-panel.html" - }; - } - ]) - - .directive('userPanel', [ - 'kubeLoader', - 'kubeSelect', - 'projectData', - 'projectActions', - function(loader, select, projectData, projectAction) { - return { - restrict: 'A', - scope: true, - link: function(scope, element, attrs) { - var tab = 'main'; - scope.tab = function(name, ev) { - if (ev) { - tab = name; - ev.stopPropagation(); - } - return tab === name; - }; - - var currUser = scope.id; - loader.load("Users"); - angular.extend(scope, projectData); - angular.extend(scope, projectAction); - scope.user = function() { - return select().kind("User") - .name(currUser) - .one(); - }; - scope.groups = function() { - return select().kind("Group"); - }; - scope.projects = function() { - return select().kind("Project"); - }; - }, - templateUrl: "views/user-panel.html" - }; - } - ]) - - .directive('projectListing', - function() { - return { - restrict: 'A', - templateUrl: 'views/project-listing.html' - }; - } - ) - - .factory('projectActions', [ - '$modal', - 'projectData', - function($modal, projectData) { - function createProject(currentUser) { - return $modal.open({ - controller: 'ProjectModifyCtrl', - templateUrl: 'views/project-modify.html', - resolve: { - dialogData: function() { - return { currUser: currentUser }; - } - }, - }).result; - } - - function modifyProject(project) { - return $modal.open({ - animation: false, - controller: 'ProjectModifyCtrl', - templateUrl: 'views/project-modify.html', - resolve: { - dialogData: function() { - return { project: project }; - } - }, - }).result; - } - function removeProject(project) { - return $modal.open({ - animation: false, - controller: 'ProjectModifyCtrl', - templateUrl: 'views/project-delete.html', - resolve: { - dialogData: function() { - return { project: project }; - } - }, - }).result; - } - function createGroup() { - return $modal.open({ - controller: 'GroupNewCtrl', - templateUrl: 'views/add-group-dialog.html', - }); - } - function addUserToGroup(groupObj) { - return $modal.open({ - controller: 'GroupChangeCtrl', - templateUrl: 'views/user-group-add.html', - resolve:{ - fields: function() { - return { group: groupObj }; - } - } - }); - } - function removeUserFromGroup(user, groupObj) { - return $modal.open({ - controller: 'GroupChangeCtrl', - templateUrl: 'views/user-group-remove.html', - resolve:{ - fields: function() { - return { group: groupObj, user: user }; - } - } - }); - } - function removeGroup(projects, groupObj) { - return $modal.open({ - controller: 'GroupChangeCtrl', - templateUrl: 'views/group-delete.html', - resolve:{ - fields: function() { - var members = projectData.getProjectsWithMember(projects, groupObj.metadata.name); - return { group: groupObj, projects: projects, members: members }; - } - } - }); - } - function createUser() { - return $modal.open({ - controller: 'UserNewCtrl', - templateUrl: 'views/add-user-dialog.html', - }); - } - function modifyUser(userObj) { - return $modal.open({ - animation: false, - controller: 'UserChangeCtrl', - templateUrl: 'views/user-modify.html', - resolve: { - fields: function() { - return { user: userObj }; - } - }, - }).result; - } - function addMemberToParent(memberObj) { - return $modal.open({ - controller: 'UserChangeCtrl', - templateUrl: 'views/user-add-membership.html', - resolve:{ - fields: function() { - return { memberObj: memberObj }; - } - } - }); - } - function removeMemberFromParent(memberObj, parentObj) { - return $modal.open({ - controller: 'UserChangeCtrl', - templateUrl: 'views/user-remove-membership.html', - resolve:{ - fields: function() { - return { parentObj: parentObj, memberObj: memberObj }; - } - } - }); - } - function removeUser(projects, groups, userObj) { - return $modal.open({ - controller: 'UserChangeCtrl', - templateUrl: 'views/user-delete.html', - resolve:{ - fields: function() { - var members = projectData.getMembershipOfUser(projects, groups, userObj.metadata.name); - return { user: userObj, projects: projects, groups: groups, - members: members }; - } - } - }); - } - return { - createProject: createProject, - modifyProject: modifyProject, - createGroup: createGroup, - createUser: createUser, - removeProject: removeProject, - removeUser: removeUser, - modifyUser: modifyUser, - addMemberToParent: addMemberToParent, - removeMemberFromParent: removeMemberFromParent, - removeGroup: removeGroup, - addUserToGroup: addUserToGroup, - removeUserFromGroup: removeUserFromGroup, - }; - } - ]) - - .factory('roleActions', [ - '$modal', - function($modal) { - function addMember(project) { - return $modal.open({ - controller: 'MemberNewCtrl', - templateUrl: 'views/add-member-role-dialog.html', - resolve: { - fields: function() { - return { namespace: toName(project) }; - } - }, - }); - } - function changeRole(member, roleMp, roles, project) { - return $modal.open({ - controller: 'ChangeRoleCtrl', - templateUrl: function() { - if (roles.indexOf(roleMp.displayRole) >= 0) { - return 'views/remove-role-dialog.html'; - } else { - return 'views/add-role-dialog.html'; - } - }, - resolve: { - fields: function() { - return { member: member, ocRole: roleMp.ocRole, - displayRole: roleMp.displayRole, roles: roles, - namespace: toName(project) }; - } - }, - }); - } - return { - addMember: addMember, - changeRole: changeRole, - }; - } - ]) - - .controller('ChangeRoleCtrl', [ - '$q', - '$scope', - 'projectPolicy', - 'kubeLoader', - 'kubeSelect', - 'fields', - function($q, $scope, projectPolicy, loader, kselect, fields) { - $scope.fields = fields; - var namespace = $scope.fields.namespace; - - $scope.performCreate = function performCreate() { - var role = $scope.fields.ocRole; - var memberObj = $scope.fields.member; - var subject = { - kind: memberObj.kind, - name: memberObj.metadata.name, - }; - return projectPolicy.addToRole(namespace, role, subject); - }; - - $scope.performRemove = function performRemove() { - var role = $scope.fields.ocRole; - var memberObj = $scope.fields.member; - var subject = { - kind: memberObj.kind, - name: memberObj.metadata.name, - }; - return projectPolicy.removeFromRole(namespace, role, subject); - }; - } - ]) - - .controller('MemberNewCtrl', [ - '$q', - '$scope', - 'projectData', - 'projectPolicy', - 'kubeLoader', - 'kubeSelect', - 'fields', - 'gettextCatalog', - function($q, $scope, projectData, projectPolicy, loader, kselect, fields, gettextCatalog) { - const _ = gettextCatalog.getString.bind(gettextCatalog); - var selectMember = _("Select Member"); - var NAME_RE = /^[a-z0-9_.]([-a-z0-9@._:]*[a-z0-9._:])?$/; - var selectRole = _("Select Role"); - - loader.watch("User", $scope); - loader.watch("Group", $scope); - - $scope.selected = { - member: selectMember, - getMembers: getAllMembers, - displayRole: selectRole, - roles: projectData.getRegistryRolesMap(), - kind: "", - ocRole: "", - }; - $scope.itemTracker = function(item) { - return item.kind + "/" + item.metadata.name; - }; - var namespace = fields.namespace; - - /* - * This function is called during Angular rendering. Make sure we - * use the same array over and over again, so angular doesn't - * try to digest again. - */ - function getAllMembers() { - var users = kselect().kind("User"); - var groups = kselect().kind("Group"); - var members = []; - angular.forEach(users, function(user) { - members.push(user); - }); - angular.forEach(groups, function(group) { - members.push(group); - }); - return members; - } - function validate(memberName, role) { - var defer = $q.defer(); - var ex; - if (memberName !== undefined) { - if (!memberName) - ex = new Error("The member name cannot be empty."); - else if (memberName === selectMember) - ex = new Error("Please select a valid Member."); - else if (!NAME_RE.test(memberName)) - ex = new Error("The member name contains invalid characters. Only letters, numbers, spaces and the following symbols are allowed: , = @ . _"); - - if (ex) { - ex.target = "#add_member_group"; - defer.reject(ex); - } - } - if (!role || role === selectRole) { - ex = new Error("Please select a valid Role."); - ex.target = "#add_role"; - defer.reject(ex); - } - - if (!ex) { - defer.resolve(); - } - - return defer.promise; - } - $scope.performCreate = function performCreate() { - var role = $scope.selected.ocRole; - var memberName = $scope.selected.memberName; - var member = $scope.selected.member; - var memberObj, kind; - if (memberName && memberName === member) { - // dropdown value selected - memberObj = $scope.selected.memberObj; - memberName = memberObj.metadata.name; - kind = memberObj.kind; - } else if (memberName && member === selectMember) { - // input field has value - kind = "User"; - } else if (!memberName && member === selectMember) { - // nothing selected - memberName = selectMember; - kind = null; - } - - return validate(memberName, role).then(function() { - var subject = { - kind: kind, - name: memberName, - }; - return projectPolicy.addToRole(namespace, role, subject); - }); - }; - } - ]) - - .controller('ProjectModifyCtrl', [ - '$q', - '$scope', - 'kubeSelect', - "dialogData", - "projectData", - '$location', - '$timeout', - "kubeMethods", - "gettextCatalog", - function($q, $scope, kselect, dialogData, projectData, $location, $timeout, methods, gettextCatalog) { - var project = dialogData.project || { }; - var meta = project.metadata || { }; - var annotations = meta.annotations || { }; - const _ = gettextCatalog.getString.bind(gettextCatalog); - - var DISPLAY = "openshift.io/display-name"; - var DESCRIPTION = "openshift.io/description"; - - var fields = { - name: meta.name || "", - display: annotations[DISPLAY] || "", - description: annotations[DESCRIPTION] || "", - access: null, - }; - - /* - * This data may not be available yet, so continue to ask until it is. - * The called function takes care of not making duplicate requests. - */ - var timr; - function updateShared() { - timr = null; - if (fields.access === null) - fields.access = projectData.sharedImages(meta.name); - if (fields.access === null) - timr = $timeout(updateShared, 500); - } - updateShared(); - $scope.$on("$destroy", function() { - if (timr !== null) - $timeout.cancel(timr); - }); - - angular.extend($scope, projectData); - $scope.fields = fields; - $scope.labels = { - access: { - "private": _("Private: Allow only specific users or groups to pull images"), - "shared": _("Shared: Allow any authenticated user to pull images"), - "anonymous" : _("Anonymous: Allow all unauthenticated users to pull images"), - } - }; - - $scope.performDelete = function performDelete(project) { - var promise = methods.delete(project) - .then(function() { - $location.path("/projects"); - }, function(ex) { - return $q.reject(ex); - }); - - return promise; - }; - $scope.performCreate = function performCreate() { - var name = fields.name.trim(); - var request = { - kind: "ProjectRequest", - apiVersion:"v1", - metadata:{ name: name, }, - displayName: fields.display.trim(), - description: fields.description.trim() - }; - - return methods.check(request, { "metadata.name": "#project-new-name" }) - .then(function() { - return methods.create(request); - }) - .then(function() { - return projectData.shareImages(name, fields.access); - }) - .then(function() { - return projectData.makeRegistryAdmin(name, dialogData.currUser); - }); - }; - - $scope.performModify = function performModify() { - var anno = { }; - var data = { metadata: { annotations: anno } }; - - var value = fields.display.trim(); - if (value !== annotations[DISPLAY]) - anno[DISPLAY] = value; - value = fields.description.trim(); - if (value !== annotations[DESCRIPTION]) - anno[DESCRIPTION] = value; - - return methods.check(data, { }) - .then(function() { - return $q.all([ - methods.patch(project, data), - projectData.shareImages(project, fields.access) - ]); - }); - }; - - angular.extend($scope, dialogData); - } - ]) - - .controller('UserNewCtrl', [ - '$q', - '$scope', - "kubeMethods", - function($q, $scope, methods) { - var fields = { - name: "", - identities: "" - }; - - $scope.fields = fields; - - $scope.performCreate = function performCreate() { - var identities = []; - if (fields.identities.trim() !== "") - identities = [fields.identities.trim()]; - - var user = { - "kind": "User", - "apiVersion": "v1", - "metadata": { - "name": fields.name.trim() - }, - "identities": identities - }; - - return methods.check(user, { "metadata.name": "#user_name" }) - .then(function() { - return methods.create(user); - }); - }; - } - ]) - - .factory('memberActions', [ - "kubeMethods", - function(methods) { - function removeUserFromGroup(user, group) { - var userName = toName(user); - var users = group.users || []; - var index = users.indexOf(userName); - if (index >= 0) - users.splice(index, 1); - var patchData = { "users": users }; - return methods.patch(group, patchData); - } - function addUserToGroup(user, group) { - var userName = toName(user); - var users = group.users || []; - var index = users.indexOf(userName); - if (index == -1) - users.push(userName); - var patchData = { "users": users }; - return methods.patch(group, patchData); - } - return { - removeUserFromGroup: removeUserFromGroup, - addUserToGroup: addUserToGroup, - }; - } - ]) - - .controller('UserChangeCtrl', [ - '$q', - '$scope', - 'kubeSelect', - 'kubeLoader', - "kubeMethods", - 'projectData', - 'projectPolicy', - '$location', - 'memberActions', - "fields", - "gettextCatalog", - function($q, $scope, kselect, loader, methods, projectData, projectPolicy, $location, memberActions, fields, gettextCatalog) { - const _ = gettextCatalog.getString.bind(gettextCatalog); - loader.watch("Group", $scope); - loader.watch("Project", $scope); - - function getMembers() { - var members = []; - var groups = getGroups(); - var projects = getProjects(); - angular.forEach(groups, function(group) { - members.push(group); - }); - angular.forEach(projects, function(project) { - members.push(project); - }); - return members; - } - function getProjects() { - return kselect().kind("Project"); - } - function getGroups() { - return kselect().kind("Group"); - } - $scope.itemTracker = function(item) { - return item.kind + "/" + item.metadata.name; - }; - $scope.selected = { - member: _("Select Member"), - getMembers: getMembers, - roles: projectData.getRegistryRolesMap, - role: _("Select Role"), - }; - angular.extend($scope, projectData); - $scope.fields = fields; - if (fields.user && fields.user.identities) - $scope.fields.identities = fields.user.identities.toString(); - else - $scope.fields.identities = ''; - - $scope.performModify = function performModify() { - var identities = []; - var user = $scope.fields.user; - var data = { "identities": identities }; - - if (fields.identities.trim() !== "") { - var idList = fields.identities.trim().split(","); - identities.push.apply(identities, idList); - } - - return methods.check(data, { }) - .then(function() { - return $q.all([ - methods.patch(user, data), - ]); - }); - }; - - $scope.performDelete = function performDelete(user) { - var chain = $q.when(); - - chain = removeMemberFromParents(user); - var promise = chain.then(function() { - $location.path("/projects"); - }, function(ex) { - if (ex.code === 404) { - loader.handle(user, true, "User"); - $location.path("/projects"); - } else { - return $q.reject(ex); - } - }); - - return promise; - }; - function removeMemberFromParents(member) { - var chain = $q.when(); - var groups = projectData.getGroupsWithMember(getGroups(), member.metadata.name); - angular.forEach(groups, function(g) { - chain = chain.then(function() { - return memberActions.removeUserFromGroup(member, g); - }); - }); - var projects = projectData.getProjectsWithMember(getProjects(), member.metadata.name); - angular.forEach(projects, function(project) { - var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project.metadata.name); - var subject = { - kind: member.kind, - name: member.metadata.name, - }; - chain = chain.then(function() { - return projectPolicy.removeMemberFromProject( - project.metadata.name, subjectRoleBindings, subject); - }); - }); - chain = chain.then(function() { - return methods.delete(member); - }); - return chain; - } - - $scope.addMemberToParent = function addMemberToParent() { - if ($scope.selected.parentObj.kind === "Project") { - var project = $scope.selected.parentObj.metadata.name; - var memberObj = $scope.fields.memberObj; - var role = $scope.selected.ocRole; - var subject = { - kind: memberObj.kind, - name: memberObj.metadata.name, - }; - return projectPolicy.addToRole(project, role, subject); - } else if ($scope.selected.parentObj.kind === "Group") { - return memberActions.addUserToGroup($scope.fields.memberObj, $scope.selected.parentObj); - } - }; - - $scope.removeMemberFromParent = function removeMemberFromParent() { - if ($scope.fields.parentObj.kind === "Group") { - return memberActions.removeUserFromGroup($scope.fields.memberObj, $scope.fields.parentObj); - } else { - // Project - var member = $scope.fields.memberObj; - var project = $scope.fields.parentObj.metadata.name; - var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project); - var subject = { - kind: member.kind, - name: member.metadata.name, - }; - return projectPolicy.removeMemberFromProject(project, subjectRoleBindings, subject); - } - }; - } - ]) - - .controller('GroupChangeCtrl', [ - '$q', - '$scope', - 'kubeLoader', - 'kubeSelect', - "kubeMethods", - 'projectData', - 'memberActions', - 'projectPolicy', - '$location', - "fields", - 'gettextCatalog', - function($q, $scope, loader, kselect, methods, projectData, memberActions, projectPolicy, $location, fields, gettextCatalog) { - const _ = gettextCatalog.getString.bind(gettextCatalog); - loader.watch("User", $scope); - loader.watch("Project", $scope); - - function getUsers() { - return kselect().kind("User"); - } - function getProjects() { - return kselect().kind("Project"); - } - $scope.select = { - member: _("Select Member"), - getMembers: getUsers, - }; - angular.extend($scope, projectData); - $scope.fields = fields; - $scope.fields.grpProjects = projectData.getProjectsWithMember(getProjects(), fields.group.metadata.name); - function removeMemberFromParents(member) { - var chain = $q.when(); - var projects = projectData.getProjectsWithMember(getProjects(), member.metadata.name); - angular.forEach(projects, function(project) { - var subjectRoleBindings = projectData.subjectRoleBindings(member.metadata.name, project.metadata.name); - var subject = { - kind: member.kind, - name: member.metadata.name, - }; - chain = chain.then(function() { - return projectPolicy.removeMemberFromProject( - project.metadata.name, subjectRoleBindings, subject); - }); - }); - chain = chain.then(function() { - return methods.delete(member); - }); - return chain; - } - $scope.performDelete = function performDelete(group) { - var chain = $q.when(); - - chain = removeMemberFromParents(group); - var promise = chain.then(function() { - $location.path("/projects"); - }, function(ex) { - if (ex.code === 404) { - $location.path("/projects"); - } else { - return $q.reject(ex); - } - }); - - return promise; - }; - $scope.addUserToGroup = function addUserToGroup() { - return memberActions.addUserToGroup($scope.select.member, $scope.fields.group); - }; - $scope.removeUserFromGroup = function removeUserFromGroup() { - return memberActions.removeUserFromGroup($scope.fields.user, $scope.fields.group); - }; - } - ]) - - .controller('GroupNewCtrl', [ - '$q', - '$scope', - "kubeMethods", - function($q, $scope, methods) { - var fields = { - name: "" - }; - - $scope.fields = fields; - $scope.performCreate = function performCreate() { - var group = { - "kind": "Group", - "apiVersion": "v1", - "metadata": { - "name": fields.name.trim() - } - }; - - return methods.check(group, { "metadata.name": "#group_name" }) - .then(function() { - return methods.create(group); - }); - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/registry.js b/pkg/kubernetes/scripts/registry.js deleted file mode 100644 index d256abb65..000000000 --- a/pkg/kubernetes/scripts/registry.js +++ /dev/null @@ -1,198 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-route'); - require('angular-gettext/dist/angular-gettext.js'); - require('angular-bootstrap-npm/dist/angular-bootstrap.js'); - - require('./app'); - require('./date'); - require('./images'); - require('./projects'); - require('./policy'); - require('./kube-client'); - require('./kube-client-cockpit'); - - require('../views/registry-dashboard-page.html'); - - var MAX_RECENT_STREAMS = 15; - var MAX_RECENT_TAGS = 8; - - angular.module('registry', [ - 'ngRoute', - 'ui.bootstrap', - 'ui.bootstrap.popover', - 'gettext', - 'kubernetes.app', - 'kubernetes.date', - 'registry.images', - 'registry.projects', - 'registry.policy', - 'registryUI.date', - 'kubeClient', - 'kubeClient.cockpit' - ]) - - .config([ - '$routeProvider', - 'KubeWatchProvider', - 'KubeRequestProvider', - 'KubeDiscoverSettingsProvider', - 'MomentLibProvider', - '$provide', - function($routeProvider, KubeWatchProvider, KubeRequestProvider, - KubeDiscoverSettingsProvider, MomentLibProvider, $provide) { - $routeProvider - .when('/', { - templateUrl: 'views/registry-dashboard-page.html', - controller: 'DashboardCtrl', - reloadOnSearch: false, - }) - .otherwise({ redirectTo: '/' }); - - /* Tell the kube-client code to use cockpit watches and requests */ - KubeWatchProvider.KubeWatchFactory = "CockpitKubeWatch"; - KubeRequestProvider.KubeRequestFactory = "CockpitKubeRequest"; - KubeDiscoverSettingsProvider.KubeDiscoverSettingsFactory = "cockpitKubeDiscoverSettings"; - MomentLibProvider.MomentLibFactory = "momentLib"; - - $provide.decorator("$exceptionHandler", - ['$delegate', - '$log', - function($delegate, $log) { - return function (exception, cause) { - /* Displays an oops if we're running in cockpit */ - if (window.parent !== window && window.name.indexOf("cockpit1:") === 0) - window.parent.postMessage("\n{ \"command\": \"oops\" }", "*"); - - $delegate(exception, cause); - }; - }]); - } - ]) - - .controller('DashboardCtrl', [ - '$scope', - 'kubeLoader', - 'kubeSelect', - 'KubeDiscoverSettings', - 'imageData', - 'imageActions', - 'projectActions', - 'projectData', - 'projectPolicy', - 'filterService', - function($scope, loader, select, discoverSettings, imageData, imageActions, projectActions, projectData, projectPolicy, filter) { - loader.load("projects"); - /* Watch the for project access changes */ - projectPolicy.watch($scope); - - /* - * For now the dashboard has to watch all images in - * order to display the 'Images pushed recently' data - * - * In the future we want to have a metadata or filtering - * service that we can query for that data. - */ - imageData.watchImages($scope); - - function compareVersion(a, b) { - a = (a.metadata || { }).resourceVersion || 0; - b = (b.metadata || { }).resourceVersion || 0; - return b - a; - } - function compareCreated(a, b) { - a = a.items ? a.items[0] : {}; - b = b.items ? b.items[0] : {}; - a = a.created || ""; - b = b.created || ""; - return (b < a ? -1 : (b > a ? 1 : 0)); - } - - select.register("buildRecentStreams", function() { - var link; - var array = []; - for (link in this) - array.push(this[link]); - array.sort(compareVersion); - array.splice(MAX_RECENT_STREAMS); - - var result = []; - var status, tags, stream, i, len, total; - for (i = 0, len = array.length; i < len; i++) { - stream = array[i]; - - status = stream.status || { }; - tags = (status.tags || []).slice(); - tags.sort(compareCreated); - total = tags.length; - tags.splice(MAX_RECENT_TAGS); - - if (tags.length > 0) - result.push({ stream: stream, tags: tags, truncated: total > tags.length }); - } - - return result; - }); - - function setShowDockerPushCommands(visible) { - if (visible != $scope.showDockerPushCommands) { - $scope.showDockerPushCommands = visible; - $scope.$applyAsync(); - } - } - - function updateShowDockerPushCommands() { - var ns = filter.namespace(); - - if (ns) { - discoverSettings().then(function(settings) { - projectPolicy.subjectAccessReview(ns, settings.currentUser, 'update', 'imagestreamimages') - .then(setShowDockerPushCommands); - }); - } else { - // no current project, always show push commands; too expensive to iterate through all projects - setShowDockerPushCommands(true); - } - } - - // watch for project changes to update showDockerPushCommands, and initialize it - $scope.$on("$routeUpdate", updateShowDockerPushCommands); - updateShowDockerPushCommands(); - - $scope.createProject = projectActions.createProject; - $scope.createImageStream = imageActions.createImageStream; - $scope.sharedImages = projectData.sharedImages; - - $scope.recentlyUpdated = function recentlyUpdated() { - return select().kind("ImageStream") - .buildRecentStreams(); - }; - - $scope.projects = function projects() { - return select().kind("Project") - .statusPhase("Active"); - }; - - $scope.filter = filter; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/tags.js b/pkg/kubernetes/scripts/tags.js deleted file mode 100644 index 5af838b6c..000000000 --- a/pkg/kubernetes/scripts/tags.js +++ /dev/null @@ -1,151 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - - var REGTAG = /[\u200B\s,]+/; - function parseNodes(parent) { - var child, text; - var names = []; - function pushName(name) { - if (name) - names.push(name); - } - for (child = parent.firstChild; child; child = child.nextSibling) { - text = ""; - if (child.nodeType == 3) - text = child.nodeValue.trim(); - else if (child.nodeType == 1 && child.hasAttribute("value")) - text = child.getAttribute("value"); - text.split(REGTAG).forEach(pushName); - } - return names; - } - - function buildNodes(names) { - var elements = [ document.createTextNode("\u200B") ]; - angular.forEach(names, function(name) { - var span = document.createElement("span"); - span.setAttribute("contenteditable", "false"); - span.setAttribute("class", "image-tag"); - span.setAttribute("value", name); - span.appendChild(document.createTextNode(name)); - var close = document.createElement("a"); - close.setAttribute("class", "pficon pficon-close"); - span.appendChild(close); - elements.push(span); - elements.push(document.createTextNode("\u00A0")); - }); - return elements; - } - - function parseSpec(spec) { - var names = []; - angular.forEach(spec.tags || [ ], function(tag) { - names.push(tag.name); - }); - return names; - } - - function buildSpec(names, spec, insecure, pull) { - var already = { }; - if (!spec) - spec = { }; - angular.forEach(spec.tags || [], function(tag) { - already[tag.name] = tag; - }); - var tags = [ ]; - angular.forEach(names, function(name) { - if (name in already) { - already[name].importPolicy = { "insecure": insecure }; - tags.push(already[name]); - } else { - tags.push({ - name: name, - "importPolicy": { "insecure": insecure }, - from: { - kind: "DockerImage", - name: pull + ":" + name, - }, - }); - } - }); - spec.tags = tags; - return spec; - } - - angular.module('registry.tags', [ ]) - - .directive('imageTagEditor', [ - function() { - return { - restrict: 'A', - transclude: true, - scope: { - tags: "=", - }, - link: function(scope, element, attrs) { - element.addClass("image-tag-editor"); - element.attr("tabindex", "0"); - element.attr("contenteditable", "true"); - - var spans = buildNodes(scope.tags); - element.append(spans); - - /* Select the last item when we get focus */ - var range = document.createRange(); - range.selectNodeContents(spans[spans.length - 1]); - range.collapse(false); - var sel = window.getSelection(); - sel.removeAllRanges(); - sel.addRange(range); - - element.on("click", function(ev) { - var target = ev.target; - var span = target.parentNode; - if (target.nodeName.toLowerCase() == "a" && span.nodeName.toLowerCase() == "span") - span.parentNode.removeChild(span); - }); - - /* When things change retag */ - element.on("blur keyup paste copy cut mouseup", function() { - var tags = parseNodes(element[0]); - while (scope.tags.length > 0) - scope.tags.pop(); - tags.forEach(function(tag) { - scope.tags.push(tag); - }); - }); - } - }; - } - ]) - - .factory('imageTagData', [ - function() { - return { - parseSpec: parseSpec, - buildSpec: buildSpec, - buildNodes: buildNodes, - parseNodes: parseNodes, - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/test-connection.js b/pkg/kubernetes/scripts/test-connection.js deleted file mode 100644 index 84fa8a933..000000000 --- a/pkg/kubernetes/scripts/test-connection.js +++ /dev/null @@ -1,379 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; - -var angular = require("angular"); -require("./connection"); - -(function() { - var fixtures = []; - - var configJson; - - /* Filled in with a function */ - var inject; - - var module = angular.module("kubernetes.connection.tests", [ - "kubeClient", - 'kubeClient.cockpit', - "kubernetes.connection", - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - function(loader, data) { - loader.reset(true); - if (fixtures) - loader.handle(fixtures); - } - ]); - } - - QUnit.test("sessionCertificates test", function(assert) { - var done = assert.async(); - assert.expect(5); - - injectLoadFixtures(fixtures); - inject([ - "sessionCertificates", - function(sessionCertificates) { - sessionCertificates.trustCert(null, "data"); - assert.equal(sessionCertificates.getCert("localhost"), "data", "data retrive"); - assert.equal(sessionCertificates.getCert(null), "data", "null is localhost"); - sessionCertificates.trustCert({}, "data1"); - assert.equal(sessionCertificates.getCert("localhost"), "data1", "blank server retrive"); - assert.equal(sessionCertificates.getCert("address"), undefined, "missing is undefined"); - sessionCertificates.trustCert({ server: "address" }, "address-data"); - assert.equal(sessionCertificates.getCert("address"), undefined, "address data"); - done(); - } - ]); - }); - - QUnit.test("cockpitKubectlConfig parseKubeConfig", function (assert) { - var done = assert.async(); - assert.expect(5); - - injectLoadFixtures(fixtures); - inject(["cockpitKubectlConfig", function (ckg) { - var alpha = { - "address": "alfa.org", - "headers": { - "Authorization": "Bearer provider-token" - }, - "port": 443, - "tls": { - "validate": false, - "authority": undefined, - "certificate": undefined, - "key": undefined, - } - }; - - var bravo = { - "address": "bravo.org", - "headers": { - "Authorization": "Bearer provider-access-token" - }, - "port": 8080, - "tls": { - "authority": { - "file": "cert-authority-file" - }, - "certificate": undefined, - "key": undefined, - "validate": true - } - }; - - var charlie = { - "address": "charlie.org", - "headers": { - "Authorization": "Bearer token" - }, - "port": 8080 - }; - - var delta1 = { - "address": "delta.org", - "headers": {}, - "port": 443, - "tls": { - "authority": undefined, - "certificate": { - "file": "cert-file" - }, - "key": { - "file": "key-file" - }, - "validate": true - } - }; - - var delta2 = { - "address": "delta.org", - "headers": { - "Authorization": "Basic dXNlcjpwYXNzd29yZA==" - }, - "port": 443, - "tls": { - "validate": true, - "authority": undefined, - "certificate": undefined, - "key": undefined, - } - }; - var configData = JSON.stringify(configJson); - assert.deepEqual(ckg.parseKubeConfig(configData), alpha); - assert.deepEqual(ckg.parseKubeConfig(configData, "bravo-with-access-token-auth-provider"), bravo); - assert.deepEqual(ckg.parseKubeConfig(configData, "charlie-with-token"), charlie); - assert.deepEqual(ckg.parseKubeConfig(configData, "delta-with-cert"), delta1); - assert.deepEqual(ckg.parseKubeConfig(configData, "delta-with-basic"), delta2); - done(); - }]); - }); - - QUnit.test("connectionActions prepareData", function (assert) { - var done = assert.async(); - assert.expect(6); - - injectLoadFixtures(fixtures); - inject(["connectionActions", function(connectionActions) { - var cluster, context, user, data, config; - data = connectionActions.prepareData(); - assert.deepEqual(data, { - "cluster": { - "cluster": { - "server": "http://localhost:8080" - }, - "name": "localhost:8080" - }, - "context": { - "context": { - "cluster": "localhost:8080", - "user": undefined - }, - "name": "localhost:8080/noauth" - }, - "user": undefined - }, "got right empty values"); - - cluster = { - "cluster": { "server": "https://127.0.0.1:8000" }, - "name": "name" - }; - user = { - "user": { "token": "token" }, - "name": "user" - }; - - context = { - "context": { - "user": "user", - "cluster": "name" - }, - name : "existing" - }; - - config = { - users: [user], - clusters: [cluster], - contexts: [ context ] - }; - - data = connectionActions.prepareData(config, cluster, user); - assert.deepEqual(data, { - "cluster": { - "cluster": { "server": "https://127.0.0.1:8000" }, - "name": "name" - }, - "context": { "name" : "existing" }, - "user": { - "user": { "token": "token" }, - "name": "user" - } - }, "matched existing"); - - // remove names - delete cluster.name; - delete user.name; - data = connectionActions.prepareData({}, cluster, user); - assert.deepEqual(data, { - "cluster": { - "cluster": { "server": "https://127.0.0.1:8000" }, - "name": "127-0-0-1:8000" - }, - "context": { - "name": "127-0-0-1:8000/user/127-0-0-1:8000", - "context": { - "user": "user/127-0-0-1:8000", - "cluster": "127-0-0-1:8000" - } - }, - "user": { - "user": { "token": "token" }, - "name": "user/127-0-0-1:8000" - }, - }, "generated names"); - - // No dups - config = { - contexts: [{ "name": "127-0-0-1:8000/user/127-0-0-1:8000" }], - }; - data = connectionActions.prepareData(config, cluster, user); - var pos = data.context.name.indexOf("127-0-0-1:8000/user/127-0-0-1:8000"); - assert.ok(data.context.name != "127-0-0-1:8000/user/127-0-0-1:8000" && pos === 0, "dedup context name"); - - config = { - clusters: [{ "name": "127-0-0-1:8000" }], - }; - delete cluster.name; - data = connectionActions.prepareData(config, cluster, user); - pos = data.cluster.name.indexOf("127-0-0-1:8000"); - assert.ok(data.cluster.name != "127-0-0-1:8000" && pos === 0, "dedup cluster name"); - - config = { - users: [{ "name": "user/127-0-0-1:8000" }], - }; - delete user.name; - data = connectionActions.prepareData(config, cluster, user); - pos = data.user.name.indexOf("user/127-0-0-1:8000"); - assert.ok(data.user.name != "user/127-0-0-1:8000" && pos === 0, "dedup user name"); - - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - configJson = { - "clusters": [{ - "name": "alfa", - "cluster": { - "insecure-skip-tls-verify": true, - "server": "https://alfa.org" - } - }, { - "name": "bravo", - "cluster": { - "server": "https://bravo.org:8080", - "certificate-authority": "cert-authority-file" - } - }, { - "name": "charlie", - "cluster": { - "server": "http://charlie.org" - } - }, { - "name": "delta", - "cluster": { - "server": "https://delta.org:443" - } - }], - "contexts": [{ - "name": "alfa-with-token-auth-provider", - "context": { - "cluster": "alfa", - "user": "token-auth-provider" - } - }, { - "name": "bravo-with-access-token-auth-provider", - "context": { - "cluster": "bravo", - "user": "access-token-auth-provider" - } - }, { - "name": "charlie-with-token", - "context": { - "cluster": "charlie", - "user": "token" - } - }, { - "name": "delta-with-cert", - "context": { - "cluster": "delta", - "user": "cert" - } - }, { - "name": "delta-with-basic", - "context": { - "cluster": "delta", - "user": "basic" - } - }], - "current-context": "alfa-with-token-auth-provider", - "users": [{ - "name": "token-auth-provider", - "user": { - "auth-provider": { - "config": { - "token": "provider-token" - }, - "name": "gcp" - } - } - }, { - "name": "access-token-auth-provider", - "user": { - "auth-provider": { - "config": { - "access-token": "provider-access-token" - }, - "name": "gcp" - } - } - }, { - "name": "token", - "user": { - "token": "token" - } - }, { - "name": "cert", - "user": { - "client-certificate": "cert-file", - "client-key": "key-file" - } - }, { - "name": "basic", - "user": { - "username": "user", - "password": "password" - } - }] - }; - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['kubernetes.connection.tests']); -}()); diff --git a/pkg/kubernetes/scripts/test-images.js b/pkg/kubernetes/scripts/test-images.js deleted file mode 100644 index 955bf2529..000000000 --- a/pkg/kubernetes/scripts/test-images.js +++ /dev/null @@ -1,405 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; - -var angular = require("angular"); - -require('angular-gettext/dist/angular-gettext.js'); -require("./images"); - -function suite(fixtures) { - /* Filled in with a function */ - var inject; - - var module = angular.module("registry.images.tests", [ - "kubeClient", - "registry.images", - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - function(loader) { - loader.reset(true); - if (fixtures) - loader.handle(fixtures); - } - ]); - } - - QUnit.test("filter containsTagImage", function (assert) { - var done = assert.async(); - assert.expect(7); - - injectLoadFixtures(fixtures); - - inject([ "kubeSelect", "imageData", function(select, data) { - var streams = select().containsTagImage("sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719"); - assert.equal(streams.length, 2, "number ofstreams"); - assert.ok("/oapi/v1/namespaces/marmalade/imagestreams/busybee" in streams, "matched busybee"); - assert.ok("/oapi/v1/namespaces/marmalade/imagestreams/juggs" in streams, "matched juggs"); - - streams = select().containsTagImage("sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450"); - assert.equal(streams.length, 1, "one stream matched"); - assert.ok("/oapi/v1/namespaces/marmalade/imagestreams/juggs" in streams, "other stream matched juggs"); - assert.ok(!("/oapi/v1/namespaces/marmalade/imagestreams/busybee" in streams), "other stream not busybee"); - - /* An unknown image */ - streams = select().containsTagImage("sha256:2077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1"); - assert.equal(streams.length, 0, "no streams selected"); - - done(); - }]); - }); - - QUnit.test("filter taggedBy", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["kubeSelect", "imageData", function(select, data) { - var tag = { "tag": "2.5", "items": [ - { "image": "sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb" }, - { "image": "sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" } - ] }; - - var images = select().kind("Image") - .taggedBy(tag); - assert.equal(images.length, 2, "number of images"); - assert.ok("/oapi/v1/images/sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb" in images, "matched busybee"); - assert.ok("/oapi/v1/images/sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" in images, "matched juggs"); - - tag = { "tag": "2.5", "items": [ - { "image": "sha256:00329beccad118aa937e839d536d753ee612b67f8feb6adb519e7f5aa6e75fbe" }, - { "image": "sha256:0085eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" } - ] }; - - images = select().kind("Image") - .taggedBy(tag); - assert.equal(images.length, 0, "no images matched"); - - done(); - }]); - }); - - QUnit.test("filter taggedFirst", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["kubeSelect", "imageData", function(select, data) { - var tag = { "tag": "2.5", "items": [ - { "image": "sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb" }, - { "image": "sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" } - ] }; - - var images = select().kind("Image") - .taggedFirst(tag); - assert.equal(images.length, 1, "number of images"); - assert.ok("/oapi/v1/images/sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb" in images, "matched busybee"); - assert.ok(!("/oapi/v1/images/sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" in images), "didn't match juggs"); - - tag = { "tag": "2.5", "items": [ - { "image": "sha256:00329beccad118aa937e839d536d753ee612b67f8feb6adb519e7f5aa6e75fbe" }, - { "image": "sha256:0085eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" } - ] }; - - images = select().kind("Image") - .taggedFirst(tag); - assert.equal(images.length, 0, "no images matched"); - - done(); - }]); - }); - - QUnit.test("filter listTagNames", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["kubeSelect", "imageData", function(select, data) { - var names = select().listTagNames("sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719"); - assert.deepEqual(names, ["marmalade/busybee:latest", "marmalade/juggs:extratag"], "got right names"); - - names = select().listTagNames("sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450"); - assert.deepEqual(names, ["marmalade/juggs:latest"], "got another image tag name"); - - names = select().listTagNames("sha256:2077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1"); - assert.deepEqual(names, [], "no names returned"); - - done(); - }]); - }); - - QUnit.test("split dockerImageManifest", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["kubeSelect", "imageData", function(select, data) { - var items = select().kind("DockerImageManifest") - .name("sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7"); - assert.equal(items.length, 1, "only manifest returned"); - - var item = items["/internal/manifests/sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7"]; - assert.ok(!!item, "got right manifest"); - - assert.equal(item.manifest.history[0].v1Compatibility.config.Hostname, "13709f13afe1", "parsed manifest and compat"); - - done(); - }]); - }); - - QUnit.test("filter dockerConfigLabels", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["kubeSelect", "imageData", function(select, data) { - var results = select().kind("Image") - .dockerImageConfig() - .dockerConfigLabels(); - assert.equal(results.length, 1, "got one set of labels"); - - var again = select().kind("Image") - .dockerImageConfig() - .dockerConfigLabels(); - assert.strictEqual(results, again, "cached results"); - - var labels = results["/oapi/v1/images/sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7"]; - assert.deepEqual(labels, { "Test": "Value", "version": "1.0" }, "got right labels"); - - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['registry.images.tests']); -} - -/* Invoke the test suite with this data */ -suite([ - { "kind": "ImageStream", "apiVersion": "v1", - "metadata": { "name": "busybee", "namespace": "marmalade", - "selfLink": "/oapi/v1/namespaces/marmalade/imagestreams/busybee", - "uid": "4612c052-b44e-11e5-a4da-5254009e00f1" - }, - "spec": {}, - "status": { - "dockerImageRepository": "172.30.87.3:5000/marmalade/busybee", - "tags": [ - { "tag": "0.x", "items": [ - { "created": "2016-01-06T08:19:58Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/busybee@sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb", - "image": "sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb" - } ] - }, - { "tag": "latest", "items": [ - { "created": "2016-01-06T08:19:58Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/busybee@sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719", - "image": "sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719" - } ] - } - ] - } - }, - { "kind": "ImageStream", "apiVersion": "v1", - "metadata": { "name": "juggs", "namespace": "marmalade", - "selfLink": "/oapi/v1/namespaces/marmalade/imagestreams/juggs", - "uid": "84e3a672-b44e-11e5-a4da-5254009e00f1" - }, - "spec": {}, - "status": { - "dockerImageRepository": "172.30.87.3:5000/marmalade/juggs", - "tags": [ - { "tag": "2.11", "items": [ - { "created": "2016-01-06T08:21:43Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/juggs@sha256:b074b7b7905895741f7425ab4e78b9df384aaa518258d2e81d9e904ecf6c9f0f", - "image": "sha256:b074b7b7905895741f7425ab4e78b9df384aaa518258d2e81d9e904ecf6c9f0f" - } ] - }, - { "tag": "2.5", "items": [ - { "created": "2016-01-06T08:21:46Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/juggs@sha256:d0329beccad118aa937e839d536d753ee612b67f8feb6adb519e7f5aa6e75fbe", - "image": "sha256:d0329beccad118aa937e839d536d753ee612b67f8feb6adb519e7f5aa6e75fbe" - } ] - }, - { "tag": "latest", "items": [ - { "created": "2016-01-06T08:21:43Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/juggs@sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450", - "image": "sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450" - } ] - }, - { "tag": "extratag", "items": [ - { "created": "2016-01-06T08:19:58Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/busybee@sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719", - "image": "sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719" - } ] - } - ] - } - }, - { "kind": "ImageStream", "apiVersion": "v1", - "metadata": { "name": "origin", "namespace": "marmalade", - "selfLink": "/oapi/v1/namespaces/marmalade/imagestreams/origin", - "uid": "94813e0a-b44e-11e5-a4da-5254009e00f1" - }, - "spec": {}, - "status": { - "dockerImageRepository": "172.30.87.3:5000/marmalade/origin", - "tags": [ - { "tag": "latest", "items": [ - { "created": "2016-01-06T08:22:10Z", - "dockerImageReference": "172.30.87.3:5000/marmalade/origin@sha256:6077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1", - "image": "sha256:6077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1" - } ] - } - ] - } - }, - - { "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450", - "selfLink": "/oapi/v1/images/sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450", - }, - "dockerImageReference": "172.30.87.3:5000/marmalade/juggs@sha256:0885eeaec4514820b2c879100425e9ea10beaf4412db7f67acfe53b4df2b9450", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:6077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1", - "selfLink": "/oapi/v1/images/sha256:6077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1", - }, - "dockerImageReference": "172.30.87.3:5000/marmalade/origin@sha256:6077956b196342f92271663ec85124aef44ee486f141b7d48e6ce5be410d78f1", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { "kind": "Image", "apiVersion": "v1", - "metadata": { - "name": "sha256:98842019ab49391fe6b419eb131211ceb1aa17a89f655b05e7305366fecea5f2", - "selfLink": "/oapi/v1/images/sha256:98842019ab49391fe6b419eb131211ceb1aa17a89f655b05e7305366fecea5f2", - }, - "dockerImageReference": "172.30.87.3:5000/zerog/test@sha256:98842019ab49391fe6b419eb131211ceb1aa17a89f655b05e7305366fecea5f2", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:a7ca0c3e270a994cfdef0a1d77d8bd41d401135f2f9e02e0a3661cd026e81a77", - "selfLink": "/oapi/v1/images/sha256:a7ca0c3e270a994cfdef0a1d77d8bd41d401135f2f9e02e0a3661cd026e81a77", - }, - "dockerImageReference": "172.30.87.3:5000/zerog/test@sha256:a7ca0c3e270a994cfdef0a1d77d8bd41d401135f2f9e02e0a3661cd026e81a77", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:b074b7b7905895741f7425ab4e78b9df384aaa518258d2e81d9e904ecf6c9f0f", - "selfLink": "/oapi/v1/images/sha256:b074b7b7905895741f7425ab4e78b9df384aaa518258d2e81d9e904ecf6c9f0f", - }, - "dockerImageReference": "172.30.87.3:5000/marmalade/juggs@sha256:b074b7b7905895741f7425ab4e78b9df384aaa518258d2e81d9e904ecf6c9f0f", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb", - "selfLink": "/oapi/v1/images/sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb", - }, - "dockerImageReference": "172.30.87.3:5000/marmalade/busybee@sha256:beadfbc3da8d183c245ab5bad4dd185dacde72dbe81b270926e60e705e534afb", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719", - "selfLink": "/oapi/v1/images/sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719", - }, - "dockerImageReference": "172.30.87.3:5000/marmalade/busybee@sha256:c1ee91e9f0f96ea280d17befdd968ce4e37653939fc9e5e36429cd9674a28719", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", "Id": "", - "Created": null, "ContainerConfig": {} }, - "dockerImageMetadataVersion": "1.0", - }, - { - "kind": "Image", "apiVersion": "v1", "metadata": { - "name": "sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7", - "selfLink": "/oapi/v1/images/sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7", - "annotations": { "openshift.io/image.managed": "true" } - }, - "dockerImageReference": "172.30.198.253:5000/marmalade/juggs@sha256:63da16dc866fa7bfca4dd9d45b70feda28aa383c9ca1f1766c127ccc715a8cb7", - "dockerImageMetadata": { "kind": "DockerImage", "apiVersion": "1.0", - "Id": "fc5cd5d8ca78a17843aba9b1b66e9d0e17200d86b0aad9a4f70d893a10c26b6d", - "Parent": "9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807", - "Created": "2016-03-04T16:50:11Z", - "Container": "7a453b461abfb9410f73e4449ed50d5840a44afb25b0144715b4266ee6d48f2d", - "ContainerConfig": { "Hostname": "13709f13afe1", - "User": "nobody:wheel", "ExposedPorts": { "8888/tcp": {} }, - "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], - "Cmd": [ "/bin/sh", "-c", "#(nop) LABEL version=1.0" ], - "Image": "9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807", - "Entrypoint": [ "top", "-b" ], - "OnBuild": [ "ADD . /app/src" ], - "Labels": { "Test": "Value", "version": "1.0" } - }, - "DockerVersion": "1.9.1", - "Config": { "Hostname": "13709f13afe1", "User": "nobody:wheel", - "ExposedPorts": { "8888/tcp": {} }, - "Env": [ "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" ], - "Cmd": [ "-c" ], - "Image": "9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807", - "Entrypoint": [ "top", "-b" ], - "OnBuild": [ "ADD . /app/src" ], - "Labels": { "Test": "Value", "version": "1.0" } - }, - "Architecture": "amd64", - "Size": 126388696 - }, - "dockerImageMetadataVersion": "1.0", - "dockerImageManifest": "{\n \"schemaVersion\": 1,\n \"name\": \"marmalade/juggs\",\n \"tag\": \"2.8\",\n \"architecture\": \"amd64\",\n \"fsLayers\": [\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:74fc2669b7664c1705ea18d946fb92111a2904fdc69c24dc25db546923663c4b\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:8cbbdaf3178f15e3e23f5eb59c754d16511edf100ba0e57557e47c8a5924d422\"\n },\n {\n \"blobSum\": \"sha256:bc66c3b5709234727e260b55c5553c2bf9608084419271b08bca484914624d84\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:a3ed95caeb02ffe68cdd9fd84406680ae93d633cb16422d00e8a7c22955b46d4\"\n },\n {\n \"blobSum\": \"sha256:f810322bba2c5f0a6dd58ba31eba0543baabb4533e479ab2db376aaa8064be55\"\n }\n ],\n \"history\": [\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"fc5cd5d8ca78a17843aba9b1b66e9d0e17200d86b0aad9a4f70d893a10c26b6d\\\",\\\"parent\\\":\\\"9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807\\\",\\\"created\\\":\\\"2016-03-04T16:50:11.993242911Z\\\",\\\"container\\\":\\\"7a453b461abfb9410f73e4449ed50d5840a44afb25b0144715b4266ee6d48f2d\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) LABEL version=1.0\\\"],\\\"Image\\\":\\\"9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{\\\"Test\\\":\\\"Value\\\",\\\"version\\\":\\\"1.0\\\"},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{\\\"Test\\\":\\\"Value\\\",\\\"version\\\":\\\"1.0\\\"},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"9192c6aa777087e5c06e1d5f1771295f7cd79d9473d71dba2241e68aa2d36807\\\",\\\"parent\\\":\\\"425d372ab4256cc54cbbd1bd6ea9e00ce11fb8685175b72e5193f5a067bb6a31\\\",\\\"created\\\":\\\"2016-03-04T16:50:06.235447946Z\\\",\\\"container\\\":\\\"a13a641996f5d0425de27a7fd80d30174e165acd7bf913432f899ab2f57e0154\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) LABEL Test=Value\\\"],\\\"Image\\\":\\\"425d372ab4256cc54cbbd1bd6ea9e00ce11fb8685175b72e5193f5a067bb6a31\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{\\\"Test\\\":\\\"Value\\\"},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"425d372ab4256cc54cbbd1bd6ea9e00ce11fb8685175b72e5193f5a067bb6a31\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{\\\"Test\\\":\\\"Value\\\"},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"425d372ab4256cc54cbbd1bd6ea9e00ce11fb8685175b72e5193f5a067bb6a31\\\",\\\"parent\\\":\\\"9a7e5193513a4e07bcdcffacb9f1996ef7162a4d2c196d2eaa5b2b959d641dac\\\",\\\"created\\\":\\\"2016-03-04T16:50:00.89289203Z\\\",\\\"container\\\":\\\"2a9474018a32f776c8470897e6600b6a62503a734ae2775a5fbedd9ba9b28307\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ARG simple\\\"],\\\"Image\\\":\\\"9a7e5193513a4e07bcdcffacb9f1996ef7162a4d2c196d2eaa5b2b959d641dac\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"9a7e5193513a4e07bcdcffacb9f1996ef7162a4d2c196d2eaa5b2b959d641dac\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"9a7e5193513a4e07bcdcffacb9f1996ef7162a4d2c196d2eaa5b2b959d641dac\\\",\\\"parent\\\":\\\"dce61bf7ed98793fcfc6c09b6e096a0b74c58648397454660d4a896289f8adc9\\\",\\\"created\\\":\\\"2016-03-04T16:49:55.64958347Z\\\",\\\"container\\\":\\\"6fc564cbd8a2f53f81e1be0cf8b2752448c9b51d69787706bd1a40efc4b53870\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ARG hello=test\\\"],\\\"Image\\\":\\\"dce61bf7ed98793fcfc6c09b6e096a0b74c58648397454660d4a896289f8adc9\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"dce61bf7ed98793fcfc6c09b6e096a0b74c58648397454660d4a896289f8adc9\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"dce61bf7ed98793fcfc6c09b6e096a0b74c58648397454660d4a896289f8adc9\\\",\\\"parent\\\":\\\"a6853913f7a2789d8e91b4be6db0f3ca1fa635942981e6289d4cb067289be53f\\\",\\\"created\\\":\\\"2016-03-04T16:49:50.274796262Z\\\",\\\"container\\\":\\\"90360222ef8c7a4978c0a27542d78175b16cf1b559ea3a0c344c21d6596f8878\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ONBUILD ADD . /app/src\\\"],\\\"Image\\\":\\\"a6853913f7a2789d8e91b4be6db0f3ca1fa635942981e6289d4cb067289be53f\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"a6853913f7a2789d8e91b4be6db0f3ca1fa635942981e6289d4cb067289be53f\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[\\\"ADD . /app/src\\\"],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"a6853913f7a2789d8e91b4be6db0f3ca1fa635942981e6289d4cb067289be53f\\\",\\\"parent\\\":\\\"e4c263ade6bb3cc552dbcd46c38ecdacb871e3e18b4db92451cf89823fb1140d\\\",\\\"created\\\":\\\"2016-03-04T16:49:43.316816134Z\\\",\\\"container\\\":\\\"ada3ba6c28f4d40ad447384f990d4a2075abf86b821cbd5b1f3b339aae2bda7b\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) STOPSIGNAL [SIGKILL]\\\"],\\\"Image\\\":\\\"e4c263ade6bb3cc552dbcd46c38ecdacb871e3e18b4db92451cf89823fb1140d\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"e4c263ade6bb3cc552dbcd46c38ecdacb871e3e18b4db92451cf89823fb1140d\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{},\\\"StopSignal\\\":\\\"SIGKILL\\\"},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"e4c263ade6bb3cc552dbcd46c38ecdacb871e3e18b4db92451cf89823fb1140d\\\",\\\"parent\\\":\\\"b3dd495a125e98acf8497462f7e59ddc59230f6e49a1e0c0a56a28007475af2e\\\",\\\"created\\\":\\\"2016-03-04T16:49:36.966840962Z\\\",\\\"container\\\":\\\"75a79bb684c3ff1a8b9bccd1f046e87f84b9da4722b8b45853602f0a69f4cb27\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) CMD [\\\\\\\"-c\\\\\\\"]\\\"],\\\"Image\\\":\\\"b3dd495a125e98acf8497462f7e59ddc59230f6e49a1e0c0a56a28007475af2e\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"-c\\\"],\\\"Image\\\":\\\"b3dd495a125e98acf8497462f7e59ddc59230f6e49a1e0c0a56a28007475af2e\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"b3dd495a125e98acf8497462f7e59ddc59230f6e49a1e0c0a56a28007475af2e\\\",\\\"parent\\\":\\\"2fef6101c97c5ca0a234e41eea1cdd577d6d9b1a21897147f8b662889f1e1890\\\",\\\"created\\\":\\\"2016-03-04T16:49:32.056781057Z\\\",\\\"container\\\":\\\"076b707ed7bf04602d56b714deb3270998c5b145520b925fc9d8029b28e1484e\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ENTRYPOINT \\\\u0026{[\\\\\\\"top\\\\\\\" \\\\\\\"-b\\\\\\\"]}\\\"],\\\"Image\\\":\\\"2fef6101c97c5ca0a234e41eea1cdd577d6d9b1a21897147f8b662889f1e1890\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":null,\\\"Image\\\":\\\"2fef6101c97c5ca0a234e41eea1cdd577d6d9b1a21897147f8b662889f1e1890\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":[\\\"top\\\",\\\"-b\\\"],\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"2fef6101c97c5ca0a234e41eea1cdd577d6d9b1a21897147f8b662889f1e1890\\\",\\\"parent\\\":\\\"6559b720edfb44ed193826e8a98181ecd0f8412d36ae141891a6be8ac33f13fe\\\",\\\"created\\\":\\\"2016-03-04T16:49:27.230310779Z\\\",\\\"container\\\":\\\"b1fff8a998363845efbbc77e64e58a2ef8cd422896a40816fe5016a0d66c8804\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) USER [nobody:wheel]\\\"],\\\"Image\\\":\\\"6559b720edfb44ed193826e8a98181ecd0f8412d36ae141891a6be8ac33f13fe\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"nobody:wheel\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"\\\\\\\"/echo-script\\\\\\\"\\\"],\\\"Image\\\":\\\"6559b720edfb44ed193826e8a98181ecd0f8412d36ae141891a6be8ac33f13fe\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"6559b720edfb44ed193826e8a98181ecd0f8412d36ae141891a6be8ac33f13fe\\\",\\\"parent\\\":\\\"21356dd5eb576b1af9a101f0acb3729b3fe5c6a4a935a0efbe52d328603c6538\\\",\\\"created\\\":\\\"2016-03-04T16:49:19.278707045Z\\\",\\\"container\\\":\\\"a9ec15a2ac6c962d3f7141f789e0a703f68b1b35386b226485a470fdc297c921\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ADD file:32d397773a81df8feb5d5baf04619f65e2a1e4fddf24bbceb85157ff7f0db752 in /usr/bin\\\"],\\\"Image\\\":\\\"21356dd5eb576b1af9a101f0acb3729b3fe5c6a4a935a0efbe52d328603c6538\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"\\\\\\\"/echo-script\\\\\\\"\\\"],\\\"Image\\\":\\\"21356dd5eb576b1af9a101f0acb3729b3fe5c6a4a935a0efbe52d328603c6538\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"Size\\\":125275044}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"21356dd5eb576b1af9a101f0acb3729b3fe5c6a4a935a0efbe52d328603c6538\\\",\\\"parent\\\":\\\"7fd39f4f39c71d76250adac15d7385fd6d68274e8a7ddd032b0b0bb6b3280a39\\\",\\\"created\\\":\\\"2016-03-04T16:48:53.085321054Z\\\",\\\"container\\\":\\\"7749a20ab52bd8714b5cc2823d3c09767f574b8f2d4bd4393b37f0a4964f3376\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) CMD [\\\\\\\"/bin/sh\\\\\\\" \\\\\\\"-c\\\\\\\" \\\\\\\"\\\\\\\\\\\\\\\"/echo-script\\\\\\\\\\\\\\\"\\\\\\\"]\\\"],\\\"Image\\\":\\\"7fd39f4f39c71d76250adac15d7385fd6d68274e8a7ddd032b0b0bb6b3280a39\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"author\\\":\\\"cockpit@example.com\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"\\\\\\\"/echo-script\\\\\\\"\\\"],\\\"Image\\\":\\\"7fd39f4f39c71d76250adac15d7385fd6d68274e8a7ddd032b0b0bb6b3280a39\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"7fd39f4f39c71d76250adac15d7385fd6d68274e8a7ddd032b0b0bb6b3280a39\\\",\\\"parent\\\":\\\"b6962728b43855b1c803aec38e67e70bd137040543def671e415834cdfc01552\\\",\\\"created\\\":\\\"2016-03-04T16:48:47.790555865Z\\\",\\\"container\\\":\\\"ab835892b5519c2d0ffd84e22fe3d971a4a80d9d3e31757c7dce5379b947887e\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"chmod +x /echo-script\\\"],\\\"Image\\\":\\\"b6962728b43855b1c803aec38e67e70bd137040543def671e415834cdfc01552\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"author\\\":\\\"cockpit@example.com\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"sh\\\"],\\\"Image\\\":\\\"b6962728b43855b1c803aec38e67e70bd137040543def671e415834cdfc01552\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"Size\\\":49}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"b6962728b43855b1c803aec38e67e70bd137040543def671e415834cdfc01552\\\",\\\"parent\\\":\\\"b70fe9098263c3c82a67bc22caf523ced24185975088fd1043a799a6b4273882\\\",\\\"created\\\":\\\"2016-03-04T16:48:42.037533681Z\\\",\\\"container\\\":\\\"e16228a90ccf6d29c214833ba202b94b467979f5db03797d0a27da8430509966\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ADD file:b35fc316562d0e29fa7ae1e767f3597811f4349e30aa74122b67965a103f817a in /\\\"],\\\"Image\\\":\\\"b70fe9098263c3c82a67bc22caf523ced24185975088fd1043a799a6b4273882\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"author\\\":\\\"cockpit@example.com\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"sh\\\"],\\\"Image\\\":\\\"b70fe9098263c3c82a67bc22caf523ced24185975088fd1043a799a6b4273882\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"Size\\\":49}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"b70fe9098263c3c82a67bc22caf523ced24185975088fd1043a799a6b4273882\\\",\\\"parent\\\":\\\"6e45971d34d5ecfc0b946014369c8dacab8f2177bbd3751dd5289b9a5ba59df2\\\",\\\"created\\\":\\\"2016-03-04T16:48:36.879318282Z\\\",\\\"container\\\":\\\"a759048c873ac86cef61a9aec0ac72734cfe53feb7acd81a2b4975473675ed20\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) EXPOSE 8888/tcp\\\"],\\\"Image\\\":\\\"6e45971d34d5ecfc0b946014369c8dacab8f2177bbd3751dd5289b9a5ba59df2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"author\\\":\\\"cockpit@example.com\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"ExposedPorts\\\":{\\\"8888/tcp\\\":{}},\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"sh\\\"],\\\"Image\\\":\\\"6e45971d34d5ecfc0b946014369c8dacab8f2177bbd3751dd5289b9a5ba59df2\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"6e45971d34d5ecfc0b946014369c8dacab8f2177bbd3751dd5289b9a5ba59df2\\\",\\\"parent\\\":\\\"fef924a0204a00b3ec67318e2ed337b189c99ea19e2bf10ed30a13b87c5e17ab\\\",\\\"created\\\":\\\"2016-03-04T16:48:31.254943299Z\\\",\\\"container\\\":\\\"0484d0202032d11f48613463684f344ddc4f238635dcb640774e00828251f57d\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) MAINTAINER cockpit@example.com\\\"],\\\"Image\\\":\\\"65e4158d96256e032299e07ac28308d644c0e81d52b18dcb08847a5027b4f107\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"author\\\":\\\"cockpit@example.com\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":[\\\"PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin\\\"],\\\"Cmd\\\":[\\\"sh\\\"],\\\"Image\\\":\\\"65e4158d96256e032299e07ac28308d644c0e81d52b18dcb08847a5027b4f107\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":[],\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"fef924a0204a00b3ec67318e2ed337b189c99ea19e2bf10ed30a13b87c5e17ab\\\",\\\"parent\\\":\\\"9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9\\\",\\\"created\\\":\\\"2016-02-16T22:59:37.407805421Z\\\",\\\"container\\\":\\\"d23509cd0189de02bef382544ebfab515f29094f3c0e2f161fa7ce09afa8974e\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) CMD [\\\\\\\"sh\\\\\\\"]\\\"],\\\"Image\\\":\\\"9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":null,\\\"Labels\\\":{}},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":[\\\"sh\\\"],\\\"Image\\\":\\\"9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":null,\\\"Labels\\\":{}},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\"}\"\n },\n {\n \"v1Compatibility\": \"{\\\"id\\\":\\\"9a163e0b8d138ec700b5a5f7e62509012f7eb34b9f86cd3bbeb3d183958114a9\\\",\\\"created\\\":\\\"2016-02-16T22:59:36.792440427Z\\\",\\\"container\\\":\\\"13709f13afe11b7d4a007d2866afd20c5b783f0a89f4e6792a28102a4c12c473\\\",\\\"container_config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":[\\\"/bin/sh\\\",\\\"-c\\\",\\\"#(nop) ADD file:7cdf7a89f6a004b2e9501317bd72bd863d93a51255d8f83b2ed3058d385a4938 in /\\\"],\\\"Image\\\":\\\"\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":null,\\\"Labels\\\":null},\\\"docker_version\\\":\\\"1.9.1\\\",\\\"config\\\":{\\\"Hostname\\\":\\\"13709f13afe1\\\",\\\"Domainname\\\":\\\"\\\",\\\"User\\\":\\\"\\\",\\\"AttachStdin\\\":false,\\\"AttachStdout\\\":false,\\\"AttachStderr\\\":false,\\\"Tty\\\":false,\\\"OpenStdin\\\":false,\\\"StdinOnce\\\":false,\\\"Env\\\":null,\\\"Cmd\\\":null,\\\"Image\\\":\\\"\\\",\\\"Volumes\\\":null,\\\"WorkingDir\\\":\\\"\\\",\\\"Entrypoint\\\":null,\\\"OnBuild\\\":null,\\\"Labels\\\":null},\\\"architecture\\\":\\\"amd64\\\",\\\"os\\\":\\\"linux\\\",\\\"Size\\\":1113554}\"\n }\n ],\n \"signatures\": [\n {\n \"header\": {\n \"jwk\": {\n \"crv\": \"P-256\",\n \"kid\": \"VQO7:TVYU:FARI:VIFC:P2YU:W23P:AC7V:7ZXR:I5RO:DTY4:NRES:MGXE\",\n \"kty\": \"EC\",\n \"x\": \"EsCEZHIfgzZDBsbCzgCng884FdTcwyQ8dZbhap2cpgo\",\n \"y\": \"9Hlp74n2G2aMwzyvvM9G-8BbrXDp2dl9rt2RGbidQ8I\"\n },\n \"alg\": \"ES256\"\n },\n \"signature\": \"MFqsTUp-ci7Th-1r02bHj8eDh5xRg_WtjpN7WD4dI2Tuvg96fyGH6rf5bYKIjEVKz1_3Z42Ma06DDw8hSsMOGw\",\n \"protected\": \"eyJmb3JtYXRMZW5ndGgiOjI3NjU1LCJmb3JtYXRUYWlsIjoiQ24wIiwidGltZSI6IjIwMTYtMDMtMDRUMTY6NTA6MzJaIn0\"\n }\n ]\n}" - } -]); diff --git a/pkg/kubernetes/scripts/test-kube-client.js b/pkg/kubernetes/scripts/test-kube-client.js deleted file mode 100644 index e35767d61..000000000 --- a/pkg/kubernetes/scripts/test-kube-client.js +++ /dev/null @@ -1,920 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import { FIXTURE_BASIC } from "./fixture-basic.js"; -import { FIXTURE_LARGE } from "./fixture-large.js"; - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./kube-client"); -require("./kube-client-cockpit"); -require("./kube-client-mock"); - -(function() { - /* Filled in with a function */ - var inject; - - var module = angular.module("kubeClient.tests", [ - "kubeClient", - "kubeClient.mock" - ]) - - .config([ - 'KubeWatchProvider', - 'KubeRequestProvider', - function(KubeWatchProvider, KubeRequestProvider) { - KubeWatchProvider.KubeWatchFactory = "MockKubeWatch"; - KubeRequestProvider.KubeRequestFactory = "MockKubeRequest"; - } - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - "MockKubeData", - function(loader, data) { - if (fixtures) - data.load(fixtures); - loader.reset(true); - } - ]); - } - - QUnit.test("loader load", function (assert) { - var done = assert.async(); - assert.expect(7); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", function(loader) { - var promise = loader.load("nodes"); - assert.ok(!!promise, "promise returned"); - assert.equal(typeof promise.then, "function", "promise has then"); - assert.equal(typeof promise.catch, "function", "promise has catch"); - assert.equal(typeof promise.finally, "function", "promise has finally"); - - return promise.then(function(items) { - assert.ok(angular.isArray(items), "got items array"); - assert.equal(items.length, 1, "one node"); - assert.equal(items[0].metadata.name, "127.0.0.1", "localhost node"); - done(); - }); - }]); - }); - - QUnit.test("loader load encoding", function (assert) { - var done = assert.async(); - assert.expect(2); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", "$q", function(loader, select, $q) { - assert.equal(select().kind("Encoded").length, 0); - - var defer = $q.defer(); - var x = loader.listen(function() { - assert.equal(select().kind("Image").length, 1); - x.cancel(); - defer.resolve(); - done(); - }); - - loader.handle([{ - "apiVersion": "v1", - "kind": "Image", - "metadata": { - "name": "encoded:one", - "resourceVersion": 10000, - "uid": "11768037-ab8a-11e4-9a7c-100001001", - "namespace": "default", - "selfLink": "/oapi/v1/images/encoded%3Aone", - }, - }, { - "apiVersion": "v1", - "kind": "Image", - "metadata": { - "name": "encoded:one", - "resourceVersion": 10000, - "uid": "11768037-ab8a-11e4-9a7c-100001001", - "namespace": "default", - }, - }, { - "apiVersion": "v1", - "kind": "Image", - "metadata": { - "name": "encoded:one", - "resourceVersion": 10000, - "uid": "11768037-ab8a-11e4-9a7c-100001001", - "namespace": "default", - "selfLink": "/oapi/v1/images/encoded:one", - }, - }]); - - return defer.promise; - }]); - }); - - QUnit.test("loader load fail", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", function(loader) { - var promise = loader.load("nonexistant"); - return promise.then(function(data) { - assert.ok(!true, "successfully loaded"); - }, function(response) { - assert.equal(response.code, 404, "not found"); - assert.equal(response.message, "Not found here", "not found message"); - assert.ok(true, "not sucessfully loaded"); - done(); - }); - }]); - }); - - QUnit.test("loader watch", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", function(loader) { - return loader.watch("nodes").then(function(response) { - assert.ok("/api/v1/nodes/127.0.0.1" in loader.objects, "found node"); - var node = loader.objects["/api/v1/nodes/127.0.0.1"]; - assert.equal(node.metadata.name, "127.0.0.1", "localhost node"); - assert.equal(typeof node.spec.capacity, "object", "node has resources"); - done(); - }); - }]); - }); - - QUnit.test("list nodes", function (assert) { - var done = assert.async(); - assert.expect(6); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("nodes").then(function() { - var nodes = select().kind("Node"); - assert.ok("/api/v1/nodes/127.0.0.1" in nodes, "found node"); - var node = nodes["/api/v1/nodes/127.0.0.1"]; - assert.equal(node.metadata.name, "127.0.0.1", "localhost node"); - assert.equal(typeof node.spec.capacity, "object", "node has resources"); - - /* The same thing should be returned */ - var nodes1 = select().kind("Node"); - assert.strictEqual(nodes, nodes1, "same object returned"); - - /* Key should not be encoded as JSON */ - var parsed = JSON.parse(JSON.stringify(node)); - assert.ok(!("key" in parsed), "key should not be serialized"); - assert.strictEqual(parsed.key, undefined, "key not be undefined after serialize"); - - done(); - }); - }]); - }); - - QUnit.test("list pods", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("pods").then(function() { - var pods = select().kind("Pod"); - assert.equal(pods.length, 3, "found pods"); - var pod = pods["/api/v1/namespaces/default/pods/apache"]; - assert.equal(typeof pod, "object", "found pod"); - assert.equal(pod.metadata.labels.name, "apache", "pod has label"); - done(); - }); - }]); - }); - - QUnit.test("set namespace", function (assert) { - var done = assert.async(); - assert.expect(7); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["$q", "kubeLoader", "kubeSelect", function($q, loader, select) { - return loader.watch("pods").then(function() { - var pods = select().kind("Pod"); - assert.equal(pods.length, 3, "number of pods"); - assert.strictEqual(loader.limits.namespace, null, "namespace is null"); - - loader.limit({ namespace: "other" }); - assert.strictEqual(loader.limits.namespace, "other", "namespace is other"); - - pods = select().kind("Pod"); - assert.equal(pods.length, 1, "pods from namespace other"); - assert.ok("/api/v1/namespaces/other/pods/apache" in pods, "other pod"); - - loader.limit({ namespace: null }); - assert.strictEqual(loader.limits.namespace, null, "namespace is null again"); - var defer = $q.defer(); - var listened = false; - var x = loader.listen(function() { - if (listened) { - pods = select().kind("Pod"); - assert.equal(pods.length, 3, "all pods back"); - x.cancel(); - defer.resolve(); - done(); - } - listened = true; - }); - - return defer.promise; - }); - }]); - }); - - QUnit.test("add pod", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["$q", "kubeLoader", "kubeSelect", "MockKubeData", function($q, loader, select, data) { - return loader.watch("pods").then(function() { - var pods = select().kind("Pod"); - assert.equal(pods.length, 3, "number of pods"); - assert.equal(pods["/api/v1/namespaces/default/pods/apache"].metadata.labels.name, - "apache", "pod has label"); - - var defer = $q.defer(); - var x = loader.listen(function() { - var pods = select().kind("Pod"); - if (pods.length === 4) { - assert.equal(pods["/api/v1/namespaces/default/pods/aardvark"].metadata.labels.name, - "aardvark", "new pod present in items"); - x.cancel(); - defer.resolve(); - done(); - } - }); - - data.update("namespaces/default/pods/aardvark", { - "kind": "Pod", - "metadata": { - "name": "aardvark", - "uid": "22768037-ab8a-11e4-9a7c-080027300d85", - "namespace": "default", - "labels": { - "name": "aardvark" - }, - }, - "spec": { - "volumes": null, - "containers": [ ], - "imagePullPolicy": "IfNotPresent" - } - }); - - return defer.promise; - }); - }]); - }); - - QUnit.test("update pod", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["$q", "kubeLoader", "kubeSelect", "MockKubeData", function($q, loader, select, data) { - return loader.watch("pods").then(function() { - var pods = select().kind("Pod"); - assert.equal(pods.length, 3, "number of pods"); - assert.equal(pods["/api/v1/namespaces/default/pods/apache"].metadata.labels.name, - "apache", "pod has label"); - - var defer = $q.defer(); - var listened = false; - var x = loader.listen(function() { - var pods; - if (listened) { - pods = select().kind("Pod"); - assert.equal(pods["/api/v1/namespaces/default/pods/apache"].metadata.labels.name, - "apachepooo", "pod has changed"); - x.cancel(); - defer.resolve(); - done(); - } - listened = true; - }); - - data.update("namespaces/default/pods/apache", { - "kind": "Pod", - "metadata": { - "name": "apache", - "uid": "11768037-ab8a-11e4-9a7c-080027300d85", - "namespace": "default", - "labels": { - "name": "apachepooo" - }, - } - }); - - return defer.promise; - }); - }]); - }); - - QUnit.test("remove pod", function (assert) { - var done = assert.async(); - assert.expect(5); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["$q", "kubeLoader", "kubeSelect", "MockKubeData", function($q, loader, select, data) { - return loader.watch("pods").then(function() { - var pods = select().kind("Pod"); - assert.equal(pods.length, 3, "number of pods"); - assert.equal(pods["/api/v1/namespaces/default/pods/apache"].metadata.labels.name, - "apache", "pod has label"); - - var defer = $q.defer(); - var listened = false; - var x = loader.listen(function() { - var pods; - if (listened) { - pods = select().kind("Pod"); - assert.equal(pods.length, 2, "removed a pod"); - assert.strictEqual(pods["/api/v1/namespaces/default/pods/apache"], undefined, "removed pod"); - assert.equal(pods["/api/v1/namespaces/default/pods/database-1"].metadata.labels.name, - "wordpressreplica", "other pod"); - x.cancel(); - defer.resolve(); - done(); - } - listened = true; - }); - - data.update("namespaces/default/pods/apache", null); - return defer.promise; - }); - }]); - }); - - QUnit.test("list services", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("services").then(function() { - var services = select().kind("Service"); - var x; - var svc = null; - for (x in services) { - svc = services[x]; - break; - } - assert.ok(!!svc, "got a service"); - assert.equal(services.length, 2, "number of services"); - assert.equal(svc.metadata.name, "kubernetes", "service id"); - assert.equal(svc.spec.selector.component, "apiserver", "service has label"); - - done(); - }); - }]); - }); - - var CREATE_ITEMS = [ - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "pod1", - "uid": "d072fb85-f70e-11e4-b829-10c37bdb8410", - "resourceVersion": "634203", - "labels": { - "name": "pod1" - }, - }, - "spec": { - "volumes": null, - "containers": [{ - "name": "database", - "image": "mysql", - "ports": [{ "containerPort": 3306, "protocol": "TCP" }], - }], - "nodeName": "127.0.0.1" - } - }, { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "node1", - "uid": "6e51438e-d161-11e4-acbc-10c37bdb8410", - "resourceVersion": "634539", - }, - "status": { - "addresses": [ - { - "address": "172.2.3.1", - "type": "ExternalIP" - } - ] - } - } - ]; - - QUnit.test("create", function (assert) { - var done = assert.async(); - assert.expect(2); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - loader.watch("pods"); - loader.watch("nodes"); - loader.watch("namespaces"); - return methods.create(CREATE_ITEMS, "namespace1").then(function() { - assert.equal(loader.objects["/api/v1/namespaces/namespace1/pods/pod1"].metadata.name, "pod1", "pod object"); - assert.equal(loader.objects["/api/v1/nodes/node1"].metadata.name, "node1", "node object"); - done(); - }); - }]); - }); - - QUnit.test("create namespace exists", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - loader.watch("pods"); - loader.watch("nodes"); - loader.watch("namespaces"); - - var NAMESPACE_ITEM = { - "apiVersion" : "v1", - "kind" : "Namespace", - "metadata" : { "name": "namespace1" } - }; - - return methods.create(NAMESPACE_ITEM).then(function() { - assert.ok("/api/v1/namespaces/namespace1" in loader.objects, "namespace created"); - - return methods.create(CREATE_ITEMS, "namespace1").then(function() { - assert.ok("/api/v1/namespaces/namespace1/pods/pod1" in loader.objects, "pod created"); - assert.ok("/api/v1/nodes/node1" in loader.objects, "node created"); - done(); - }); - }); - }]); - }); - - QUnit.test("create namespace default", function (assert) { - var done = assert.async(); - assert.expect(2); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - loader.watch("pods"); - loader.watch("nodes"); - loader.watch("namespaces"); - return methods.create(CREATE_ITEMS).then(function() { - assert.equal(loader.objects["/api/v1/namespaces/default/pods/pod1"].metadata.name, "pod1", "pod created"); - assert.equal(loader.objects["/api/v1/nodes/node1"].metadata.name, "node1", "node created"); - done(); - }); - }]); - }); - - QUnit.test("create object exists", function (assert) { - var done = assert.async(); - assert.expect(1); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - loader.watch("pods"); - loader.watch("nodes"); - loader.watch("namespaces"); - - var items = CREATE_ITEMS.slice(); - items.push(items[0]); - - return methods.create(items).then(function(response) { - assert.equal(response, false, "should have failed"); - done(); - }, function(response) { - assert.equal(response.code, 409, "http already exists"); - done(); - }); - }]); - }); - - QUnit.test("delete pod", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - var watch = loader.watch("pods"); - - return methods.create(CREATE_ITEMS, "namespace2").then(function() { - assert.ok("/api/v1/namespaces/namespace2/pods/pod1" in loader.objects, "pod created"); - return methods.delete("/api/v1/namespaces/namespace2/pods/pod1").then(function() { - assert.ok(true, "remove succeeded"); - return watch.finally(function() { - assert.ok(!("/api/v1/namespaces/namespace2/pods/pod1" in loader.objects), "pod was removed"); - done(); - }); - }); - }); - }]); - }); - - QUnit.test("patch pod", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - var watch = loader.watch("pods"); - var path = "/api/v1/namespaces/namespace2/pods/pod1"; - - return methods.create(CREATE_ITEMS, "namespace2").then(function() { - assert.ok(path in loader.objects, "pod created"); - return methods.patch(path, { "extra": "blah" }).then(function() { - assert.ok(true, "patch succeeded"); - return methods.patch(loader.objects[path], { "second": "test" }).then(function() { - return watch.finally(function() { - var pod = loader.objects[path]; - assert.equal(pod.extra, "blah", "pod has changed"); - assert.equal(pod.second, "test", "pod changed by own object"); - done(); - }); - }); - }); - }); - }]); - }); - - QUnit.test("post", function (assert) { - var done = assert.async(); - assert.expect(1); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - return methods.post("/api/v1/namespaces/namespace1/pods", CREATE_ITEMS[0]).then(function(response) { - assert.equal(response.metadata.name, "pod1", "pod object"); - done(); - }); - }]); - }); - - QUnit.test("post fail", function (assert) { - var done = assert.async(); - assert.expect(1); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - return methods.post("/api/v1/nodes", FIXTURE_BASIC["nodes/127.0.0.1"]).then(function() { - assert.ok(false, "shouldn't succeed"); - }, function(response) { - assert.deepEqual(response, { "code": 409, "message": "Already exists" }, "got failure code"); - done(); - }); - }]); - }); - - QUnit.test("put", function (assert) { - var done = assert.async(); - assert.expect(1); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeMethods", function(loader, methods) { - var node = { "kind": "Node", "metadata": { "name": "127.0.0.1", labels: { "test": "value" } } }; - return methods.put("/api/v1/nodes/127.0.0.1", node).then(function(response) { - assert.deepEqual(response.metadata.labels, { "test": "value" }, "put returned object"); - done(); - }); - }]); - }); - - QUnit.test("check resource ok", function (assert) { - var done = assert.async(); - assert.expect(0); - - injectLoadFixtures(null); - - inject(["kubeMethods", function(methods) { - var data = { kind: "Blah", metadata: { name: "test" } }; - done(); - return methods.check(data); - }]); - }); - - QUnit.test("check resource name empty", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(null); - - inject(["kubeMethods", function(methods) { - var data = { kind: "Blah", metadata: { name: "" } }; - return methods.check(data).catch(function(ex) { - assert.ok(angular.isArray(ex), "threw array of failures"); - assert.equal(ex.length, 1, "number of errors"); - assert.ok(ex[0] instanceof Error, "threw an error"); - done(); - }); - }]); - }); - - QUnit.test("check resource name missing", function (assert) { - var done = assert.async(); - assert.expect(1); - - injectLoadFixtures(null); - - inject(["kubeMethods", function(methods) { - var data = { kind: "Blah", metadata: { } }; - return methods.check(data).then(function() { - assert.ok(true, "passed check"); - done(); - }, null); - }]); - }); - - QUnit.test("check resource name namespace bad", function (assert) { - var done = assert.async(); - assert.expect(6); - - injectLoadFixtures(null); - - inject(["kubeMethods", function(methods) { - var data = { kind: "Blah", metadata: { name: "a#a", namespace: "" } }; - var targets = { "metadata.name": "#name", "metadata.namespace": "#namespace" }; - return methods.check(data, targets).catch(function(ex) { - assert.ok(angular.isArray(ex), "threw array of failures"); - assert.equal(ex.length, 2, "number of errors"); - assert.ok(ex[0] instanceof Error, "threw an error"); - assert.equal(ex[0].target, "#name", "correct name target"); - assert.ok(ex[1] instanceof Error, "threw an error"); - assert.equal(ex[1].target, "#namespace", "correct name target"); - done(); - }); - }]); - }); - - QUnit.test("check resource namespace bad", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(null); - - inject(["kubeMethods", function(methods) { - var data = { kind: "Blah", metadata: { name: "aa", namespace: "" } }; - var targets = { "metadata.name": "#name", "metadata.namespace": "#namespace" }; - return methods.check(data, targets).catch(function(ex) { - assert.ok(angular.isArray(ex), "threw array of failures"); - assert.equal(ex.length, 1, "number of errors"); - assert.ok(ex[0] instanceof Error, "threw an error"); - assert.equal(ex[0].target, "#namespace", "correct name target"); - done(); - }); - }]); - }); - - QUnit.test("lookup uid", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("pods").then(function() { - /* Get the item */ - var item = select().kind("Pod") - .one(); - var uid = item.metadata.uid; - assert.ok(uid, "Have uid"); - - var by_uid_item = select().uid(uid) - .one(); - assert.strictEqual(item, by_uid_item, "load uid"); - - /* Shouldn't match */ - item = select().uid("bad") - .one(); - assert.strictEqual(item, null, "mismatch uid"); - - done(); - }); - }]); - }); - - QUnit.test("lookup host", function (assert) { - var done = assert.async(); - assert.expect(2); - - injectLoadFixtures(FIXTURE_BASIC); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("pods").then(function() { - /* Get the item */ - var item = select().host("127.0.0.1") - .one(); - assert.deepEqual(item.metadata.selfLink, "/api/v1/namespaces/default/pods/database-1", "correct pod"); - - /* Shouldn't match */ - item = select().host("127.0.0.2") - .one(); - assert.strictEqual(item, null, "mismatch host"); - - done(); - }); - }]); - }); - - QUnit.test("lookup", function (assert) { - var done = assert.async(); - assert.expect(6); - - injectLoadFixtures(FIXTURE_LARGE); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - var expected = { - "apiVersion": "v1", - "kind": "ReplicationController", - "metadata": { "labels": { "example": "mock", "name": "3controller" }, - "name": "3controller", - "resourceVersion": 10000, - "uid": "11768037-ab8a-11e4-9a7c-100001001", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/replicationcontrollers/3controller", - }, - "spec": { "replicas": 1, "selector": { "factor3": "yes" } } - }; - - return loader.watch("replicationcontrollers").then(function() { - /* Get the item */ - var item = select().kind("ReplicationController") - .name("3controller") - .namespace("default") - .one(); - assert.deepEqual(item, expected, "correct item"); - - /* The same item, without namespace */ - item = select().kind("ReplicationController") - .name("3controller") - .one(); - assert.deepEqual(item, expected, "selected without namespace"); - - /* Any replication controller */ - item = select().kind("ReplicationController") - .one(); - assert.equal(item.kind, "ReplicationController", "any replication controller"); - - /* Shouldn't match */ - item = select().kind("BadKind") - .name("3controller") - .namespace("default") - .one(); - assert.strictEqual(item, null, "mismatch kind"); - item = select().kind("ReplicationController") - .name("badcontroller") - .namespace("default") - .one(); - assert.strictEqual(item, null, "mismatch name"); - item = select().kind("ReplicationController") - .name("3controller") - .namespace("baddefault") - .one(); - assert.strictEqual(item, null, "mismatch namespace"); - - done(); - }); - }]); - }); - - QUnit.test("select", function (assert) { - var done = assert.async(); - assert.expect(12); - - injectLoadFixtures(FIXTURE_LARGE); - - inject(["kubeLoader", "kubeSelect", function(loader, select) { - return loader.watch("pods").then(function() { - var image = { kind: "Image" }; - - /* same thing twice */ - var first = select(image); - var second = select(image); - assert.strictEqual(first, second, "identical for single object"); - - /* null thing twice */ - first = select(null); - second = select(null); - assert.strictEqual(first, second, "identical for null object"); - - /* Select everything odd, 500 pods */ - var results = select().namespace("default") - .label({ "type": "odd" }); - assert.equal(results.length, 500, "correct amount"); - - /* The same thing should be returned */ - var results1 = select().namespace("default") - .label({ "type": "odd" }); - assert.strictEqual(results, results1, "same object returned"); - - /* Select everything odd, but wrong namespace, no pods */ - results = select().namespace("other") - .label({ "type": "odd" }); - assert.equal(results.length, 0, "other namespace no pods"); - - /* The same ones selected even when a second (present) label */ - results = select().namespace("default") - .label({ "type": "odd", "tag": "silly" }); - assert.equal(results.length, 500, "with additional label"); - - /* Nothing selected when additional invalid field */ - results = select().namespace("default") - .label({ "type": "odd", "tag": "billy" }); - assert.equal(results.length, 0, "no objects"); - - /* Limit by kind */ - results = select().kind("Pod") - .namespace("default") - .label({ "type": "odd" }); - assert.equal(results.length, 500, "by kind"); - - /* Limit by invalid kind */ - results = select().kind("Ood") - .namespace("default") - .label({ "type": "odd" }); - assert.equal(results.length, 0, "nothing for invalid kind"); - - /* Everything selected when no selector */ - results = select().namespace("default"); - assert.equal(results.length, 1000, "all pods"); - - /* Nothing selected when bad namespace */ - results = select().namespace("bad"); - assert.equal(results.length, 0, "bad namespace no objects"); - - /* Nothing selected when empty selector */ - results = select().label({ }); - assert.equal(results.length, 0, "nothing selected"); - - done(); - }); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['kubeClient.tests']); -}()); diff --git a/pkg/kubernetes/scripts/test-nodes.js b/pkg/kubernetes/scripts/test-nodes.js deleted file mode 100644 index 2fda22d2f..000000000 --- a/pkg/kubernetes/scripts/test-nodes.js +++ /dev/null @@ -1,309 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./nodes"); -require("./kube-client-cockpit"); - -function suite(fixtures) { - /* Filled in with a function */ - var inject; - - var module = angular.module("kubernetes.nodes.tests", [ - "kubeClient", - 'kubeClient.cockpit', - "kubernetes.nodes", - ]) - - .config([ - 'KubeTranslateProvider', - 'KubeFormatProvider', - function(KubeTranslateProvider, KubeFormatProvider) { - KubeTranslateProvider.KubeTranslateFactory = "CockpitTranslate"; - KubeFormatProvider.KubeFormatFactory = "CockpitFormat"; - } - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - function(loader, data) { - loader.reset(true); - if (fixtures) - loader.handle(fixtures); - } - ]); - } - - QUnit.test("nodeStatus tests", function (assert) { - var done = assert.async(); - assert.expect(10); - - injectLoadFixtures(fixtures); - - inject(["nodeData", "kubeSelect", function(nodeData, select) { - var nodes = select().kind("Node"); - assert.equal(nodeData.nodeStatus(), "Unknown", "undefined node"); - assert.equal(nodeData.nodeStatus({}), "Unknown", "empty node"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/unknown-node']), "Unknown", "no conditions"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/unknown-node2']), "Unknown", "no ready condition"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/failed-node']), "Not Ready", "failed"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/ready-node']), "Ready", "ready"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/unschedulable-node']), "Scheduling Disabled", "ready but unschedulable"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/unschedulable-failed-node']), "Not Ready", "not ready and unschedulable"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/disk-node']), "Ready", "out of disk"); - assert.equal(nodeData.nodeStatus(nodes['/api/v1/nodes/mem-node']), "Ready", "out of memory"); - done(); - }]); - }); - - QUnit.test("nodeStatusIcon tests", function (assert) { - var done = assert.async(); - assert.expect(10); - - injectLoadFixtures(fixtures); - - inject(["nodeData", "kubeSelect", function(nodeData, select) { - var nodes = select().kind("Node"); - assert.equal(nodeData.nodeStatusIcon(), "wait", "undefined node"); - assert.equal(nodeData.nodeStatusIcon({}), "wait", "empty node"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/unknown-node']), "wait", "no conditions"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/unknown-node2']), "wait", "no ready condition"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/failed-node']), "fail", "failed"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/ready-node']), ""); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/unschedulable-node']), "", "ready but unschedulable"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/unschedulable-failed-node']), "fail", "not ready and unschedulable"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/disk-node']), "warn", "out of disk"); - assert.equal(nodeData.nodeStatusIcon(nodes['/api/v1/nodes/mem-node']), "warn", "out of memory"); - done(); - }]); - }); - - QUnit.test("nodeConditions tests", function (assert) { - var done = assert.async(); - assert.expect(5); - - injectLoadFixtures(fixtures); - - inject(["nodeData", "kubeSelect", function(nodeData, select) { - var nodes = select().kind("Node"); - assert.equal(nodeData.nodeConditions(), undefined); - assert.equal(nodeData.nodeConditions(null), undefined); - assert.deepEqual(nodeData.nodeConditions({}), {}); - var conditions = nodeData.nodeConditions(nodes['/api/v1/nodes/unschedulable-node']); - assert.deepEqual(conditions, { - "OutOfDisk": { - "status": "False", - "type": "OutOfDisk" - }, - "Ready": { - "status": "True", - "type": "Ready" - } - }, "Correct object"); - assert.strictEqual(conditions, nodeData.nodeConditions(nodes['/api/v1/nodes/unschedulable-node']), "identical when called with the same object"); - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['kubernetes.nodes.tests']); -} - -/* Invoke the test suite with this data */ -suite([ - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "unknown-node", - "selfLink": "/api/v1/nodes/unknown-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f1", - "resourceVersion": "17152", - }, - "status": { - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "unknown-node2", - "selfLink": "/api/v1/nodes/unknown-node2", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f2", - "resourceVersion": "17152", - }, - "status": { - "conditions": [ - { - "type": "Other", - "status": "Other", - }, - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "failed-node", - "selfLink": "/api/v1/nodes/failed-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f3", - "resourceVersion": "17152", - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "Other", - }, - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "ready-node", - "selfLink": "/api/v1/nodes/ready-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f4", - "resourceVersion": "17152", - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "True", - }, - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "unschedulable-node", - "selfLink": "/api/v1/nodes/unschedulable-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f5", - "resourceVersion": "17152", - }, - "spec": { - "unschedulable": true - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "True", - }, - { - "type": "OutOfDisk", - "status": "False", - } - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "unschedulable-failed-node", - "selfLink": "/api/v1/nodes/unschedulable-failed-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f7", - "resourceVersion": "17152", - }, - "spec": { - "unschedulable": true - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "False", - }, - { - "type": "OutOfDisk", - "status": "False", - } - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "disk-node", - "selfLink": "/api/v1/nodes/disk-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f8", - "resourceVersion": "17152", - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "True", - }, - { - "type": "OutOfDisk", - "status": "True", - } - ], - } - }, - { - "kind": "Node", - "apiVersion": "v1", - "metadata": { - "name": "mem-node", - "selfLink": "/api/v1/nodes/mem-node", - "uid": "4920ab25-1092-11e6-a03c-5254009e00f7", - "resourceVersion": "17152", - }, - "status": { - "conditions": [ - { - "type": "Ready", - "status": "True", - }, - { - "type": "OutOfMemory", - "status": "True", - } - ], - } - } -]); diff --git a/pkg/kubernetes/scripts/test-projects.js b/pkg/kubernetes/scripts/test-projects.js deleted file mode 100644 index 13f319d07..000000000 --- a/pkg/kubernetes/scripts/test-projects.js +++ /dev/null @@ -1,404 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./projects"); - -function suite(fixtures) { - /* Filled in with a function */ - var inject; - - var module = angular.module("registry.projects.tests", [ - "kubeClient", - "registry.projects", - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - function(loader, data) { - loader.reset(true); - if (fixtures) - loader.handle(fixtures); - } - ]); - } - - QUnit.test("format Users", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["projectData", 'kubeSelect', function(projectUtil, select) { - var user = select().kind("User") - .name("amanda"); - assert.equal(user.length, 1, "number of users"); - assert.equal(projectUtil.formatMembers(user.one().groups, 'Groups'), - "finance", "number of groups"); - user = select().kind("User") - .name("jay"); - assert.equal(projectUtil.formatMembers(user.one().groups, 'Groups'), - "4 Groups", "number of groups"); - assert.equal(projectUtil.formatMembers(user.one().groups, 'Users'), - "4 Users", "number of users"); - done(); - }]); - }); - - QUnit.test("policy checks", function (assert) { - var done = assert.async(); - assert.expect(11); - - injectLoadFixtures(fixtures); - - inject(["projectData", 'kubeSelect', function(projectUtil, select) { - var user = select().kind("User") - .name("amanda"); - var policybinding = select().kind("PolicyBinding") - .namespace("financeprj") - .name(":default"); - assert.equal(user.length, 1, "number of users"); - assert.equal(policybinding.length, 1, "number of policybinding"); - var rolesArray = projectUtil.getAllRoles("", ""); - assert.equal(rolesArray.length, 0, "no values passed 1 "); - rolesArray = projectUtil.getAllRoles(); - assert.equal(rolesArray.length, 0, "no values passed 2"); - rolesArray = projectUtil.getAllRoles(user.one(), "financeprj"); - assert.equal(rolesArray.length, 3, "values passed"); - - var regRolesArray = projectUtil.getRegistryRoles(user.one(), "financeprj"); - assert.equal(regRolesArray[0], "Admin", "getRegistryRoles displayRole values"); - regRolesArray = projectUtil.getRegistryRoles("", ""); - assert.equal(regRolesArray.length, 0, "no values passed 3 "); - regRolesArray = projectUtil.getRegistryRoles(); - assert.equal(regRolesArray.length, 0, "no values passed 4"); - - assert.equal(projectUtil.isRegistryRole(user.one(), "Admin", "financeprj"), true, "check if Admin registry role"); - assert.equal(projectUtil.isRegistryRole("system:unauthenticated", "Pull", "financeprj"), true, "check if Pull registry role"); - assert.equal(projectUtil.isRoles(user.one(), "financeprj"), true, "check if any role exist"); - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['registry.projects.tests']); -} - -/* Invoke the test suite with this data */ -suite([ - { - "kind": "User", - "apiVersion": "v1", - "metadata": { - "name": "amanda", - "selfLink": "/oapi/v1/users/amanda", - "uid": "8d10b355-b9d4-11e5-b7ad-5254009e00f1", - "resourceVersion": "1114", - "creationTimestamp": "2016-01-13T09:03:45Z" - }, - "identities": [ - "anypassword:abc123" - ], - "groups": [ - "finance" - ] - }, - { - "kind": "User", - "apiVersion": "v1", - "metadata": { - "name": "jay", - "selfLink": "/oapi/v1/users/jay", - "uid": "8d10b355-b9d4-11e5-b7ad-5254009e00f1", - "resourceVersion": "1114", - "creationTimestamp": "2016-01-13T09:03:45Z" - }, - "identities": [ - "anypassword:abc123" - ], - "groups": [ - "finance", "admin", "hr", "dev" - ] - }, - { - "kind": "Group", - "apiVersion": "v1", - "metadata": { - "name": "finance", - "selfLink": "/oapi/v1/groups/finance", - "uid": "bff4578c-b9d4-11e5-b7ad-5254009e00f1", - "resourceVersion": "1124", - "creationTimestamp": "2016-01-13T09:05:10Z" - }, - "users": [ - "tom", - "jay", - "amanda", - "myadmin" - ] - }, - { - "kind": "PolicyBinding", - "apiVersion": "v1", - "metadata": { - "name": ":default", - "namespace": "financeprj", - "selfLink": "/oapi/v1/namespaces/financeprj/policybindings/:default", - "uid": "d5a78dfc-e9e4-11e5-a1bd-3c970eb867f7", - "resourceVersion": "53908", - "creationTimestamp": "2016-03-14T13:01:15Z" - }, - "lastModified": "2016-03-24T07:19:42Z", - "policyRef": { - "name": "default" - }, - "roleBindings": [ - { - "name": "admin", - "roleBinding": { - "metadata": { - "name": "admin", - "namespace": "financeprj", - "uid": "f33cbdd7-ea0e-11e5-ba57-3c970eb867f7", - "resourceVersion": "24003", - "creationTimestamp": "2016-03-14T18:02:43Z" - }, - "userNames": null, - "groupNames": null, - "subjects": [ - - ], - "roleRef": { - "name": "admin" - } - } - }, - { - "name": "edit", - "roleBinding": { - "metadata": { - "name": "edit", - "namespace": "financeprj", - "selfLink": "/oapi/v1/namespaces/financeprj/rolebindings/edit", - "uid": "d5a340e0-e9e4-11e5-a1bd-3c970eb867f7", - "resourceVersion": "24002", - "creationTimestamp": "2016-03-14T13:01:15Z" - }, - "userNames": [ - "amanda" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "amanda" - } - ], - "roleRef": { - "name": "edit" - } - } - }, - { - "name": "registry-admin", - "roleBinding": { - "metadata": { - "name": "registry-admin", - "namespace": "financeprj", - "uid": "c0746786-f0fd-11e5-b5cb-3c970eb867f7", - "resourceVersion": "24005", - "creationTimestamp": "2016-03-23T13:47:15Z" - }, - "userNames": [ - "amanda" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "amanda" - } - ], - "roleRef": { - "name": "registry-admin" - } - } - }, - { - "name": "registry-editor", - "roleBinding": { - "metadata": { - "name": "registry-editor", - "namespace": "financeprj", - "selfLink": "/oapi/v1/namespaces/financeprj/rolebindings/registry-editor", - "uid": "c613716d-f0fd-11e5-b5cb-3c970eb867f7", - "resourceVersion": "24339", - "creationTimestamp": "2016-03-23T13:47:24Z" - }, - "userNames": [ - "sunny", - "sam", - "janet" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "sunny" - }, - { - "kind": "User", - "name": "sam" - }, - { - "kind": "User", - "name": "janet" - } - ], - "roleRef": { - "name": "registry-editor" - } - } - }, - { - "name": "registry-viewer", - "roleBinding": { - "metadata": { - "name": "registry-viewer", - "namespace": "financeprj", - "uid": "de6e0980-f0fd-11e5-b5cb-3c970eb867f7", - "resourceVersion": "24264", - "creationTimestamp": "2016-03-23T13:48:05Z" - }, - "userNames": [ - "janet", - "sunny" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "janet" - }, - { - "kind": "User", - "name": "sunny" - }, - { - "kind": "SystemGroup", - "name": "system:unauthenticated" - } - ], - "roleRef": { - "name": "registry-viewer" - } - } - }, - { - "name": "view", - "roleBinding": { - "metadata": { - "name": "view", - "namespace": "financeprj", - "uid": "07e34b4c-ea0f-11e5-ba57-3c970eb867f7", - "resourceVersion": "23860", - "creationTimestamp": "2016-03-14T18:03:18Z" - }, - "userNames": null, - "groupNames": null, - "subjects": [ - - ], - "roleRef": { - "name": "view" - } - } - } - ] - }, - { - "kind": "RoleBinding", - "apiVersion": "v1", - "metadata": { - "name": "registry-admin", - "namespace": "financeprj", - "selfLink": "/oapi/v1/namespaces/financeprj/rolebindings/registry-admin", - "uid": "c0746786-f0fd-11e5-b5cb-3c970eb867f7", - "resourceVersion": "24005", - "creationTimestamp": "2016-03-23T13:47:15Z" - }, - "userNames": [ - "amanda" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "amanda" - } - ], - "roleRef": { - "name": "registry-admin" - } - }, - { - "kind": "RoleBinding", - "apiVersion": "v1", - "metadata": { - "name": "admin", - "namespace": "financeprj", - "selfLink": "/oapi/v1/namespaces/financeprj/rolebindings/admin", - "uid": "c0746786-f0fd-11e5-b5cb-3c970eb867f7", - "resourceVersion": "24005", - "creationTimestamp": "2016-03-23T13:47:15Z" - }, - "userNames": [ - "amanda" - ], - "groupNames": null, - "subjects": [ - { - "kind": "User", - "name": "amanda" - } - ], - "roleRef": { - "name": "admin" - } - } -]); diff --git a/pkg/kubernetes/scripts/test-tags.js b/pkg/kubernetes/scripts/test-tags.js deleted file mode 100644 index 3b1dc938f..000000000 --- a/pkg/kubernetes/scripts/test-tags.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./tags"); - -var specData; - -function suite() { - /* Filled in with a function */ - var inject; - - var module = angular.module("registry.tags.tests", [ - "registry.tags" - ]); - - QUnit.test("parseSpec", function (assert) { - var done = assert.async(); - assert.expect(1); - - inject(["imageTagData", function(data) { - var names = data.parseSpec(specData); - assert.deepEqual(names, [ "1", "1.23", "1.24.0", "1.24.2", "latest" ], "parsed names correctly"); - done(); - }]); - }); - - QUnit.test("buildSpec with spec", function (assert) { - var done = assert.async(); - assert.expect(1); - - inject(["imageTagData", function(data) { - var spec = angular.extend({ }, specData); - spec = data.buildSpec(["2.5", "latest", "second"], spec, true, 'docker.io/busybox'); - assert.deepEqual(spec, { - "dockerImageRepository": "busybox", - "tags": [ - { "name": "2.5", "importPolicy": { "insecure": true }, - "from": { "kind": "DockerImage", "name": "docker.io/busybox:2.5" } }, - { "annotations": null, "from": { "kind": "DockerImage", "name": "docker.io/busybox:latest" }, - "generation": 2, "importPolicy": { "insecure": true }, "name": "latest" }, - { "name": "second", "importPolicy": { "insecure": true }, - "from": { "kind": "DockerImage", "name": "docker.io/busybox:second" } } - ] - }, "build spec correctly"); - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['registry.tags.tests']); -} - -specData = { - "dockerImageRepository": "busybox", - "tags": [ - { - "name": "1", - "annotations": null, - "from": { - "kind": "DockerImage", - "name": "docker.io/busybox:1" - }, - "generation": 2, - "importPolicy": {} - }, - { - "name": "1.23", - "annotations": null, - "from": { - "kind": "DockerImage", - "name": "docker.io/busybox:1.23" - }, - "generation": 2, - "importPolicy": {} - }, - { - "name": "1.24.0", - "annotations": null, - "from": { - "kind": "DockerImage", - "name": "docker.io/busybox:1.24.0" - }, - "generation": 2, - "importPolicy": {} - }, - { - "name": "1.24.2", - "annotations": null, - "from": { - "kind": "DockerImage", - "name": "docker.io/busybox:1.24.2" - }, - "generation": 2, - "importPolicy": {} - }, - { - "name": "latest", - "annotations": null, - "from": { - "kind": "DockerImage", - "name": "docker.io/busybox:latest" - }, - "generation": 2, - "importPolicy": { - "insecure": false - } - } - ] -}; - -suite(); diff --git a/pkg/kubernetes/scripts/test-utils.js b/pkg/kubernetes/scripts/test-utils.js deleted file mode 100644 index d3fe83c05..000000000 --- a/pkg/kubernetes/scripts/test-utils.js +++ /dev/null @@ -1,130 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./utils"); - -function suite() { - /* Filled in with a function */ - var inject; - - var module = angular.module("kubeUtils.tests", [ - "kubeUtils", - ]); - - QUnit.test("map Named Array", function (assert) { - var done = assert.async(); - assert.expect(4); - - inject(["KubeMapNamedArray", function lala(mapNamedArray) { - var target = { - "one": { - "name": "one", - "other": "other1", - "value": 1 - }, - "two": { - "name": "two", - "other": "other2", - "value": 2 - } - }; - var target2 = { - "other1": { - "name": "one", - "other": "other1", - "value": 1 - }, - "other2": { - "name": "two", - "other": "other2", - "value": 2 - } - }; - - var source = [{ - "name": "one", - "other": "other1", - "value": 1 - }, { - "name": "two", - "other": "other2", - "value": 2 - }]; - - assert.deepEqual(mapNamedArray(), {}); - assert.deepEqual(mapNamedArray([]), {}); - assert.deepEqual(mapNamedArray(source), target); - assert.deepEqual(mapNamedArray(source, "other"), target2); - done(); - }]); - }); - - QUnit.test("Kube string to bytes", function (assert) { - var done = assert.async(); - assert.expect(20); - - inject(["KubeStringToBytes", function(stringToBytes) { - assert.deepEqual(stringToBytes(), undefined); - assert.deepEqual(stringToBytes("bad"), undefined); - assert.deepEqual(stringToBytes("10"), undefined); - assert.deepEqual(stringToBytes("aGi"), undefined); - assert.deepEqual(stringToBytes("Gi"), undefined); - assert.deepEqual(stringToBytes("Gi10"), undefined); - assert.deepEqual(stringToBytes("Gil"), undefined); - assert.deepEqual(stringToBytes("10E"), 10000000000000000000); - assert.deepEqual(stringToBytes("10P"), 10000000000000000); - assert.deepEqual(stringToBytes("10T"), 10000000000000); - assert.deepEqual(stringToBytes("10G"), 10000000000); - assert.deepEqual(stringToBytes("10M"), 10000000); - assert.deepEqual(stringToBytes("10K"), 10000); - assert.deepEqual(stringToBytes("10m"), 0.01); - assert.deepEqual(stringToBytes("10Ei"), 11529215046068469760); - assert.deepEqual(stringToBytes("10Pi"), 11258999068426240); - assert.deepEqual(stringToBytes("10Ti"), 10995116277760); - assert.deepEqual(stringToBytes("10Gi"), 10737418240); - assert.deepEqual(stringToBytes("10Mi"), 10485760); - assert.deepEqual(stringToBytes("10Ki"), 10240); - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['kubeUtils.tests']); -} - -suite(); diff --git a/pkg/kubernetes/scripts/test-volumes.js b/pkg/kubernetes/scripts/test-volumes.js deleted file mode 100644 index f60cb9c93..000000000 --- a/pkg/kubernetes/scripts/test-volumes.js +++ /dev/null @@ -1,841 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import QUnit from "qunit-tests"; -var angular = require("angular"); - -require("./volumes"); -require("./kube-client-cockpit"); - -function suite(fixtures) { - /* Filled in with a function */ - var inject; - - var module = angular.module("kubernetes.volumes.tests", [ - "kubeClient", - 'kubeClient.cockpit', - "kubernetes.volumes", - "kubeUtils", - ]) - - .config([ - 'KubeTranslateProvider', - 'KubeFormatProvider', - function(KubeTranslateProvider, KubeFormatProvider) { - KubeTranslateProvider.KubeTranslateFactory = "CockpitTranslate"; - KubeFormatProvider.KubeFormatFactory = "CockpitFormat"; - } - ]); - - function injectLoadFixtures(fixtures) { - inject([ - "kubeLoader", - function(loader, data) { - loader.reset(true); - if (fixtures) - loader.handle(fixtures); - } - ]); - } - - QUnit.test("pods for Claim", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var claim = select().kind("PersistentVolumeClaim") - .name("bound-claim") - .one(); - var pods = volumeData.podsForClaim(claim); - assert.equal(pods.length, 1, "number of pods"); - assert.equal(pods.one().metadata.name, "mock-pod", "correct pod"); - - pods = volumeData.podsForClaim(); - assert.deepEqual(pods.length, 0, "null claim pods"); - - pods = volumeData.podsForClaim({}); - assert.deepEqual(pods.length, 0, "empty claim pods"); - - done(); - }]); - }); - - QUnit.test("volumes for Pod", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var pod = select().kind("Pod") - .one(); - var volumes = volumeData.volumesForPod(pod); - assert.deepEqual(volumes, { - "default-token-luvqo": { - "name": "default-token-luvqo", - "secret": { - "secretName": "default-token-luvqo" - }, - "mounts": { - "mock-volume-container": { - "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", - "name": "default-token-luvqo", - "readOnly": true - }, - "mock-volume-container1": { - "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount", - "name": "default-token-luvqo", - "readOnly": true - } - } - }, - "host-tmp": { - "mounts": { - "mock-volume-container": { - "mountPath": "/other", - "name": "host-tmp" - }, - "mock-volume-container1": { - "mountPath": "/tmp", - "name": "host-tmp" - } - }, - "name": "host-tmp", - "persistentVolumeClaim": { - "claimName": "bound-claim" - } - }, - "missing-claim": { - "mounts": { - "mock-volume-container": { - "mountPath": "/tmp", - "name": "missing-claim" - } - }, - "name": "missing-claim", - "persistentVolumeClaim": { - "claimName": "missing-claim" - } - }, - "missing-claim2": { - "name": "missing-claim2", - "persistentVolumeClaim": { - "claimName": "missing-claim2" - } - } - }); - assert.equal(volumes, volumeData.volumesForPod(pod), "same object"); - - assert.deepEqual(volumeData.volumesForPod(), {}, "No null volumes"); - assert.deepEqual(volumeData.volumesForPod({}), {}, "No empty volumes"); - - done(); - }]); - }); - - QUnit.test("claim From Volume Source", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var pod = select().kind("Pod") - .one(); - var volumes = volumeData.volumesForPod(pod); - var source = volumes["host-tmp"]["persistentVolumeClaim"]; - var claim = volumeData.claimFromVolumeSource(source, "default"); - assert.equal(claim.metadata.name, "bound-claim", "correct claim"); - assert.equal(claim.kind, "PersistentVolumeClaim", "correct type"); - - assert.deepEqual(volumeData.claimFromVolumeSource(), null, "No null volumes"); - assert.deepEqual(volumeData.claimFromVolumeSource({}), null, "No empty volumes"); - - done(); - }]); - }); - - QUnit.test("claim For Volume", function (assert) { - var done = assert.async(); - assert.expect(5); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var bound = select().kind("PersistentVolume") - .name("bound") - .one(); - var claim = volumeData.claimForVolume(bound); - - assert.equal(claim.metadata.name, "bound-claim", "correct claim"); - assert.equal(claim.kind, "PersistentVolumeClaim", "correct claim"); - - var unbound = select().kind("PersistentVolume") - .name("unbound") - .one(); - assert.equal(volumeData.claimForVolume(unbound), null, "no claim"); - - assert.equal(volumeData.claimForVolume(), null, "null volume"); - assert.equal(volumeData.claimForVolume(), null, "empty volume"); - done(); - }]); - }); - - QUnit.test("claim phases", function (assert) { - var done = assert.async(); - assert.expect(2); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var claim = select().kind("PersistentVolumeClaim") - .statusPhase("Bound") - .one(); - assert.equal(claim.metadata.name, "bound-claim", "select bound claims"); - - var pending = select().kind("PersistentVolumeClaim") - .statusPhase("Pending") - .one(); - assert.equal(pending.metadata.name, "unbound-claim", "select unbound claims"); - done(); - }]); - }); - - QUnit.test("volume Types", function (assert) { - var done = assert.async(); - assert.expect(4); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var pv = select().kind("PersistentVolume") - .name("bound") - .one(); - var volumes = volumeData.volumesForPod(select().kind("Pod") - .one()); - assert.equal(volumeData.getVolumeType(pv.spec), "nfs", "correct type"); - assert.equal(volumeData.getVolumeType(volumes["default-token-luvqo"]), "secret", "secret volume"); - assert.equal(volumeData.getVolumeType(), undefined, "null volume"); - assert.equal(volumeData.getVolumeType({}), undefined, "empty volume"); - done(); - }]); - }); - - QUnit.test("volume Labels", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["volumeData", 'kubeSelect', function(volumeData, select) { - var pv = select().kind("PersistentVolume") - .name("bound") - .one(); - assert.equal(volumeData.getVolumeLabel(), "Unknown", "null volume"); - assert.equal(volumeData.getVolumeLabel({}), "Unknown", "empty volume"); - assert.equal(volumeData.getVolumeLabel(pv.spec), "NFS Mount", "volume label"); - done(); - }]); - }); - - QUnit.test("default volume build", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["defaultVolumeFields", "kubeSelect", function(volumeFields, select) { - var blank_fields = { - "accessModes": { - "ReadOnlyMany": "Read only from multiple nodes", - "ReadWriteMany": "Read and write from multiple nodes", - "ReadWriteOnce": "Read and write from a single node" - }, - "capacity": "", - "policy": "Retain", - "reclaimPolicies": { - "Delete": "Delete", - "Recycle": "Recycle", - "Retain": "Retain" - } - }; - - assert.deepEqual(blank_fields, volumeFields.build(), "default fields"); - assert.deepEqual(blank_fields, volumeFields.build({}), "empty fields"); - assert.deepEqual({ - "accessModes": { - "ReadOnlyMany": "Read only from multiple nodes", - "ReadWriteMany": "Read and write from multiple nodes", - "ReadWriteOnce": "Read and write from a single node" - }, - "capacity": "2Gi", - "policy": "Retain", - "ReadWriteMany": true, - "reclaimPolicies": { - "Delete": "Delete", - "Recycle": "Recycle", - "Retain": "Retain" - } - }, volumeFields.build(select().name("available") - .one()), "default fields"); - done(); - }]); - }); - - QUnit.test("default volume validate", function (assert) { - var done = assert.async(); - assert.expect(15); - - injectLoadFixtures(fixtures); - - inject(["defaultVolumeFields", "kubeSelect", function(volumeFields, select) { - var result = volumeFields.validate(null, {}); - assert.equal(result.data, null, "blank fields blank data"); - assert.equal(result.errors.length, 4); - assert.equal(result.errors[0].target, "#last-access", "blank fields access error"); - assert.equal(result.errors[1].target, "#modify-name", "blank fields name error"); - assert.equal(result.errors[2].target, "#modify-capacity", "blank fields capacity error"); - assert.equal(result.errors[3].target, "#last-policy", "blank fields policy error"); - - var invalid = { - "reclaimPolicies": { "policy1": "policy2" }, - "accessModes": { "mode1": "mode1" }, - "mode2": true, - "policy" : "policy2", - "name": "a name", - "capacity": "invalid" - }; - result = volumeFields.validate(null, invalid); - assert.equal(result.data, null, "invalid fields invalid data"); - assert.equal(result.errors.length, 4); - assert.equal(result.errors[0].target, "#last-access", "invalid fields access error"); - assert.equal(result.errors[1].target, "#modify-name", "invalid fields name error"); - assert.equal(result.errors[2].target, "#modify-capacity", "invalid fields capacity error"); - assert.equal(result.errors[3].target, "#last-policy", "invalid fields policy error"); - - var valid = { - "reclaimPolicies": { "policy1": "policy2" }, - "accessModes": { "mode1": "mode1" }, - "mode1": true, - "policy" : "policy1", - "name": " name ", - "capacity": " 2Gi " - }; - var spec = { - "accessModes": [ - "mode1" - ], - "capacity": { - "storage": "2Gi" - }, - "persistentVolumeReclaimPolicy": "policy1" - }; - result = volumeFields.validate(null, valid); - assert.deepEqual(result.data, { - "kind": "PersistentVolume", - "metadata": { - "name": "name" - }, - "spec": spec - }, "no item full object"); - assert.equal(result.errors.length, 0); - - result = volumeFields.validate({}, valid); - assert.deepEqual(result.data, { "spec": spec }, "with item only spec"); - - done(); - }]); - }); - - QUnit.test("gluster volume build", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["glusterfsVolumeFields", "kubeSelect", function(gfs, select) { - var endpoints = select().kind("Endpoints"); - var blank_fields = { - "glusterfsPath": undefined, - "endpoint": undefined, - "endpointOptions": endpoints, - "readOnly": undefined, - "reclaimPolicies": { - "Retain": "Retain" - } - }; - - assert.deepEqual(blank_fields, gfs.build(), "default gluster fields"); - assert.deepEqual(blank_fields, gfs.build({}), "empty gluster fields"); - assert.deepEqual({ - "glusterfsPath": "kube_vo", - "endpointOptions": endpoints, - "readOnly": undefined, - "reclaimPolicies": { - "Retain": "Retain" - }, - "endpoint": "my-gluster-endpoint", - }, gfs.build(select().name("gfs-volume") - .one()), "gluster fields"); - - done(); - }]); - }); - - QUnit.test("gfs volume validate", function (assert) { - var done = assert.async(); - assert.expect(9); - - injectLoadFixtures(fixtures); - - inject(["glusterfsVolumeFields", function(nfsVolumeFields) { - var result = nfsVolumeFields.validate(null, {}); - assert.equal(result.data, null, "blank fields blank data"); - assert.equal(result.errors.length, 2); - assert.equal(result.errors[0].target, "#modify-endpoint", "blank fields endpoint error"); - assert.equal(result.errors[1].target, "#modify-glusterfs-path", "blank fields path error"); - - var invalid = { - "endpoint": "bad", - "glusterfsPath": "name" - }; - result = nfsVolumeFields.validate(null, invalid); - assert.equal(result.data, null, "invalid fields invalid data"); - assert.equal(result.errors.length, 1); - assert.equal(result.errors[0].target, "#modify-endpoint", "invalid endpoint error"); - - var valid = { - "endpoint": "my-gluster-endpoint", - "glusterfsPath": "name", - }; - var source = { - "endpoints": "my-gluster-endpoint", - "path": "name", - "readOnly": false - }; - result = nfsVolumeFields.validate(null, valid); - assert.deepEqual(result.data, source, "valid source result"); - assert.equal(result.errors.length, 0, "no errors when valid"); - done(); - }]); - }); - - QUnit.test("nfs volume build", function (assert) { - var done = assert.async(); - assert.expect(3); - - injectLoadFixtures(fixtures); - - inject(["nfsVolumeFields", "kubeSelect", function(nfsVolumeFields, select) { - var blank_fields = { - "path": undefined, - "readOnly": undefined, - "reclaimPolicies": { - "Recycle": "Recycle", - "Retain": "Retain" - }, - "server": undefined - }; - - assert.deepEqual(blank_fields, nfsVolumeFields.build(), "default nfs fields"); - assert.deepEqual(blank_fields, nfsVolumeFields.build({}), "empty nfs fields"); - assert.deepEqual({ - "path": "/tmp", - "readOnly": true, - "reclaimPolicies": { - "Recycle": "Recycle", - "Retain": "Retain" - }, - "server": "host-or.ip:port", - }, nfsVolumeFields.build(select().name("bound") - .one()), "nfs fields"); - done(); - }]); - }); - - QUnit.test("nfs volume validate", function (assert) { - var done = assert.async(); - assert.expect(10); - - injectLoadFixtures(fixtures); - - inject(["nfsVolumeFields", function(nfsVolumeFields) { - var result = nfsVolumeFields.validate(null, {}); - assert.equal(result.data, null, "blank fields blank data"); - assert.equal(result.errors.length, 2); - assert.equal(result.errors[0].target, "#nfs-modify-server", "blank fields server error"); - assert.equal(result.errors[1].target, "#modify-path", "blank fields path error"); - - var invalid = { - "server": "server/bad", - "path": "bad", - }; - result = nfsVolumeFields.validate(null, invalid); - assert.equal(result.data, null, "invalid fields invalid data"); - assert.equal(result.errors.length, 2); - assert.equal(result.errors[0].target, "#nfs-modify-server", "invalid fields server error"); - assert.equal(result.errors[1].target, "#modify-path", "invalid fields path error"); - - var valid = { - "server": "host.or-ip:port", - "path": "/tmp", - }; - var source = { - "server": "host.or-ip:port", - "path": "/tmp", - "readOnly": false - }; - result = nfsVolumeFields.validate(null, valid); - assert.deepEqual(result.data, source, "valid source result"); - assert.equal(result.errors.length, 0, "no errors when valid"); - done(); - }]); - }); - - angular.module('exceptionOverride', []).factory('$exceptionHandler', function() { - return function(exception, cause) { - exception.message += ' (caused by "' + cause + '")'; - throw exception; - }; - }); - - module.run([ - '$injector', - function($injector) { - inject = function inject(func) { - return $injector.invoke(func); - }; - QUnit.start(); - } - ]); - - angular.bootstrap(document, ['kubernetes.volumes.tests']); -} - -/* Invoke the test suite with this data */ -suite([ - { - "kind": "PersistentVolume", - "apiVersion": "v1", - "metadata": { - "name": "iscsi-vol", - "selfLink": "/api/v1/persistentvolumes/iscsi-vol", - "uid": "3b2e0dc2-f6a4-11e5-9e36-5254009e00f2", - "resourceVersion": "1325", - "creationTimestamp": "2016-03-30T18:21:33Z" - }, - "spec": { - "capacity": { - "storage": "2Gi" - }, - "iscsi":{ - "targetPortal": "host-or.ip:port", - "iqn": "iqn.1994-05.t.com.redhat:83ba4072bb9c", - "lun": 10, - "iscsiInterface": "custom-iface", - "fsType":"ext3", - "readOnly": true, - }, - "accessModes":["ReadWriteOnce"], - "persistentVolumeReclaimPolicy": "Retain" - }, - "status": { - "phase": "Available" - } - }, - { - "kind": "PersistentVolume", - "apiVersion": "v1", - "metadata": { - "name": "available", - "selfLink": "/api/v1/persistentvolumes/available", - "uid": "3b2e0dc2-f6a4-11e5-9e36-5254009e00f1", - "resourceVersion": "1325", - "creationTimestamp": "2016-03-30T18:21:33Z" - }, - "spec": { - "capacity": { - "storage": "2Gi" - }, - "hostPath": { - "path": "/tmp" - }, - "accessModes": [ - "ReadWriteMany" - ], - "persistentVolumeReclaimPolicy": "Retain" - }, - "status": { - "phase": "Available" - } - }, - { - "kind": "PersistentVolume", - "apiVersion": "v1", - "metadata": { - "name": "bound", - "selfLink": "/api/v1/persistentvolumes/bound", - "uid": "ae3133fc-f6a4-11e5-9e36-5254009e00f1", - "resourceVersion": "1388", - "creationTimestamp": "2016-03-30T18:24:46Z" - }, - "spec": { - "capacity": { - "storage": "5Gi" - }, - "nfs": { - "path": "/tmp", - "server": "host-or.ip:port", - "readOnly": true - }, - "accessModes": [ - "ReadWriteMany" - ], - "claimRef": { - "kind": "PersistentVolumeClaim", - "namespace": "default", - "name": "bound-claim", - "uid": "43dfbea5-f6a4-11e5-9e36-5254009e00f1", - "apiVersion": "v1", - "resourceVersion": "1331" - }, - "persistentVolumeReclaimPolicy": "Retain" - }, - "status": { - "phase": "Bound" - } - }, - { - "kind": "PersistentVolume", - "apiVersion": "v1", - "metadata": { - "name": "gfs-volume", - "selfLink": "/api/v1/persistentvolumes/gfs-volume", - "uid": "ae3133fc-f6a4-11e5-9e36-5254009e00cc", - "resourceVersion": "1388", - "creationTimestamp": "2016-03-30T18:24:46Z" - }, - "spec": { - "capacity": { - "storage": "5Gi" - }, - "glusterfs": { - "path": "kube_vo", - "endpoints": "my-gluster-endpoint" - }, - "accessModes": [ - "ReadWriteMany" - ], - "persistentVolumeReclaimPolicy": "Retain" - }, - "status": { - "phase": "Pending" - } - }, - { - "kind": "PersistentVolumeClaim", - "apiVersion": "v1", - "metadata": { - "name": "unbound-claim", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/unbound-claim", - "uid": "3d474220-f6b3-11e5-ab0c-3b97187a9955", - "resourceVersion": "1331", - "creationTimestamp": "2016-03-30T18:21:47Z" - }, - "spec": { - "accessModes": [ - "ReadWriteMany" - ], - "resources": { - "requests": { - "storage": "5Gi" - } - } - }, - "status": { - "phase": "Pending" - } - }, - { - "kind": "PersistentVolumeClaim", - "apiVersion": "v1", - "metadata": { - "name": "bound-claim", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/bound-claim", - "uid": "43dfbea5-f6a4-11e5-9e36-5254009e00f1", - "resourceVersion": "1387", - "creationTimestamp": "2016-03-30T18:21:47Z" - }, - "spec": { - "accessModes": [ - "ReadWriteMany" - ], - "resources": { - "requests": { - "storage": "5Gi" - } - }, - "volumeName": "available" - }, - "status": { - "phase": "Bound", - "accessModes": [ - "ReadWriteMany" - ], - "capacity": { - "storage": "5Gi" - } - } - }, - { - "kind": "Pod", - "apiVersion": "v1", - "metadata": { - "name": "mock-pod", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/pods/mock-pod", - "uid": "43d38e8e-f6a4-11e5-9e36-5254009e00f1", - "resourceVersion": "1328", - "creationTimestamp": "2016-03-30T18:21:47Z" - }, - "spec": { - "volumes": [ - { - "name": "missing-claim", - "persistentVolumeClaim": { - "claimName": "missing-claim" - } - }, - { - "name": "host-tmp", - "persistentVolumeClaim": { - "claimName": "bound-claim" - } - }, - { - "name": "missing-claim2", - "persistentVolumeClaim": { - "claimName": "missing-claim2" - } - }, - { - "name": "default-token-luvqo", - "secret": { - "secretName": "default-token-luvqo" - } - } - ], - "containers": [ - { - "name": "mock-volume-container1", - "image": "busybox:buildroot-2014.02", - "command": [ - "/bin/sh", - "-c", - "for x in $(seq 1 1000); do echo 'HelloMessage.' \u003e\u00262; sleep 1; done" - ], - "ports": [ - { - "containerPort": 9949, - "protocol": "TCP" - } - ], - "resources": {}, - "volumeMounts": [ - { - "name": "host-tmp", - "mountPath": "/tmp" - }, - { - "name": "default-token-luvqo", - "readOnly": true, - "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount" - } - ] - }, - { - "name": "mock-volume-container", - "image": "busybox:buildroot-2014.02", - "command": [ - "/bin/sh", - "-c", - "for x in $(seq 1 1000); do echo 'HelloMessage.' \u003e\u00262; sleep 1; done" - ], - "ports": [ - { - "containerPort": 9949, - "protocol": "TCP" - } - ], - "resources": {}, - "volumeMounts": [ - { - "name": "host-tmp", - "mountPath": "/other" - }, - { - "name": "missing-claim", - "mountPath": "/tmp" - }, - { - "name": "default-token-luvqo", - "readOnly": true, - "mountPath": "/var/run/secrets/kubernetes.io/serviceaccount" - } - ] - } - ] - }, - "status": { - "phase": "Pending" - } - }, - { - "kind": "Endpoints", - "apiVersion": "v1", - "metadata": { - "name": "my-gluster-endpoint", - "namespace": "default", - "selfLink": "/api/v1/namespaces/default/endpoints/my-gluster-endpoint", - "uid": "498cac38-ffc0-11e5-8098-5254009e00dd", - "resourceVersion": "1078", - "creationTimestamp": "2016-04-11T08:35:03Z" - }, - "subsets": [ - { - "addresses": [ - { - "ip": "172.17.0.2" - } - ], - "ports": [ - { - "port": 1, - "protocol": "TCP" - } - ] - } - ] - } - -]); diff --git a/pkg/kubernetes/scripts/topology.js b/pkg/kubernetes/scripts/topology.js deleted file mode 100644 index eace11a98..000000000 --- a/pkg/kubernetes/scripts/topology.js +++ /dev/null @@ -1,189 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-route'); - require('kubernetes-topology-graph/dist/topology-graph.js'); - - require('./kube-client'); - require('./details'); - - require('../views/topology-page.html'); - - var icons = { - Pod: '#vertex-Pod', - ReplicationController: '#vertex-ReplicationController', - Node: '#vertex-Node', - Service: '#vertex-Service', - DeploymentConfig: "#vertex-DeploymentConfig", - Route: "#vertex-Route" - }; - - angular.module('kubernetes.topology', [ - 'ngRoute', - 'kubernetesUI', - 'kubeClient', - 'kubernetes.details' - ]) - - .config(['$routeProvider', - function($routeProvider) { - $routeProvider.when('/topology/:namespace?', { - templateUrl: 'views/topology-page.html', - controller: 'TopologyCtrl' - }); - } - ]) - - .controller('TopologyCtrl', [ - '$scope', - '$window', - 'kubeLoader', - 'kubeSelect', - 'KubeDiscoverSettings', - 'itemActions', - function($scope, $window, loader, select, discoverSettings, actions) { - $scope.items = { }; - $scope.relations = [ ]; - $scope.selected = null; - - var ready = false; - - function link_for_item(kind, namespace, name) { - var rel = select().kind(kind) - .name(name) - .namespace(namespace) - .one(); - if (rel) - return rel.metadata.selfLink; - } - - function rels_for_item(item) { - var rels = { }; - var endpoints, subsets; - var link; - - /* Lookup which node this pod is scheduled on */ - if (item.kind === "Node") { - rels = select().kind("Pod") - .host(item.metadata.name); - - /* Kubernetes tells us about endpoints, which are service to pod mappings */ - } else if (item.kind === "Service") { - endpoints = select().kind("Endpoints") - .namespace(item.metadata.namespace) - .name(item.metadata.name) - .one() || { }; - subsets = endpoints.subsets || [ ]; - subsets.forEach(function(subset) { - var addresses = subset.addresses || [ ]; - addresses.forEach(function(address) { - if (address.targetRef && address.targetRef.kind == "Pod") - link = link_for_item("Pod", address.targetRef.namespace, - address.targetRef.name); - if (link) - rels[link] = {}; - }); - }); - - /* For ReplicationControllers we just do the selection ourselves */ - } else if (item.kind === "ReplicationController") { - rels = select().kind("Pod") - .namespace(item.metadata.namespace); - if (item.spec.selector) - rels = rels.label(item.spec.selector); - } else if (item.kind === "DeploymentConfig") { - rels = select().kind("ReplicationController") - .namespace(item.metadata.namespace) - .label({ "openshift.io/deployment-config.name" : item.metadata.name }); - /* For Routes just build it out */ - } else if (item.kind === "Route" && item.spec.to) { - link = link_for_item(item.spec.to.kind, item.metadata.namespace, - item.spec.to.name); - if (link) - rels[link] = {}; - } - return rels; - } - - loader.watch("Node", $scope); - loader.watch("Pod", $scope); - loader.watch("ReplicationController", $scope); - loader.watch("Service", $scope); - loader.watch("Endpoints", $scope); - - discoverSettings().then(function(settings) { - if (settings.flavor === "openshift") { - loader.watch("DeploymentConfig", $scope); - loader.watch("Route", $scope); - } - }); - - loader.listen(function(changed, removed) { - var selected_meta; - var relations = []; - var item; - var key; - - $scope.items = select(); - if ($scope.selected) { - selected_meta = $scope.selected.metadata || {}; - item = select().kind($scope.selected.kind) - .name(selected_meta.name); - if (selected_meta.namespace) - item = item.namespace(selected_meta.namespace); - $scope.selected = item.one(); - } - - for (key in $scope.items) { - var pkey; - var rels = rels_for_item($scope.items[key]); - for (pkey in rels) - relations.push({ source: key, target: pkey }); - } - - $scope.relations = relations; - }, $scope); - - $scope.$on("select", function(ev, item) { - $scope.$applyAsync(function () { - $scope.selected = item; - }); - }); - - /* Make a copy since we modify */ - $scope.kinds = angular.copy(icons); - - /* All the actions available on the $scope */ - angular.extend($scope, actions); - - function resized() { - $scope.height = { height: (window.innerHeight - 60) + "px" }; - if (ready) - $scope.$digest(); - } - - angular.element($window).bind('resize', resized); - resized(); - - ready = true; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/utils.js b/pkg/kubernetes/scripts/utils.js deleted file mode 100644 index 21a86dcd3..000000000 --- a/pkg/kubernetes/scripts/utils.js +++ /dev/null @@ -1,204 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - - angular.module("kubeUtils", []) - - .factory("KubeMapNamedArray", [ - function () { - return function mapNamedArray(array, attr) { - if (!attr) - attr = "name"; - - var result = { }; - var i, len; - if (array) { - for (i = 0, len = array.length; i < len; i++) - result[array[i][attr]] = array[i]; - } - return result; - }; - } - ]) - - .factory("KubeStringToBytes", [ - function() { - return function (byte_string) { - var valid_suffixes = { - "E": 1000000000000000000, - "P": 1000000000000000, - "T": 1000000000000, - "G": 1000000000, - "M": 1000000, - "K": 1000, - "m": 0.001, - "Ei": 1152921504606846976, - "Pi": 1125899906842624, - "Ti": 1099511627776, - "Gi": 1073741824, - "Mi": 1048576, - "Ki": 1024, - }; - - if (!byte_string) - return; - - byte_string = byte_string.trim(); - for (var key in valid_suffixes) { - if (byte_string.length > key.length && - byte_string.slice(-key.length) === key) { - var number = Number(byte_string.slice(0, -key.length)); - if (!isNaN(number)) - return number * valid_suffixes[key]; - } - } - }; - } - ]) - - .provider('KubeFormat', [ - function() { - var self = this; - - /* Until we come up with a good default implementation, must be provided */ - self.KubeFormatFactory = "MissingFormat"; - - function load(injector, name) { - if (angular.isString(name)) - return injector.get(name, "KubeFormat"); - else - return injector.invoke(name); - } - - self.$get = [ - "$injector", - function($injector) { - return load($injector, self.KubeFormatFactory); - } - ]; - } - ]) - - .factory("MissingFormat", [ - function() { - return function MissingFormatCapacity(value) { - throw Error("no KubeFormatFactory set"); - }; - } - ]) - - .provider('KubeTranslate', [ - function() { - var self = this; - - /* Until we come up with a good default implementation, must be provided */ - self.KubeTranslateFactory = "KubeTranslate"; - - function load(injector, name) { - if (angular.isString(name)) - return injector.get(name, "MissingKubeTranslate"); - else - return injector.invoke(name); - } - - self.$get = [ - "$injector", - function($injector) { - return load($injector, self.KubeTranslateFactory); - } - ]; - } - ]) - - .factory("MissingKubeTranslate", [ - function() { - function error_func() { - throw Error("no KubeTranslateFactory set"); - } - - return { - gettext: error_func, - ngettext: error_func - }; - } - ]) - - .provider('KubeBrowserStorage', [ - function() { - var self = this; - - /* Until we come up with a good default implementation, must be provided */ - self.KubeBrowserStorageFactory = "DefaultKubeBrowserStorage"; - - function load(injector, name) { - if (angular.isString(name)) - return injector.get(name, "DefaultKubeBrowserStorage"); - else - return injector.invoke(name); - } - - self.$get = [ - "$injector", - function($injector) { - return load($injector, self.KubeBrowserStorageFactory); - } - ]; - } - ]) - - .factory("DefaultKubeBrowserStorage", [ - "$window", - function($window) { - return { - localStorage: $window.localStorage, - sessionStorage: $window.sessionStorage, - }; - } - ]) - - .filter('formatCapacityName', function() { - return function(key) { - var data; - if (key == "cpu") { - data = "CPUs"; - } else { - key = key.replace(/-/g, " "); - data = key.charAt(0).toUpperCase() + key.substr(1); - } - return data; - }; - }) - - .filter('formatCapacityValue', [ - "KubeFormat", - "KubeStringToBytes", - function (format, stringToBytes) { - return function(value, key) { - if (key == "memory") { - var raw = stringToBytes(value); - if (raw) - value = format.formatBytes(raw); - } - return value; - }; - } - ]); -}()); diff --git a/pkg/kubernetes/scripts/volumes.js b/pkg/kubernetes/scripts/volumes.js deleted file mode 100644 index 09cc6409b..000000000 --- a/pkg/kubernetes/scripts/volumes.js +++ /dev/null @@ -1,1042 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-route'); - require('angular-dialog.js'); - - require('./date'); - require('./listing'); - require('./kube-client'); - require('./utils'); - - require('../views/volumes-page.html'); - require('../views/pv-page.html'); - require('../views/pv-body.html'); - require('../views/pvc-body.html'); - require('../views/pv-claim.html'); - require('../views/volume-body.html'); - require('../views/pvc-delete.html'); - require('../views/pv-delete.html'); - require('../views/pv-modify.html'); - - var VOLUME_FACTORY_SUFFIX = "VolumeFields"; - - angular.module('kubernetes.volumes', [ - 'ngRoute', - 'kubeClient', - 'kubernetes.date', - 'kubernetes.listing', - 'ui.cockpit', - ]) - - .config([ - '$routeProvider', - function($routeProvider) { - $routeProvider - .when('/volumes', { - templateUrl: 'views/volumes-page.html', - controller: 'VolumeCtrl' - }) - - .when('/volumes/:target', { - controller: 'VolumeCtrl', - templateUrl: 'views/pv-page.html' - }); - } - ]) - - /* - * The controller for the volumes view. - */ - .controller('VolumeCtrl', [ - '$scope', - 'kubeLoader', - 'kubeSelect', - 'ListingState', - 'filterService', - '$routeParams', - '$location', - 'volumeActions', - '$timeout', - function($scope, loader, select, ListingState, filterService, - $routeParams, $location, actions, $timeout) { - var target = $routeParams["target"] || ""; - $scope.target = target; - $scope.pvFailure = null; - - loader.listen(function() { - $scope.pending = select().kind("PersistentVolumeClaim") - .statusPhase("Pending"); - $scope.pvs = select().kind("PersistentVolume"); - if (target) - $scope.item = select().kind("PersistentVolume") - .name(target) - .one(); - }, $scope); - - loader.watch("PersistentVolume", $scope) - .catch(function (ex) { - $scope.pvFailure = ex.message; - }); - - loader.watch("PersistentVolumeClaim", $scope); - loader.watch("Endpoints", $scope); - loader.watch("Pod", $scope); - - $scope.listing = new ListingState($scope); - - /* All the actions available on the $scope */ - angular.extend($scope, actions); - - /* Redirect after a delete */ - $scope.deletePV = function(item) { - var promise = actions.deletePV(item); - - /* If the promise is successful, redirect to another page */ - promise.then(function() { - if ($scope.target) - $location.path('/volumes/'); - }); - - return promise; - }; - - $scope.$on("activate", function(ev, id) { - ev.preventDefault(); - $location.path('/volumes/' + id); - }); - } - ]) - - .directive('pvBody', - function() { - return { - restrict: 'A', - templateUrl: 'views/pv-body.html' - }; - } - ) - - .directive('pvcBody', - function() { - return { - restrict: 'A', - templateUrl: 'views/pvc-body.html', - scope: { - item: '=item', - settings: '=settings' - }, - }; - } - ) - - .directive('pvClaim', [ - 'volumeData', - 'kubeLoader', - function(volumeData, loader) { - return { - restrict: 'A', - templateUrl: 'views/pv-claim.html', - link: function(scope, element, attrs) { - loader.listen(function() { - scope.pvc = volumeData.claimForVolume(scope.item); - scope.pods = volumeData.podsForClaim(scope.pvc); - }, scope); - - loader.watch("PersistentVolume", scope); - loader.watch("PersistentVolumeClaim", scope); - loader.watch("Pod", scope); - }, - }; - } - ]) - - .directive('volumeBody', - function() { - return { - restrict: 'A', - templateUrl: 'views/volume-body.html', - scope: { - volume: '=volume' - }, - }; - } - ) - - .factory("volumeData", [ - 'kubeSelect', - "KubeTranslate", - "KubeMapNamedArray", - function (select, translate, mapNamedArray) { - const _ = translate.gettext; - - var KNOWN_VOLUME_TYPES = { - "gcePersistentDisk" : _("GCE Persistent Disk"), - "awsElasticBlockStore" : _("AWS Elastic Block Store"), - "gitRepo" : _("Git Repository"), - "secret" : _("Secret"), - "emptyDir" : _("Empty Directory"), - "hostPath" : _("Host Path"), - "glusterfs" : _("Gluster FS"), - "nfs" : _("NFS Mount"), - "rbd" : _("Rados Block Device"), - "iscsi" : _("ISCSI"), - "cinder" : _("Cinder"), - "cephfs" : _("Ceph Filesystem Mount"), - "fc" : _("Fibre Channel"), - "flocker" : _("Flocker"), - "flexVolume" : _("Flex"), - "azureFile" : _("Azure") - }; - - var ACCESS_MODES = { - "ReadWriteOnce" : _("Read and write from a single node"), - "ReadOnlyMany" : _("Read only from multiple nodes"), - "ReadWriteMany" : _("Read and write from multiple nodes"), - }; - - var RECLAIM_POLICIES = { - "Retain" : _("Retain"), - "Delete" : _("Delete"), - "Recycle" : _("Recycle") - }; - - select.register({ - name: "volumeName", - digest: function(arg) { - if (typeof arg === "string") - return arg; - - var spec = arg.spec || {}; - return spec.volumeName; - } - }); - - select.register({ - name: "claim", - digests: function(arg) { - if (typeof arg === "string") - return ["claimName=" + arg]; - - var i; - var ret = []; - var spec = arg.spec || {}; - var vols = spec.volumes || []; - for (i in vols) { - var claim = vols[i].persistentVolumeClaim || {}; - if (claim.claimName) - ret.push("claimName=" + claim.claimName); - } - return ret; - } - }); - - function getVolumeType(volume) { - var keys = Object.keys(KNOWN_VOLUME_TYPES); - var i; - volume = volume || {}; - for (i = 0; i < keys.length; i++) { - var key = keys[i]; - if (volume[key]) - return key; - } - } - - function getVolumeLabel(volume) { - var type = getVolumeType(volume); - if (type) - return KNOWN_VOLUME_TYPES[type]; - return _("Unknown"); - } - - function claimForVolume(volume) { - var uid = ""; - if (volume && volume.spec.claimRef) - uid = volume.spec.claimRef.uid || ""; - - return select().kind("PersistentVolumeClaim") - .uid(uid) - .one(); - } - - function claimFromVolumeSource(source, namespace) { - source = source || {}; - return select().kind("PersistentVolumeClaim") - .namespace(namespace || "") - .name(source.claimName || "") - .one(); - } - - function podsForClaim(claim) { - var meta; - claim = claim || {}; - meta = claim.metadata || {}; - return select().kind("Pod") - .namespace(meta.namespace || "") - .claim(meta.name || ""); - } - - function volumesForPod(item) { - var volumes; - var i, j, container, volumeMounts, name; - if (item && !item.volumes) { - if (item.spec) - volumes = mapNamedArray(item.spec.volumes); - else - volumes = { }; - - if (item.spec && item.spec.containers) { - for (i = 0; i < item.spec.containers.length; i++) { - container = item.spec.containers[i]; - volumeMounts = container.volumeMounts || []; - for (j = 0; j < volumeMounts.length; j++) { - name = volumeMounts[j].name; - if (!volumes[name]) - volumes[name] = {}; - - if (!volumes[name]['mounts']) - volumes[name]['mounts'] = {}; - - volumes[name]['mounts'][container.name] = volumeMounts[j]; - } - } - } - - item.volumes = volumes; - } - return item ? item.volumes : { }; - } - - return { - podsForClaim: podsForClaim, - volumesForPod: volumesForPod, - claimFromVolumeSource: claimFromVolumeSource, - claimForVolume: claimForVolume, - getVolumeType: getVolumeType, - getVolumeLabel: getVolumeLabel, - reclaimPolicies: RECLAIM_POLICIES, - accessModes: ACCESS_MODES, - }; - } - ]) - - .factory('volumeActions', [ - '$modal', - '$injector', - 'volumeData', - function($modal, $injector, volumeData) { - function canEdit(item) { - var spec = item ? item.spec : {}; - var type = volumeData.getVolumeType(spec); - if (type) - return $injector.has(type + VOLUME_FACTORY_SUFFIX); - return true; - } - - function deleteItem(item, resolve, template, ev) { - if (ev) - ev.stopPropagation(); - - return $modal.open({ - animation: false, - controller: 'VolumeDeleteCtrl', - templateUrl: template, - resolve: resolve, - }).result; - } - - function deletePVC(item, ev) { - var resolve = { - dialogData: function() { - return { item: item, - pvc: item, - pods: volumeData.podsForClaim(item) }; - } - }; - return deleteItem(item, resolve, 'views/pvc-delete.html', ev); - } - - function deletePV(item, ev) { - var resolve = { - dialogData: function() { - return { item: item }; - } - }; - return deleteItem(item, resolve, 'views/pv-delete.html', ev); - } - - function createPV(item) { - return $modal.open({ - animation: false, - controller: 'PVModifyCtrl', - templateUrl: 'views/pv-modify.html', - resolve: { - dialogData: function() { - return { pvc : item }; - } - }, - }).result; - } - - function modifyPV(item) { - return $modal.open({ - animation: false, - controller: 'PVModifyCtrl', - templateUrl: 'views/pv-modify.html', - resolve: { - dialogData: function() { - return { item: item }; - } - }, - }).result; - } - - return { - modifyPV: modifyPV, - createPV: createPV, - deletePV: deletePV, - deletePVC: deletePVC, - canEdit: canEdit, - }; - } - ]) - - .factory("defaultVolumeFields", [ - "volumeData", - "KubeStringToBytes", - "KubeTranslate", - "KUBE_NAME_RE", - function (volumeData, stringToBytes, translate, NAME_RE) { - const _ = translate.gettext; - - function build (item, type) { - if (!item) - item = {}; - - var spec = item.spec || {}; - var requests, storage; - - if (item.kind == "PersistentVolumeClaim") { - requests = spec.resources ? spec.resources.requests : {}; - storage = requests ? requests.storage : ""; - } else { - storage = spec.capacity ? spec.capacity.storage : ""; - } - - var fields = { - "capacity" : storage || "", - "policy" : spec.persistentVolumeReclaimPolicy || "Retain", - "accessModes": volumeData.accessModes, - "reclaimPolicies": volumeData.reclaimPolicies, - }; - - var i; - for (i in spec.accessModes || []) { - fields[spec.accessModes[i]] = true; - } - - return fields; - } - - function validate (item, fields) { - var ex, spec, name, capacity, policy, i, validModes; - var accessModes = []; - var ret = { - errors: [], - data: null, - }; - - validModes = Object.keys(fields.accessModes || {}); - for (i = 0; i < validModes.length; i++) { - var mode = validModes[i]; - if (fields[mode]) - accessModes.push(mode); - } - - if (accessModes.length < 1) { - ex = new Error(_("Please select a valid access mode")); - ex.target = "#last-access"; - ret.errors.push(ex); - ex = null; - } - - name = fields.name ? fields.name.trim() : fields.name; - if (!item && (!name || !NAME_RE.test(name))) { - ex = new Error(_("Please provide a valid name")); - ex.target = "#modify-name"; - ret.errors.push(ex); - ex = null; - } - - capacity = fields.capacity ? fields.capacity.trim() : fields.capacity; - if (!item && (!capacity || !stringToBytes(capacity))) { - ex = new Error(_("Please provide a valid storage capacity.")); - ex.target = "#modify-capacity"; - ret.errors.push(ex); - ex = null; - } - - policy = fields.policy ? fields.policy.trim() : fields.policy; - if (!fields.reclaimPolicies || !fields.reclaimPolicies[policy]) { - ex = new Error(_("Please select a valid policy option.")); - ex.target = "#last-policy"; - ret.errors.push(ex); - ex = null; - } - - if (ret.errors.length < 1) { - spec = { - "accessModes" : accessModes, - "capacity" : { "storage" : capacity }, - "persistentVolumeReclaimPolicy" : policy, - }; - - if (item) { - ret.data = { - spec: spec - }; - } else { - ret.data = { - kind: "PersistentVolume", - metadata: { - name: fields.name.trim() - }, - spec: spec - }; - } - } - - return ret; - } - - return { - build: build, - validate: validate, - }; - } - ]) - - .factory("glusterfs" + VOLUME_FACTORY_SUFFIX, [ - "volumeData", - "KubeTranslate", - "kubeSelect", - function (volumeData, translate, select) { - const _ = translate.gettext; - - function build(item) { - if (!item) - item = {}; - - var spec = item.spec || {}; - var glusterfs = spec.glusterfs || {}; - - return { - endpoint: glusterfs.endpoints, - endpointOptions: select().kind("Endpoints"), - glusterfsPath: glusterfs.path, - readOnly: glusterfs.readOnly, - reclaimPolicies: { - "Retain" : volumeData.reclaimPolicies["Retain"] - }, - }; - } - - function validate (item, fields) { - var ex, endpoint, path; - var ret = { - errors: [], - data: null, - }; - - endpoint = fields.endpoint ? fields.endpoint.trim() : fields.endpoint; - if (!select().kind("Endpoints") - .name(endpoint) - .one()) { - ex = new Error(_("Please select a valid endpoint")); - ex.target = "#modify-endpoint"; - ret.errors.push(ex); - ex = null; - } - - // The API calls glusterfs volume name, path. - path = fields.glusterfsPath ? fields.glusterfsPath.trim() : fields.glusterfsPath; - if (!path) { - ex = new Error(_("Please provide a GlusterFS volume name")); - ex.target = "#modify-glusterfs-path"; - ret.errors.push(ex); - ex = null; - } - - if (ret.errors.length < 1) { - ret.data = { - endpoints: endpoint, - path: path, - readOnly: !!fields.readOnly - }; - } - - return ret; - } - - return { - build: build, - validate: validate, - }; - } - ]) - - .factory("nfs" + VOLUME_FACTORY_SUFFIX, [ - "volumeData", - "KubeTranslate", - function (volumeData, translate) { - const _ = translate.gettext; - - function build(item) { - if (!item) - item = {}; - - var spec = item.spec || {}; - var nfs = spec.nfs || {}; - return { - server: nfs.server, - path: nfs.path, - readOnly: nfs.readOnly, - reclaimPolicies: { - "Recycle" : volumeData.reclaimPolicies["Recycle"], - "Retain" : volumeData.reclaimPolicies["Retain"], - }, - }; - } - - function validate (item, fields) { - var regex = /^[a-z0-9.:-]+$/i; - - var ex, server, path; - var ret = { - errors: [], - data: null, - }; - - server = fields.server ? fields.server.trim() : fields.server; - if (!server || !regex.test(server)) { - ex = new Error(_("Please provide a valid NFS server")); - ex.target = "#nfs-modify-server"; - ret.errors.push(ex); - ex = null; - } - - path = fields.path ? fields.path.trim() : fields.path; - if (!path || path.search("/") !== 0) { - ex = new Error(_("Please provide a valid path")); - ex.target = "#modify-path"; - ret.errors.push(ex); - ex = null; - } - - if (ret.errors.length < 1) { - ret.data = { - server: server, - path: path, - readOnly: !!fields.readOnly - }; - } - - return ret; - } - - return { - build: build, - validate: validate, - }; - } - ]) - - .factory("hostPath" + VOLUME_FACTORY_SUFFIX, [ - "volumeData", - "KubeTranslate", - function (volumeData, translate) { - const _ = translate.gettext; - - function build(item) { - if (!item) - item = {}; - - var spec = item.spec || {}; - var hp = spec.hostPath || {}; - return { - path: hp.path, - readOnly: hp.readOnly, - reclaimPolicies: { - "Recycle" : volumeData.reclaimPolicies["Recycle"], - "Retain" : volumeData.reclaimPolicies["Retain"], - }, - }; - } - - function validate (item, fields) { - var ex, path; - var ret = { - errors: [], - data: null, - }; - - path = fields.path ? fields.path.trim() : fields.path; - if (!path || path.search("/") !== 0) { - ex = new Error(_("Please provide a valid path")); - ex.target = "#modify-path"; - ret.errors.push(ex); - ex = null; - } - - if (ret.errors.length < 1) { - ret.data = { - path: path, - }; - } - - return ret; - } - - return { - build: build, - validate: validate, - }; - } - ]) - - .controller("VolumeDeleteCtrl", [ - "$scope", - "$modalInstance", - "dialogData", - "volumeData", - "kubeMethods", - "kubeLoader", - function($scope, $instance, dialogData, volumeData, methods, loader) { - angular.extend($scope, dialogData); - - loader.listen(function() { - if ($scope.pvc) - $scope.pods = volumeData.podsForClaim($scope.pvc); - }, $scope); - - $scope.performDelete = function performDelete() { - return methods.delete($scope.item); - }; - } - ]) - - .factory("iscsi" + VOLUME_FACTORY_SUFFIX, [ - "volumeData", - "KubeTranslate", - function (volumeData, translate) { - const _ = translate.gettext; - - function build(item) { - if (!item) - item = {}; - - var spec = item.spec || {}; - var source = spec.iscsi || {}; - return { - target: source.targetPortal, - fstype: source.fsType || "ext4", - iqn: source.iqn, - lun: source.lun || 0, - iface: source.iscsiInterface, - readOnly: source.readOnly, - ReadWriteOnce: true, - accessModes: { - "ReadWriteOnce": volumeData.accessModes["ReadWriteOnce"], - }, - reclaimPolicies: { - "Retain": volumeData.reclaimPolicies["Retain"], - }, - }; - } - - function validate (item, fields) { - var ex, lun, target, iqn, fs, iface; - var regex = /^[a-z0-9.:-]+$/i; - - var ret = { - errors: [], - data: null, - }; - - target = fields.target ? fields.target.trim() : fields.target; - if (!target || !regex.test(target)) { - ex = new Error(_("Please provide a valid target")); - ex.target = "#modify-iscsi-target"; - ret.errors.push(ex); - ex = null; - } - - iqn = fields.iqn ? fields.iqn.trim() : fields.iqn; - if (!iqn || !regex.test(iqn)) { - ex = new Error(_("Please provide a valid qualified name")); - ex.target = "#modify-iscsi-iqn"; - ret.errors.push(ex); - ex = null; - } - - lun = parseInt(fields.lun ? fields.lun.trim() : fields.lun, 10); - if (isNaN(lun)) { - ex = new Error(_("Please provide a valid logical unit number")); - ex.target = "#modify-iscsi-lun"; - ret.errors.push(ex); - ex = null; - } - - fs = fields.fstype ? fields.fstype.trim() : "ext4"; - if (!regex.test(fs)) { - ex = new Error(_("Please provide a valid filesystem type")); - ex.target = "#modify-fstype"; - ret.errors.push(ex); - ex = null; - } - - iface = fields.iface ? fields.iface.trim() : undefined; - if (iface && !regex.test(iface)) { - ex = new Error(_("Please provide a valid interface")); - ex.target = "#modify-iscsi-iface"; - ret.errors.push(ex); - ex = null; - } - - if (ret.errors.length < 1) { - ret.data = { - iqn: iqn, - lun: lun, - fsType: fs, - targetPortal: target, - readOnly: !!fields.readOnly - }; - if (iface) - ret.data["iscsiInterface"] = iface; - } - - return ret; - } - - return { - build: build, - validate: validate, - }; - } - ]) - - .controller("PVModifyCtrl", [ - "$q", - "$scope", - "$injector", - "$modalInstance", - "dialogData", - "volumeData", - "defaultVolumeFields", - "kubeMethods", - "KubeTranslate", - function($q, $scope, $injector, $instance, dialogData, volumeData, - defaultVolumeFields, methods, translate) { - const _ = translate.gettext; - var volumeFields, valName; - - angular.extend($scope, dialogData); - - $scope.types = [ - { - name: _("NFS"), - type: "nfs", - }, - { - name: _("Host Path"), - type: "hostPath", - }, - { - name: _("ISCSI"), - type: "iscsi", - }, - { - name: _("GlusterFS"), - type: "glusterfs", - }, - ]; - - function selectType(type) { - $scope.current_type = type; - valName = $scope.current_type + VOLUME_FACTORY_SUFFIX; - $scope.fields = defaultVolumeFields.build($scope.item || $scope.pvc); - if ($injector.has(valName)) { - volumeFields = $injector.get(valName, "PVModifyCtrl"); - angular.extend($scope.fields, volumeFields.build($scope.item || $scope.pvc)); - } else { - $scope.$applyAsync(function () { - $scope.$dismiss(); - }); - } - } - - if ($scope.item) { - $scope.current_type = volumeData.getVolumeType($scope.item.spec); - selectType(volumeData.getVolumeType($scope.item.spec)); - } else { - $scope.selected = $scope.types[0]; - selectType($scope.selected.type); - } - - function validate() { - var defer = $q.defer(); - var resp, main_resp; - var errors = []; - - if (!$scope.item) { - valName = $scope.current_type + VOLUME_FACTORY_SUFFIX; - if ($injector.has(valName)) - volumeFields = $injector.get(valName, "PVModifyCtrl"); - else - errors.push(new Error(_("Sorry, I don't know how to modify this volume"))); - } - - if (volumeFields) { - resp = volumeFields.validate($scope.item, $scope.fields); - errors = resp.errors; - } - - main_resp = defaultVolumeFields.validate($scope.item, $scope.fields); - errors = errors.concat(main_resp.errors); - - if (errors.length > 0) { - defer.reject(errors); - } else { - main_resp.data.spec[$scope.current_type] = resp ? resp.data : null; - defer.resolve(main_resp.data); - } - - return defer.promise; - } - - function updatePVC() { - /* - * HACK: https://github.com/kubernetes/kubernetes/issues/21498 - * - * Until the API gets a way to manually - * trigger the process that matches a volume with a claim - * we change something else on the claim to try to kick things - * off sooner. Otherwise in the worse case - * the user will need to wait for around 10 mins. - */ - if ($scope.pvc) { - return methods.patch($scope.pvc, { - "metadata" : { - "annotations" : { - "claimTrigger": "on" - } - } - }) - .then(function () { - methods.patch($scope.pvc, { - "metadata" : { - "annotations" : { - "claimTrigger": null - } - } - }); - }); - } - } - - $scope.select = function(type) { - $scope.selected = type; - selectType(type.type); - }; - - $scope.setField = function(name, value) { - $scope.fields[name] = value; - }; - - $scope.hasField = function(name) { - return $scope.fields.hasOwnProperty(name); - }; - - $scope.performModify = function performModify() { - return validate().then(function(data) { - var res; - if (!$scope.item) - res = methods.create(data, null); - else - res = methods.patch($scope.item, data); - return res.then(updatePVC); - }); - }; - } - ]) - - .filter("formatReadOnly", [ - "KubeTranslate", - function(translate) { - return function(readOnly) { - if (readOnly) - return translate.gettext("Yes"); - else - return translate.gettext("No"); - }; - } - ]) - - .filter("formatPartitionNumber", [ - function() { - return function(partition) { - if (!partition) - return 0; - else - return partition; - }; - } - ]) - - .filter("formatVolumeType", [ - 'volumeData', - function(volumeData) { - return function(volume) { - return volumeData.getVolumeLabel(volume || {}); - }; - } - ]) - - .filter("reclaimLabel", [ - 'volumeData', - function(volumeData) { - return function(policy) { - var label = volumeData.reclaimPolicies[policy || ""]; - return label || policy; - }; - } - ]) - - .filter("accessModeLabel", [ - 'volumeData', - function(volumeData) { - return function(mode) { - var label = volumeData.accessModes[mode || ""]; - return label || mode; - }; - } - ]); -}()); diff --git a/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/client.go b/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/client.go deleted file mode 100644 index 9f80b5d5b..000000000 --- a/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/client.go +++ /dev/null @@ -1,433 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -package helpers - -import ( - "bytes" - "crypto/tls" - "crypto/x509" - "encoding/base64" - "encoding/json" - "errors" - "fmt" - "io/ioutil" - "log" - "net/http" - "os" - "strconv" - "strings" -) - -const CA_PATH = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt" - -type AuthError struct { - msg string -} - -func (v *AuthError) Error() string { - return v.msg -} - -func newAuthError(msg string) error { - return &AuthError{msg} -} - -// helpers -func namedArrayObject(key string, name string, m map[string]interface{}) []map[string]interface{} { - nm := make(map[string]interface{}) - nm[key] = m - nm["name"] = name - s := make([]map[string]interface{}, 1) - s[0] = nm - return s -} - -// Struct for decoding json -type userInfo struct { - FullName string `json:"fullName"` - MetaData struct { - Name string `json:"name"` - } `json:"metadata"` -} - -type apiVersions struct { - Versions []string `json:"versions"` -} - -// Simple client -type Client struct { - host string - version string - - caData string - insecure bool - requireOpenshift bool - isOpenshift bool - - userAPI string - client *http.Client - creds *Credentials -} - -func doRequest(client *http.Client, method string, path string, auth string, body []byte) (*http.Response, error) { - var req *http.Request - var err error - if body != nil { - req, err = http.NewRequest(method, path, bytes.NewReader(body)) - } else { - req, err = http.NewRequest(method, path, nil) - } - - if err != nil { - return nil, err - } - - if auth != "" { - req.Header.Add("Authorization", auth) - } - return client.Do(req) -} - -func (self *Client) fetchVersion(authHeader string) error { - path := fmt.Sprintf("%s/api", self.host) - resp, err := doRequest(self.client, "GET", path, authHeader, nil) - - // Treat connection errors as internal errors and invalid - // responses as auth errors - if err != nil { - return errors.New(fmt.Sprintf("Couldn't connect to the api: %s", err)) - } - - defer resp.Body.Close() - - if resp.StatusCode != 200 { - return newAuthError(fmt.Sprintf("Couldn't get api version: %s", resp.Status)) - } - - data := apiVersions{} - deErr := json.NewDecoder(resp.Body).Decode(&data) - if deErr != nil { - return newAuthError(fmt.Sprintf("Couldn't get api version: %s", deErr)) - } - - if len(data.Versions) < 1 { - return newAuthError(fmt.Sprintf("Couldn't get api version: invalid data")) - } - - self.version = data.Versions[0] - return nil -} - -func (self *Client) apiStatus(resource string, auth string) (int, error) { - path := fmt.Sprintf("%s/api/%s/%s", self.host, self.version, resource) - resp, rErr := doRequest(self.client, "GET", path, auth, nil) - if rErr != nil { - return 0, errors.New(fmt.Sprintf("Couldn't connect to api: %s", rErr)) - } - - defer resp.Body.Close() - return resp.StatusCode, nil -} - -func (self *Client) confirmBearerAuth(creds *Credentials) error { - // There are no bugs we have to work around here - // so just make sure we get a 200 or 403 to - // a namespace call - - status, e := self.apiStatus("namespaces", creds.GetHeader()) - if e == nil && status != 403 && status != 200 { - newAuthError(fmt.Sprintf("Couldn't verify bearer token with api: %s", status)) - } - - return e -} - -func (self *Client) confirmBasicAuth(creds *Credentials) error { - // Issue a request to the the /api API endpoint without any - // auth data. - // If we get 401 in response then we know our creds were good and we can log the user in. - // If we get a 200 or a 403 then we don't know if are creds were correct and we need to - // make more calls to figure it out. - // Any other code is treated as an error. - var e error - var status int - status, e = self.apiStatus("", "") - success := status == 401 - - if status == 200 || status == 403 { - // Either /api is open or the current user, possibly (system:anonymous) - // doesn't have permissions on it - // Send a request to the /api/$version/namespaces endpoint with a - // Authorization header that is guarenteed to be invalid. - // This should return a 200 if the whole api is open or a 401 if the - // api is protected. - status, e = self.apiStatus("namespaces", "Basic Og==") - if e != nil { - return e - } - - // Some versions of kubernetes return 403 instead of 401 - // when presented with bad basic auth data. In those cases - // we need to refuse authentication, as we have no way - // know if the credentials we have are in fact valid. - // https://github.com/kubernetes/kubernetes/pull/41775 - if status == 403 { - e = errors.New("This version of kubernetes is not supported. Turn off anonymous auth or upgrade.") - } else if status == 200 { - success = true - } else if status == 401 { - if creds.GetHeader() != "" { - success = true - } else { - status = 403 - } - } - } - - if !success && e == nil { - e = newAuthError(fmt.Sprintf("Couldn't verify authentication with api: %s", status)) - } - - return e -} - -func (self *Client) confirmCreds(creds *Credentials) error { - // Do this explictly so that we know we have a valid response - // Kubernetes doesn't provide any way for a caller - // to find out who it is, so we need to confirm the creds - // we got some other way. - err := self.fetchVersion(creds.GetHeader()) - if err != nil { - return err - } - - // If we are here we got a version for the api from the /api endpoint, - // using the credentials the user gave us. - // This happens when either - // a) /api is protected and the credentials are correct - // or - // b) /api is open in which case we have no idea if our creds were correct - // Confirming them is different for Basic or Bearer auth - var e error - if creds.UserName != "" { - e = self.confirmBasicAuth(creds) - } else { - creds.UserName = "Unknown" - e = self.confirmBearerAuth(creds) - } - - creds.DisplayName = creds.UserName - return e -} - -func (self *Client) fetchUserData(creds *Credentials) error { - resp, err := self.DoRequest("GET", self.userAPI, "users/~", creds, nil) - if err != nil { - return err - } - - defer resp.Body.Close() - - // 404 or 403 are both responses we can - // get when the oapi/users endpoint doesn't exists - notFound := resp.StatusCode == 404 || resp.StatusCode == 403 - if notFound && self.requireOpenshift { - return errors.New("Couldn't connect: Incompatible API") - - // This might be kubernetes, it doesn't have a way to - // get user data, if we have a username try to - // see if we can connect to it anyways - } else if notFound { - return self.confirmCreds(creds) - } else if resp.StatusCode != 200 { - return newAuthError(fmt.Sprintf("Couldn't get user data: %s", resp.Status)) - } - - self.isOpenshift = true - data := userInfo{} - deErr := json.NewDecoder(resp.Body).Decode(&data) - if deErr != nil { - return newAuthError(fmt.Sprintf("Couldn't get user json data: %s", deErr)) - } - - creds.UserName = data.MetaData.Name - if creds.UserName != "" { - creds.DisplayName = data.FullName - if creds.DisplayName == "" { - creds.DisplayName = creds.UserName - } - } else { - return newAuthError(fmt.Sprintf("Openshift user data wasn't valid: %v", data)) - } - return nil -} - -func (self *Client) DoRequest(method string, api string, resource string, - creds *Credentials, body []byte) (*http.Response, error) { - if self.host == "" { - return nil, errors.New("No kubernetes available") - } - - authHeader := "" - if creds != nil { - authHeader = creds.GetHeader() - } - - if self.version == "" { - err := self.fetchVersion(authHeader) - if err != nil { - return nil, err - } - } - - path := fmt.Sprintf("%s/%s/%s/%s", self.host, api, self.version, resource) - resp, rErr := doRequest(self.client, method, path, authHeader, body) - if rErr != nil { - return nil, errors.New(fmt.Sprintf("Couldn't connect: %s", rErr)) - } - return resp, nil -} - -func (self *Client) Login(authLine string) (map[string]interface{}, error) { - parts := strings.SplitN(authLine, " ", 2) - if len(parts) == 0 { - return nil, newAuthError("Invalid Authorization line") - } - authData := "" - authType := parts[0] - if len(parts) == 2 { - authData = parts[1] - } - - creds, err := NewCredentials(authType, authData) - if err == nil { - err = self.fetchUserData(creds) - } - - if err != nil { - if creds != nil && creds.authType == "negotiate" { - return nil, newAuthError(fmt.Sprintf("Negotiate failed: %s", err)) - } - return nil, err - } - - // Login successfull, save creds - self.creds = creds - user_data := creds.GetApiUserMap() - cluster := make(map[string]interface{}) - cluster["server"] = self.host - if self.caData != "" { - cluster["certificate-authority-data"] = self.caData - } - - cluster["insecure-skip-tls-verify"] = self.insecure - clusters := namedArrayObject("cluster", "container-cluster", cluster) - - context := make(map[string]interface{}) - context["cluster"] = "container-cluster" - context["user"] = user_data["name"] - contexts := namedArrayObject("context", "container-context", context) - - users := make([]map[string]interface{}, 1) - users[0] = user_data - - login_data := make(map[string]interface{}) - login_data["apiVersion"] = self.version - login_data["displayName"] = creds.DisplayName - login_data["current-context"] = "container-context" - login_data["clusters"] = clusters - login_data["contexts"] = contexts - login_data["users"] = users - - return login_data, nil -} - -func (self *Client) CleanUp() error { - if self.creds != nil && self.isOpenshift { - token := self.creds.GetToken() - if token != "" { - path := fmt.Sprintf("oauthaccesstokens/%s", token) - resp, err := self.DoRequest("DELETE", self.userAPI, path, self.creds, nil) - if err != nil { - return err - } - - if resp.StatusCode != 200 { - log.Println(fmt.Sprintf("Invalid token cleanup response: %d", resp.StatusCode)) - } - - defer resp.Body.Close() - } - } - return nil -} - -func NewClient() *Client { - var caData []byte = nil - var pool *x509.CertPool - - ac := new(Client) - ac.insecure = false - ac.host = os.Getenv("KUBERNETES_SERVICE_HOST") - if ac.host != "" { - // assume we are always on https - ac.host = fmt.Sprintf("https://%s", ac.host) - port := os.Getenv("KUBERNETES_SERVICE_PORT") - if port != "" { - ac.host = fmt.Sprintf("%s:%s", ac.host, port) - } - } - - ac.userAPI = os.Getenv("KUBERNETES_USER_API") - if ac.userAPI == "" { - ac.userAPI = "oapi" - } - - ac.requireOpenshift, _ = strconv.ParseBool(os.Getenv("REGISTRY_ONLY")) - - ac.insecure, _ = strconv.ParseBool(os.Getenv("KUBERNETES_INSECURE")) - if !ac.insecure { - data := os.Getenv("KUBERNETES_CA_DATA") - if data != "" { - caData = []byte(data) - } - - if caData == nil { - var err error - caData, err = ioutil.ReadFile(CA_PATH) - if err != nil { - log.Println(fmt.Sprintf("Couldn't load CA data: %s", err)) - } - } - - if caData != nil { - pool = x509.NewCertPool() - pool.AppendCertsFromPEM(caData) - ac.caData = base64.StdEncoding.EncodeToString(caData) - } - } - - tr := &http.Transport{ - TLSClientConfig: &tls.Config{RootCAs: pool, InsecureSkipVerify: ac.insecure}, - } - ac.client = &http.Client{Transport: tr} - - return ac -} diff --git a/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/creds.go b/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/creds.go deleted file mode 100644 index 5a5497580..000000000 --- a/pkg/kubernetes/standalone/src/cockpit-kube-auth/helpers/creds.go +++ /dev/null @@ -1,102 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -package helpers - -import ( - "encoding/base64" - "errors" - "fmt" - "io/ioutil" - "strings" -) - -type Credentials struct { - UserName string - DisplayName string - - password string - bearerToken string - - authHeader string - authType string -} - -func (self *Credentials) GetHeader() string { - return self.authHeader -} - -func (self *Credentials) GetToken() string { - return self.bearerToken -} - -func (self *Credentials) GetApiUserMap() map[string]interface{} { - m := make(map[string]interface{}) - name := self.UserName - if name == "" { - name = "cockpit-container-user" - } - - user := make(map[string]string) - if self.password != "" { - user["password"] = self.password - user["username"] = self.UserName - } else { - user["token"] = self.bearerToken - } - - m["name"] = self.UserName - m["user"] = user - - return m -} - -func NewCredentials(authType string, authData string) (*Credentials, error) { - cred := new(Credentials) - cred.authType = strings.ToLower(authType) - if cred.authType == "basic" { - raw, err := base64.StdEncoding.DecodeString(authData) - if err != nil { - return nil, errors.New(fmt.Sprintf("Couldn't decode basic header: %s", err)) - } - parts := strings.SplitN(string(raw), ":", 2) - cred.UserName = parts[0] - if len(parts) > 1 { - cred.password = parts[1] - } - cred.authHeader = fmt.Sprintf("Basic %s", authData) - } else if cred.authType == "bearer" { - cred.bearerToken = authData - cred.authHeader = fmt.Sprintf("Bearer %s", cred.bearerToken) - - } else if cred.authType == "negotiate" { - cred.UserName = "Unauthenticated" - } else { - return nil, errors.New(fmt.Sprintf("Unsuported authentication type %s", authType)) - } - return cred, nil -} - -func NewCredentialsForSystem() (*Credentials, error) { - token, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token") - if err != nil { - return nil, err - } - return NewCredentials("bearer", string(token)) -} diff --git a/pkg/kubernetes/standalone/src/cockpit-kube-auth/main.go b/pkg/kubernetes/standalone/src/cockpit-kube-auth/main.go deleted file mode 100644 index a2a214eec..000000000 --- a/pkg/kubernetes/standalone/src/cockpit-kube-auth/main.go +++ /dev/null @@ -1,232 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -package main - -import ( - "cockpit-kube-auth/helpers" - "encoding/json" - "errors" - "fmt" - "log" - "os" - "strconv" - "syscall" - "time" -) - -type ChallengeResponse struct { - Cookie string `json:"cookie"` - Response string `json:"response"` - Command string `json:"command"` -} - -func readSize(fd int) (int, error) { - single := make([]byte, 1) - sep := byte('\n') - var size int64 = 0 - seen := 0 - - for true { - _, err := syscall.Read(fd, single) - if err != nil { - return -1, err - } - - if single[0] == sep { - break - } - - i, e := strconv.ParseInt(string(single), 10, 64) - if e != nil { - return -1, errors.New("Invalid frame: invalid size") - } - - size = size * 10 - size = size + i - seen++ - - if seen > 7 { - return -1, errors.New("Invalid frame: size too long") - } - } - - return int(size), nil -} - -func readFrame(fd int) ([]byte, error) { - size, sizeErr := readSize(fd) - if sizeErr != nil { - return nil, sizeErr - } - data := make([]byte, 0) - - for size > 0 { - buffer := make([]byte, size) - i, err := syscall.Read(fd, buffer) - - if err != nil { - return nil, err - } - - if i == 0 { - break - } - - size = size - i - data = append(data, buffer[:i]...) - } - - if size > 0 { - return nil, errors.New(fmt.Sprintf("Invalid frame: Missing %d bytes", size)) - } - - return data, nil -} - -func getCockpitControlMsg(iface interface{}) error { - buf, err := readFrame(syscall.Stdin) - if err == nil { - err = json.Unmarshal(buf, iface) - } - return err -} - -func sendCockpitControlMsg(data interface{}) error { - response, respErr := json.Marshal(data) - if respErr != nil { - return respErr - } - - _, err := syscall.Write(syscall.Stdout, []byte(fmt.Sprintf("%d\n\n", len(response)+1))) - if err == nil { - _, err = syscall.Write(syscall.Stdout, response) - } - - return err -} - -func sendAuthorization(login_data map[string]interface{}) error { - data := make(map[string]interface{}) - data["command"] = "authorize" - data["challenge"] = "x-login-data" - data["cookie"] = "kube-auth-unused" - data["login-data"] = login_data - return sendCockpitControlMsg(data) -} - -func sendInitProblem(err error) error { - log.Println(err) - errorType := "internal-error" - if _, ok := err.(*helpers.AuthError); ok { - errorType = "authentication-failed" - } - - data := make(map[string]interface{}) - data["command"] = "init" - data["problem"] = errorType - data["message"] = fmt.Sprintf("%s", err) - return sendCockpitControlMsg(data) -} - -func challengeForAuthData() ([]byte, error) { - t := time.Now() - data := make(map[string]interface{}) - data["command"] = "authorize" - data["challenge"] = "*" - data["cookie"] = fmt.Sprintf("cookie%d%d", os.Getpid(), t.Unix()) - - err := sendCockpitControlMsg(data) - if err != nil { - return nil, nil - } - - r := ChallengeResponse{} - fetchErr := getCockpitControlMsg(&r) - if fetchErr != nil { - return nil, fetchErr - } - - if r.Command != "authorize" { - return nil, errors.New(fmt.Sprintf("Got invalid command %s", r.Command)) - } - - return []byte(r.Response), nil -} - -func runStub() int { - var wstatus syscall.WaitStatus - sysProcAttr := &syscall.SysProcAttr{ - Pdeathsig: syscall.SIGTERM, - } - - procAttr := &syscall.ProcAttr{ - Env: os.Environ(), - Files: []uintptr{os.Stdin.Fd(), os.Stdout.Fd(), os.Stderr.Fd()}, - Sys: sysProcAttr, - } - - pid, fork_err := syscall.ForkExec("/usr/libexec/cockpit-stub", nil, procAttr) - if fork_err != nil { - log.Fatal("Error forking process:", fork_err) - } - - _, wait_err := syscall.Wait4(pid, &wstatus, 0, nil) - for wait_err == syscall.EINTR { - _, wait_err = syscall.Wait4(pid, &wstatus, 0, nil) - } - if wait_err != nil { - log.Fatal("Error waiting on bridge pid:", wait_err) - } - - return wstatus.ExitStatus() -} - -func main() { - authData, err := challengeForAuthData() - if err != nil { - log.Fatal("Error reading authentication data ", err) - } - - client := helpers.NewClient() - response, loginErr := client.Login(string(authData)) - if loginErr != nil { - err = sendInitProblem(loginErr) - } else { - err = sendAuthorization(response) - } - - if err != nil { - log.Fatal("Error sending auth result", err) - } - - if err == nil && loginErr == nil { - if os.Getenv("XDG_RUNTIME_DIR") == "" { - os.Setenv("XDG_RUNTIME_DIR", "/tmp") - } - - status := runStub() - err = client.CleanUp() - if err != nil { - log.Fatal("Error deleting token", err) - } - - os.Exit(status) - } -} diff --git a/pkg/kubernetes/standalone/src/cockpit-kube-launch/main.go b/pkg/kubernetes/standalone/src/cockpit-kube-launch/main.go deleted file mode 100644 index 067886ad7..000000000 --- a/pkg/kubernetes/standalone/src/cockpit-kube-launch/main.go +++ /dev/null @@ -1,174 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -package main - -import ( - "cockpit-kube-auth/helpers" - "flag" - "fmt" - "log" - "os" - "os/exec" - "path" - "strconv" - "syscall" - "text/template" -) - -var OAUTH_CLIENT_ID = "cockpit-kube-client" -var CONFIG_FILE = "/etc/cockpit/cockpit.conf" -var CONFIG_TEMPLATE = "cockpit.conf.tmpl" - -var confDir = flag.String("config-dir", "/container", "Directory with cockpit-kube-launch config files") - -func writeConfigFile(confData map[string]interface{}) { - tmpl, tErr := template.New("cockpit.conf.tmpl").ParseFiles(path.Join(*confDir, CONFIG_TEMPLATE)) - if tErr != nil { - log.Fatalf("Invalid cockpit.conf template: %s", tErr) - } - - f, fErr := os.Create(CONFIG_FILE) - if fErr != nil { - log.Fatalf("Could't open file config file: %s", fErr) - } - - wErr := tmpl.Execute(f, confData) - if wErr != nil { - log.Fatalf("Could't write config file: %s", wErr) - } -} - -func linkFiles(src string, target string) { - // Not using symlink because os.Symlink doesn't let you force. - out, err := exec.Command("ln", "-sf", src, target).CombinedOutput() - if err != nil { - log.Fatalf("Could't link %s to %s: %v: %s", src, target, err, out) - } -} - -func setupCertificates() { - // Ensure path exits - dErr := os.MkdirAll("/etc/cockpit/ws-certs.d", os.ModeDir|0775) - if dErr != nil { - log.Fatalf("Couldn't create certificate directory %s", dErr) - } - - // Finding these certificate files or setting ownership on - // the certificate may fail so execute combine and ensure - // and the check results without - exec.Command("/usr/sbin/remotectl", "certificate", - "/var/run/secrets/ws-certs.d/tls.crt", - "/var/run/secrets/ws-certs.d/tls.key").CombinedOutput() - exec.Command("/usr/sbin/remotectl", "certificate", "--ensure").CombinedOutput() - out, rErr := exec.Command("/usr/sbin/remotectl", "certificate").CombinedOutput() - if rErr != nil { - log.Fatalf("Failed to generate certificates %s %s", rErr, out) - } -} - -func haveOpenShiftEndpoint() (bool, error) { - var isOpenShift bool = false - - creds, err := helpers.NewCredentialsForSystem() - if err != nil { - return isOpenShift, err - } - - client := helpers.NewClient() - resp, e := client.DoRequest("GET", "oapi", "", creds, nil) - if e != nil { - return isOpenShift, e - } - - defer resp.Body.Close() - if resp.StatusCode == 200 { - isOpenShift = true - } - - return isOpenShift, nil -} - -func main() { - flag.Parse() - - var isOpenShift bool = false - args := []string{ - "/usr/libexec/cockpit-ws", - } - - insecure, _ := strconv.ParseBool(os.Getenv("COCKPIT_KUBE_INSECURE")) - if insecure { - args = append(args, "--no-tls") - } - - setupCertificates() - - name := "kubernetes" - isRegistry, _ := strconv.ParseBool(os.Getenv("REGISTRY_ONLY")) - - oauth_url := os.Getenv("OPENSHIFT_OAUTH_PROVIDER_URL") - if oauth_url != "" { - isOpenShift = true - client_id := os.Getenv("OPENSHIFT_OAUTH_CLIENT_ID") - if client_id == "" { - client_id = OAUTH_CLIENT_ID - } - oauth_url = fmt.Sprintf("%s/oauth/authorize?client_id=%s&response_type=token", - oauth_url, client_id) - } else { - oauth_url = os.Getenv("OAUTH_PROVIDER_URL") - var osErr error = nil - isOpenShift, osErr = haveOpenShiftEndpoint() - if osErr != nil { - log.Printf("Error checking for openshift endpoint %s", osErr) - } - } - - if isRegistry { - name = "registry" - } else if isOpenShift { - name = "openshift" - } - - confData := make(map[string]interface{}) - confData["login_command"] = "/usr/libexec/cockpit-kube-auth" - confData["oauth_url"] = oauth_url - confData["is_openshift"] = isOpenShift - confData["is_registry"] = isRegistry - confData["origins"] = os.Getenv("COCKPIT_KUBE_URL"); - writeConfigFile(confData) - - override := path.Join(*confDir, fmt.Sprintf("%s-override.json", name)) - brand := path.Join(*confDir, fmt.Sprintf("%s-brand", name)) - linkFiles(override, "/usr/share/cockpit/shell/override.json") - linkFiles(brand, "/container/os-release") - - if isRegistry { - registry_override := path.Join(*confDir, "registry-dashboard-override.json") - linkFiles(registry_override, "/usr/share/cockpit/kubernetes/override.json") - linkFiles("/usr/share/cockpit/kubernetes/registry.html.gz", - "/usr/share/cockpit/kubernetes/index.html.gz") - } else { - linkFiles("/usr/share/cockpit/kubernetes/original-index.gz", - "/usr/share/cockpit/kubernetes/index.html.gz") - } - - syscall.Exec(args[0], args, os.Environ()) -} diff --git a/pkg/kubernetes/styles/app.less b/pkg/kubernetes/styles/app.less deleted file mode 100644 index 65e67abdf..000000000 --- a/pkg/kubernetes/styles/app.less +++ /dev/null @@ -1,216 +0,0 @@ -#graphs { - display: block; -} - -#graphs svg { - font-size: 10px; -} - -#graphs ul { - padding-top: 15px; - margin-right: 10px; -} - -.axis path, .axis line { - fill: none; - stroke: #000; - shape-rendering: crispEdges; -} - -.axis .domain, -.axis .tick line { - stroke: lightgrey; - opacity: 0.5; -} - -.tick text { - fill: #545454; - font-size: 12px; -} - -path.line { - stroke: steelblue; - fill: none; - stroke-width: 2; -} - -path.line.highlight { - stroke-width: 4; -} - -/* Page global stuff */ - -.container-fluid { - margin-top: 0px; - padding-left: 0px; -} - -.container-more { - margin-top: 10px; -} - -/* Dashboard */ - -#content { - margin-left: 110px; - margin-right: 0px; - min-height: 100%; -} - -#content > .row { - margin-right: 0px; -} - -#content > *:last-child { - padding-bottom: 20px; -} - -/* When panel is editable, then buttons are visible */ -.dashboard-list td button { - display: none; -} - -.dashboard-list.editable td button { - display: block; -} - -.dashboard-list.editable td.status > span { - display: none; -} - -.dashboard-list.editable tr:hover td { - background-color: #FFF; - cursor: auto; -} - -.dashboard-list td.status { - padding: 4px 10px 4px !important; - text-align: right; - white-space: nowrap; - vertical-align: middle; - width: 1%; - min-width: 50px; -} - -.dashboard-list span.pficon, -.dashboard-list span.fa { - font-size: 18px; - color: black; - display: inline-block; -} - -.dashboard-list span.spinner { - display: inline-block; -} - -.dashboard-list span.fa-failed { - color: #af151a; -} - - -/* App deploy dialog */ - -#deploy-app-deploying > span { - margin-left: 7px; -} - -#deploy-app-manifest-file { - opacity: 0.0001; - height: 1px; -} - -#deploy-app-manifest-file-button { - width: 100%; - padding-right: 25px; -} - -.deploy-app-type-text { - font-style: normal; - text-align: left; -} - -.manifest_file { - font-style: normal; - text-align: left; - font-size: 11px; -} - -.manifest_file_default { - text-align: left; - font-style: italic; - font-size: 11px; -} - -.combobox_option { - width: 100%; -} - -.deploy-dialog-aids { - margin-bottom: 0px; -} - -/* Replicas dialog */ - -input.adjust-replica { - width: 70px; -} - -#adjust-dialog .modal-dialog { - width: 400px; -} - -#deploy-app-type-field > .bootstrap-select { - margin-bottom: 3px; -} - -.app-name { - color: #333333; - margin-top: 10px; - text-align: left; -} - -/* Used to hide angular elements until they are ready */ -[ng\:cloak], [ng-cloak], [data-ng-cloak], [x-ng-cloak], .ng-cloak, .x-ng-cloak { - display: none !important; -} - -input.adjust-replica { - width: 200px; -} - -.console-ct pre { - background-color: #fcfcfc; - border: 1px solid #cccccc; -} - -pre.dialog { - height: 200px; - width: 500px; - border: 1px solid #cccccc; -} - -.action-menu { - display: block; - float: right; -} - -/* Input combo replacement */ - -.input-combo .input-group-btn { - position: static; -} - -.input-combo .dropdown-menu { - left: 0; - right: 0; -} - -/* overide since registry-image-widget sets - the last column to be aligned right - but we don't want that when we are - using colspan - */ -table.listing-ct > thead td[colspan]:last-child, -table.listing-ct > thead th[colspan]:last-child { - text-align: left; -} diff --git a/pkg/kubernetes/styles/containers.less b/pkg/kubernetes/styles/containers.less deleted file mode 100644 index 8ea87c742..000000000 --- a/pkg/kubernetes/styles/containers.less +++ /dev/null @@ -1,19 +0,0 @@ - -.containers-listing { - width: 100%; -} - -.containers-listing i.fa-cube, -.content-filter i.fa-cube { - position: relative; - font-size: 22px; -} - -.containers-listing .console-ct { - min-height: 310px; -} - -kubernetes-container-terminal .terminal-actions { - position: relative; - z-index: auto; -} diff --git a/pkg/kubernetes/styles/dashboard.less b/pkg/kubernetes/styles/dashboard.less deleted file mode 100644 index dbfd95f68..000000000 --- a/pkg/kubernetes/styles/dashboard.less +++ /dev/null @@ -1,108 +0,0 @@ -.container-cards-pf { - display: flex; - margin-top: 10px; -} - -.card-pf { - flex-grow: 1; - margin: 10px; - display: flex; - flex-direction: column; - flex-basis: 25%; -} - -.card-pf-aggregate-status .card-pf-body { - margin-bottom: 0px; -} - -.card-pf-wide { - flex-basis: ~"calc(75% + 20px)"; -} - -.card-pf-double { - flex-basis: ~"calc(66% - 76px)"; -} - -.dashboard-cards { - width: 100%; - max-width: 1024px; - padding-right: 7px; -} - -.card-pf-aggregate-status-notification .spinner { - display: inline-block; - margin-right: 7px; -} - -.card-pf-aggregate-status-text { - font-size: 13px; - vertical-align: 3px; -} - -.card-pf-heading { - margin-bottom: 0px; - - button { - margin: 15px 0px; - } - - i { - font-size: 24px; - line-height: 16px; - vertical-align: top; - padding-right: 5px; - } -} - -.card-pf-footer { - min-height: 5em; -} - -.card-pf-body { - margin-top: 10px; - margin-bottom: auto; -} - -.card-pf-body.blank-slate-pf { - background: transparent; - padding-top: 20px; -} - -.card-pf-body table.listing-ct { - margin-top: 0px; - width: 100%; -} - -.card-pf-body table.listing-ct thead th { - border-top: none; -} - -.card-pf-body table.listing-ct tbody:last-child { - border-bottom: none; -} - -.card-pf-body table.listing-ct tbody:last-child tr:last-child { - border-bottom: none; -} - -.pvc-notice { - border-top: 1px solid #d1d1d1; - padding-top: 5px; -} - -.pvc-notice .pficon { - font-size: 18px; - margin-right: 5px; - color: #72767b; -} - -code { - display: block; - white-space: pre; - font-size: 13px; - margin-bottom: 1em; -} - -.form-table-ct label span[translate] { - vertical-align: top; -} diff --git a/pkg/kubernetes/styles/details.less b/pkg/kubernetes/styles/details.less deleted file mode 100644 index 6b7fe1af9..000000000 --- a/pkg/kubernetes/styles/details.less +++ /dev/null @@ -1,75 +0,0 @@ -.details-listing { - min-width: 70% !important; -} - -.details-listing i.pficon-service { - font-size: 30px; - line-height: 20px; - position: relative; - padding-right: 5px; - left: -5px; -} - -.details-listing i.pficon-route { - position: relative; - font-size: 25px; - line-height: 20px; - left: -2px; - padding-right: 8px; -} - -.details-listing i.fa-server { - position: relative; - top: 3px; -} - -.content-filter i.pficon-service { - margin-right: 5px; -} - -.details-listing i.pficon-replicator { - position: relative; - font-size: 28px; - top: -6px; -} - -.content-filter i.pficon-replicator { - margin-right: 5px; -} - -.content-filter i.pficon-container-node { - top: 3px; - margin-right: 5px; -} - -.details-listing i.fa-cubes { - -} - -.details-listing i.fa-gear { - position: relative; - font-size: 25px; - top: -3px; -} - -.details-listing dl dd dl.inline-dl { - padding-left: 15px; -} - -.details-listing dl dd dl.inline-dl dt { - text-align: left; -} - -.listing-ct-inline .console-ct > pre { - text-align: left; - margin: 0; -} - -.type-filter .btn, -.type-filter .dropdown-menu { - font-size: 13px; -} - -.type-filter .btn-group.open .dropdown-toggle { - box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.125) inset; -} diff --git a/pkg/kubernetes/styles/dropdown.less b/pkg/kubernetes/styles/dropdown.less deleted file mode 100644 index b99416ad1..000000000 --- a/pkg/kubernetes/styles/dropdown.less +++ /dev/null @@ -1,12 +0,0 @@ -.dropdown-menu { - li a:before { - font-family: FontAwesome; - content: "\f00c"; - margin-right: 5px; - visibility: hidden; - } - - li.checked a:before { - visibility: visible; - } -} diff --git a/pkg/kubernetes/styles/filter.less b/pkg/kubernetes/styles/filter.less deleted file mode 100644 index 23d8a8568..000000000 --- a/pkg/kubernetes/styles/filter.less +++ /dev/null @@ -1,89 +0,0 @@ -@filter-height: 50px; - -.content-filter { - background-color: @sidebar-pf-bg; - padding: 10px 16px 10px 20px; - border-bottom: 1px @sidebar-pf-border-color solid; - position: fixed; - top: 0px; - right: 0px; - z-index: 1; - height: @filter-height; - - h3 { - display: inline; - font-size: 18px; - line-height: 28px; - } - - h3 i { - font-size: 24px; - position: relative; - padding-right: 3px; - } - - i.pficon-image { - top: 3px; - } - - i.fa { - margin-top: 2px; - font-size: 18px; - line-height: 28px; - } - - i.fa-folder { - font-size: 22px; - } - - a { - padding-left: 30px; - } -} - -@media (min-width: 700px) { - .content-filter { - a.hidden-xs { - display: inline !important; - } - } -} - -.content-filter + div { - padding-top: @filter-height; -} - -.namespace-filter .btn, -.namespace-filter .dropdown-menu { - font-size: 13px; -} - -.namespace-filter .btn-group.open .dropdown-toggle { - box-shadow: 0px 3px 5px rgba(0, 0, 0, 0.125) inset; -} - -.namespace-filter .namespace-meta { - color: @metadata-color; -} - -.filter-menu { - display: block; - - .caret { - height: 10px; - } -} - -.filter-menu > .btn + .dropdown-toggle { - padding: 3px 1px; - min-width: 0; - border-left: none; - height: 26px; -} - -.filter-menu > .btn:first-child { - border-right: none; - height: 26px; - font-size: 15px; -} - diff --git a/pkg/kubernetes/styles/images.less b/pkg/kubernetes/styles/images.less deleted file mode 100644 index 176f7b6e1..000000000 --- a/pkg/kubernetes/styles/images.less +++ /dev/null @@ -1,66 +0,0 @@ -@import (less) "../../../node_modules/registry-image-widgets/dist/image-widgets.css"; - -@tag-border: @link-color; - -table.images-listing { - max-width: 2000px; - min-width: 85%; - - tbody:hover { - background-color: #edf8ff; - } - - thead { - th { - border-top: none; - } - } - - tr.listing-ct-item { - - td.tag-label { - vertical-align: top; - background: linear-gradient(90deg, transparent 10px, @tag-border 10px, @tag-border 12px, transparent 12px); - } - - td.listing-ct-toggle:hover + td.tag-label { - background-color: #ededed - } - - border-top: none; - border-bottom: none; - } - - tbody.first { - tr.tag-item td { - padding-top: 20px; - } - } - - tbody.last { - tr.listing-ct-item.tag-item td.tag-label { - background-size: 100% 20px; - background-repeat: no-repeat; - } - } - - tr.imagestream-item { - border-top: 1px solid @gray-lighter; - - th, td { - border-bottom: 2px solid @tag-border; - font-size: 14px; - padding-bottom: 5px; - } - } - - tr.listing-ct-item tt { - color: @metadata-color; - } -} - -registry-imagestream-listing { - table.listing-ct { - margin-top: -15px; - } -} diff --git a/pkg/kubernetes/styles/main.less b/pkg/kubernetes/styles/main.less deleted file mode 100644 index 8c5685eba..000000000 --- a/pkg/kubernetes/styles/main.less +++ /dev/null @@ -1,28 +0,0 @@ -@import "variables.less"; -@import (less) "../../../node_modules/angular/angular-csp.css"; - -@import (less) "../../lib/page.css"; -@import "../../lib/listing.less"; -@import (less) "../../lib/console.css"; -@import (less) "../../lib/table.css"; - -/* Depends on number of items in the sidebar */ -@sidebar-height-lg: 630px; - -@import "app.less"; -@import (less) "../../../node_modules/kubernetes-container-terminal/dist/container-terminal.css"; -@import "containers.less"; -@import "details.less"; -@import (less) "../../../node_modules/kubernetes-topology-graph/dist/topology-graph.css"; -@import "topology.less"; -@import "revealable.less"; -@import "dashboard.less"; - -@import "sidebar.less"; -@import "filter.less"; -@import "dropdown.less"; -@import "tags.less"; -@import "images.less"; -@import "projects.less"; -@import "volumes.less"; -@import "nodes.less"; diff --git a/pkg/kubernetes/styles/nodes.less b/pkg/kubernetes/styles/nodes.less deleted file mode 100644 index 34dbfbb02..000000000 --- a/pkg/kubernetes/styles/nodes.less +++ /dev/null @@ -1,112 +0,0 @@ -.node-status { - padding-right: 3px; -} - -.node-alert { - margin-top: 20px; -} - -div.nodes-delete ul { - padding-top: 10px; -} - -div.nodes-delete ul li { - padding-bottom: 10px; -} - -.nodes-heatmap-card { - flex-basis: 66%; - - .card-pf-title { - margin-top: 10px; - } - - .node-heatmap { - height: 90px; - } - - ul.chart-legend { - margin-top: 30px; - } - - li.chart-legend-item { - float: left; - display: inline; - } - - li.chart-legend-item:first-of-type span.legend-pf-color-box{ - margin-left: 0px; - } - - li.chart-legend-item span.legend-pf-color-box { - margin-left: 5px; - } - - rect { - cursor: pointer; - } -} - -.nodes-os-card { - flex-basis: 33%; - - #os-counts-graph { - height: 150px; - } - - h2 { - text-align: center; - margin-bottom: 0; - } - - @media (min-width: 992px) { - div.row { - display: flex; - align-items: center; - } - } -} - -.chart-title { - text-anchor: middle; - dominant-baseline: middle; -} - -.chart-focused { - opacity: 1; - cursor: pointer; -} - -.chart-unfocused { - opacity: 0.3; -} - -ul.chart-legend { - list-style-type: none; - margin-top: 5px; - padding: 0; - overflow: auto; -} - -li.chart-legend-item { - cursor: pointer; -} - -li.chart-legend-item span.legend-pf-color-box { - width: 11px; - height: 11px; - margin-right: 5px; - display: inline-block; -} - -li.chart-legend-item span.legend-pf-text { - font-size: 11px; - font-weight: 400; - line-height: 11px; - margin-right: 5px; -} - -.nodes-container-cards svg { - min-width: 90px; - min-height: 90px; -} diff --git a/pkg/kubernetes/styles/projects.less b/pkg/kubernetes/styles/projects.less deleted file mode 100644 index dbc828f3c..000000000 --- a/pkg/kubernetes/styles/projects.less +++ /dev/null @@ -1,141 +0,0 @@ - -@tag-border: @link-color; - -table.project-body { - margin-top: 0px; - - thead.th { - border-top:0px; - font-size: 12px; - } - - tr { - display: table-row; - vertical-align: inherit; - border-color: inherit; - } - - tr.listing-ct-item { - border-top: 1px solid color("#eee"); - border-bottom: 1px solid color("#eee"); - cursor: pointer; - } -} - -.close-icon { - color: #000000; -} -.user-membership-body { - overflow-y: auto; - overflow-x: hidden; - max-height: 200px; - border-top: 1px solid #eee; - border-bottom: 1px solid #eee; - padding-top: 10px; - padding-bottom: 10px; - - h4 { - color: #888; - margin-top: 0px; - margin-bottom: 5px; - font-size: 14px; - } - - span { - display: block; - margin-left: 20px; - } -} - -.user-body { - border: 0px; - - table.listing-ct thead th { - border-bottom: 0px; - border-bottom: 1px solid color("#eee"); - } -} - -table.listing-ct > thead td { - padding-top: 0px; -} - -.listing-ct-head .pficon-project { - margin-bottom: 10px; -} - -span.project-description { - font-size: 13px; - font-weight: normal; -} - -p.project-description { - margin-top: 1em; -} - -a.input-icon { - position: absolute; - right: 18px; -} - -.project-panel { - padding-right: 25px; - padding-top: 5px; -} - -.project-panel-actions { - padding-right: 5px; - padding-top: 5px; -} - -table.projects-listing { - max-width: 2000px; - min-width: 85%; - - thead { - th { - border-top: 0px; - } - } - - tr { - display: table-row; - vertical-align: inherit; - border-color: inherit; - } - - .details-listing { - min-width: 70% !important; - } - - tr.listing-ct-item { - border-top: 1px solid color("#eee"); - border-bottom: 1px solid color("#eee"); - cursor: pointer; - } - - tr.inner-project-listing { - display: table-row; - } - - tbody.first { - tr.tag-item td { - padding-top: 20px; - } - } - - tbody.last { - tr.listing-ct-item.tag-item td:first-child { - background-size: 100% 20px; - background-repeat: no-repeat; - } - } - - tr.tag-item td { - padding-bottom: 0px; - } - - tr.listing-ct-item tt { - color: @metadata-color; - } -} diff --git a/pkg/kubernetes/styles/registry.less b/pkg/kubernetes/styles/registry.less deleted file mode 100644 index 006eb28af..000000000 --- a/pkg/kubernetes/styles/registry.less +++ /dev/null @@ -1,248 +0,0 @@ -@import "variables.less"; -@import (less) "../../../node_modules/angular/angular-csp.css"; - -@import (less) "../../lib/page.css"; -@import "../../lib/listing.less"; -@import (less) "../../lib/console.css"; -@import (less) "../../lib/table.css"; - -@icon-sidebar-width: 100px; - -@import "filter.less"; -@import "dropdown.less"; -@import "dashboard.less"; - -@import "images.less"; -@import "projects.less"; -@import "tags.less"; - -#content { - margin-right: 0px; - min-height: 100%; - padding-bottom: 20px; -} - -.listing-ct-body dl { - margin-bottom: 13px; -} - -/* Registry dashboard */ - -.card-pf-utilization .card-pf-title { - line-height: 1.1; -} - -.dashboard-storage { - img { - display: block; - margin: 20px auto 0px auto; - } -} - -.dashboard-images { - .card-pf-heading { - position: relative; - - .card-pf-title { - max-width: 80%; - } - } - - .card-pf-body { - min-height: 220px; - padding-bottom: 0px; - - div { - padding: 7px 10px 10px 10px; - cursor: pointer; - } - - div:hover { - background-color: @table-bg-hover; - } - - ul { - background: linear-gradient(90deg, transparent 20px, @tag-border 20px, @tag-border 22px, transparent 22px); - background-size: 100% 20px; - background-repeat: no-repeat; - padding: 3px 0px 0px 20px; - margin-bottom: 0px; - line-height: 30px; - - li { - background: linear-gradient(180deg, transparent 8px, @tag-border 8px, @tag-border 10px, transparent 10px); - background-repeat: no-repeat; - padding-left: 7px; - display: inline; - list-style: none; - } - - li:first-child { - padding-left: 15px; - } - - li.image-tag-truncated { - padding-left: 15px; - opacity: 0.5; - } - } - } - - .namespace-filter { - margin-top: -3px; - } - - .namespace-filter button { - margin-bottom: 0px; - } - - .all-images { - display: block; - float: right; - margin-bottom: 10px; - } - - .registry-imagestream-lock { - display: block; - float: right; - margin: 9px; - } - - .table > tbody > tr > td { - border-top: none; - font-weight: bold; - padding: 0px; - } - - .table a { - display: block; - color: inherit; - padding: 8px 15px; - } - - dt { - font-size: 13px; - } - - dt a { - text-decoration: none; - color: inherit; - } - - dd { - float: right; - margin-left: 20px; - } - -} - -.dashboard-commands { - p { - font-size: 13px; - font-weight: bold; - } -} - -.blank-slate-pf { - border: none; -} - -#content { - margin-left: unit(@icon-sidebar-width, px); -} - -.content-filter { - left: unit(@icon-sidebar-width - 10, px); -} - -.content-filter + div { - padding-left: 10px; - padding-right: 17px; -} - -/* A different sidebar */ -.icon-sidebar { - width: unit(@icon-sidebar-width, px); - - ul { - margin: 0; - padding: 0; - list-style: none; - width: unit(@icon-sidebar-width - 10, px); - height: 100%; - position: fixed; - background-color: @nav-pf-vertical-secondary-bg-color; - top: 0px; - z-index: 1; - - li { - border-bottom: 1px solid @nav-pf-vertical-border-color; - display: block; - font-size: 13px; - - a { - border-bottom: 0; - color: @nav-pf-vertical-secondary-color; - background-color: @nav-pf-vertical-secondary-bg-color; - padding: 15px 11px 15px 9px; - text-align: center; - display: block; - text-decoration: none; - position: relative; - - i { - display: inline; - font-size: 20px; - line-height: 20px; - color: @nav-pf-vertical-icon-color; - } - - i.pficon-image { - font-size: 24px; - line-height: 20px; - } - } - - a:hover { - color: @nav-pf-vertical-secondary-active-color; - background-color: @nav-pf-vertical-secondary-active-bg-color; - - i { - color: @nav-pf-vertical-active-icon-color; - } - } - } - - li.active { - a { - color: @nav-pf-vertical-secondary-active-color; - background-color: @nav-pf-vertical-secondary-active-bg-color; - - i { - color: @link-color; - } - } - - a:after { - content: ''; - width: 4px; - height: 100%; - left: 0; - top: 0; - display: block; - position: absolute; - background-color: @link-color; - } - } - } -} - -/* overide since registry-image-widget sets - the last column to be aligned right - but we don't want that when we are - using colspan - */ -table.listing-ct > thead td[colspan]:last-child, -table.listing-ct > thead th[colspan]:last-child { - text-align: left; -} diff --git a/pkg/kubernetes/styles/revealable.less b/pkg/kubernetes/styles/revealable.less deleted file mode 100644 index 8fd00f351..000000000 --- a/pkg/kubernetes/styles/revealable.less +++ /dev/null @@ -1,46 +0,0 @@ -.revealable { - white-space: nowrap !important; - text-overflow: ellipsis; - overflow: hidden !important; -} - -.revealable.clickable { - cursor: pointer; -} - -.revealed { - white-space: normal !important; - overflow: visible !important; - cursor: pointer; - overflow-wrap: break-word; -} - -.masked { - color: transparent; - position: relative; - text-ellipsis: none !important; - cursor: pointer; - max-width: 1; - display: inline-block; -} - -.masked:after { - content: "●●●●"; - position: absolute; - left: 0px; - font-weight: bold; - letter-spacing: 2px; - padding-left: 2px; - color: black; - cursor: pointer; - line-height: 1.5; - opacity: 0.5; -} - -.revealed .masked:after { - display: none; -} - -.revealed .masked { - color: black; -} diff --git a/pkg/kubernetes/styles/sidebar.less b/pkg/kubernetes/styles/sidebar.less deleted file mode 100644 index ed11e0dcc..000000000 --- a/pkg/kubernetes/styles/sidebar.less +++ /dev/null @@ -1,126 +0,0 @@ -/* - * Full large size sidebar. - */ - - -.nav-sidebar { - background: #393f44; - width: unit(@sidebar-width-xl, px); - height: 100%; - position: fixed; - top: 0px; - z-index: 1; - overflow-x: hidden; - overflow-y: auto; - - border-right: 1px solid #292e34; - border-bottom: none; - border-top: none; - border-left: none; - bottom: 0; - - a { - width: unit(@sidebar-width-xl, px) !important; - } - .list-group-item-value { - max-width: unit(@sidebar-width-xl - 60, px) !important; - padding-right: 10px !important; - } -} - -.nav-item-pf-header { - color: #fff; - font-size: 16px; - margin: 18px 20px 10px 20px; -} - -.nav-sidebar .list-group { - border: none; -} - -.nav-sidebar .list-group-item { - background: inherit; - border: none; -} - -.nav-sidebar .list-group-item.active { - background-color: #4d5258; -} -.nav-sidebar > .list-group > .list-group-item.active > a { - background-color: inherit; -} - -.nav-sidebar .list-group-item a { - display: block; - color: #d1d1d1; -} - -#content { - margin-left: unit(@sidebar-width-xl + 20, px); -} - -.content-filter { - left: unit(@sidebar-width-xl, px); -} - -/* - * Very small. Only icons - */ -@media (max-width: @screen-sm-min) { - .nav-sidebar { - .nav-item-pf-header { - display: none; - } - - width: unit(@sidebar-width-sm, px); - .list-group-item-value { - display: none !important; - } - a { - padding: 8px !important; - height: 40px !important; - width: unit(@sidebar-width-sm, px) !important; - } - } - - #content { - margin-left: unit(@sidebar-width-sm + 20, px); - } - - .content-filter { - left: unit(@sidebar-width-sm, px); - } -} - -/* - * Short window. Text next to icons. - */ -@media (min-width: @screen-sm-min) and (max-width: @screen-lg-min), (min-width: @screen-sm-min) and (max-height: @sidebar-height-lg) { - .nav-sidebar { - width: unit(@sidebar-width-md, px); - a { - padding: 7px 8px 5px 8px !important; - height: 40px !important; - width: unit(@sidebar-width-md, px) !important; - i { - float: none !important; - margin-right: 0px !important; - } - span { - display: inline !important; - font-size: 12px; - margin-left: 4px; - margin-top: 2px; - } - } - } - - #content { - margin-left: unit(@sidebar-width-md + 20, px); - } - - .content-filter { - left: unit(@sidebar-width-md, px); - } - -} diff --git a/pkg/kubernetes/styles/tags.less b/pkg/kubernetes/styles/tags.less deleted file mode 100644 index d47f42b66..000000000 --- a/pkg/kubernetes/styles/tags.less +++ /dev/null @@ -1,54 +0,0 @@ - -.image-tag { - border: 2px solid @tag-border; - border-radius: 7px; - padding: 3px 5px; - white-space: nowrap; - background-color: @listing-ct-hover; -} - -a.image-tag { - color: inherit; -} - -.image-tag-editor { - -moz-appearance: textfield; - -webkit-appearance: textfield; - background-color: white; - background-color: -moz-field; - border: 1px solid darkgray; - box-shadow: 1px 1px 1px 0 lightgray inset; - font: -moz-field; - font: -webkit-small-control; - padding: 4px; - font-size: 13px; - max-width: 500px; -} - -.image-tag-editor:focus { - border-color: #66afe9; - outline: 0; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); - box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6); -} - -.image-tag-editor .image-tag { - padding: 1px 5px; - margin: 2px 1px 2px 1px; - cursor: default; - display: inline-block; -} - -.image-tag a { - color: #999; - position: relative; - padding-left: 4px; - font-size: 12px; - top: 1px; -} - -.image-tag a:hover { - color: black; - text-decoration: none; -} - diff --git a/pkg/kubernetes/styles/topology.less b/pkg/kubernetes/styles/topology.less deleted file mode 100644 index c57ec30f4..000000000 --- a/pkg/kubernetes/styles/topology.less +++ /dev/null @@ -1,60 +0,0 @@ -kubernetes-topology-graph { - margin-right: 25%; - margin-top: 55px; - padding-bottom: 0px !important; - overflow: hidden; -} - -.kube-pane { - float: right; - width: 25%; - - .sidebar-pf-right { - right: 0px; - } -} - -.kube-pane .sidebar-pf { - position: fixed; - width: 25%; - height: 100%; - padding: 10px; - overflow: hidden; -} - -.kube-pane .dl-horizontal { -} - -.kube-pane .dl-horizontal dt { - text-align: left; - width: 90px; - overflow: hidden; - text-overflow: ellipsis; -} - -.kube-pane .dl-horizontal dd { - margin-left: 100px; - margin-right: 30px; - overflow: hidden; - text-overflow: ellipsis; -} - -.kube-pane .sidebar-help p { - margin-right: 30px; - margin-bottom: 30px; -} - -.kube-pane .sidebar-help h3 { - padding-top: 7px; - padding-bottom: 10px; -} - -kubernetes-topology-icon { - display: block; - float: left; - padding: 0 10px 5px 0; -} - -.topology-actions { - float: right; -} diff --git a/pkg/kubernetes/styles/variables.less b/pkg/kubernetes/styles/variables.less deleted file mode 100644 index f8d9bf9ce..000000000 --- a/pkg/kubernetes/styles/variables.less +++ /dev/null @@ -1,7 +0,0 @@ -@import "../../lib/variables.less"; - -@sidebar-width-sm: 40; -@sidebar-width-md: 145; -@sidebar-width-xl: 185; - -@command-bg-color: #eee; diff --git a/pkg/kubernetes/styles/volumes.less b/pkg/kubernetes/styles/volumes.less deleted file mode 100644 index de23402ae..000000000 --- a/pkg/kubernetes/styles/volumes.less +++ /dev/null @@ -1,19 +0,0 @@ -label.inline { - margin-right: 16px; -} - -div.modal-body ul.dialog-list-ct { - padding-top: 10px; -} - -div.modal-body ul.dialog-list-ct li { - padding-bottom: 10px; -} - -.pvc-listing button.btn-danger { - visibility: hidden; -} - -.pvc-listing tr.listing-ct-item:hover button.btn-danger { - visibility: visible; -} diff --git a/pkg/kubernetes/views/add-group-dialog.html b/pkg/kubernetes/views/add-group-dialog.html deleted file mode 100644 index 48a759481..000000000 --- a/pkg/kubernetes/views/add-group-dialog.html +++ /dev/null @@ -1,21 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/add-member-role-dialog.html b/pkg/kubernetes/views/add-member-role-dialog.html deleted file mode 100644 index a59aff2e4..000000000 --- a/pkg/kubernetes/views/add-member-role-dialog.html +++ /dev/null @@ -1,63 +0,0 @@ - -
- - - diff --git a/pkg/kubernetes/views/add-role-dialog.html b/pkg/kubernetes/views/add-role-dialog.html deleted file mode 100644 index 05bc3f97c..000000000 --- a/pkg/kubernetes/views/add-role-dialog.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/add-user-dialog.html b/pkg/kubernetes/views/add-user-dialog.html deleted file mode 100644 index 166840fec..000000000 --- a/pkg/kubernetes/views/add-user-dialog.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/auth-dialog.html b/pkg/kubernetes/views/auth-dialog.html deleted file mode 100644 index 27f32c736..000000000 --- a/pkg/kubernetes/views/auth-dialog.html +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - diff --git a/pkg/kubernetes/views/auth-form.html b/pkg/kubernetes/views/auth-form.html deleted file mode 100644 index 0a53d0b0f..000000000 --- a/pkg/kubernetes/views/auth-form.html +++ /dev/null @@ -1,132 +0,0 @@ - - - diff --git a/pkg/kubernetes/views/auth-rejected-cert.html b/pkg/kubernetes/views/auth-rejected-cert.html deleted file mode 100644 index cb5e1cf83..000000000 --- a/pkg/kubernetes/views/auth-rejected-cert.html +++ /dev/null @@ -1,35 +0,0 @@ - - - diff --git a/pkg/kubernetes/views/container-body.html b/pkg/kubernetes/views/container-body.html deleted file mode 100644 index 0bdc8292c..000000000 --- a/pkg/kubernetes/views/container-body.html +++ /dev/null @@ -1,33 +0,0 @@ -
-
-
-
Container
-
{{container.spec.name}}
-
Image
-
{{container.spec.image}}
-
Image ID
-
{{container.status.imageID | kubeIdentifier }}
-
Container ID
-
{{container.status.containerID | kubeIdentifier }}
-
Ports
-
- {{port.containerPort}}/{{port.protocol}} -
-
State
-
{{state}}
-
Since
-
{{args.startedAt}}
-
Restart Count
-
{{container.status.restartCount}}
-
-
-
-
-
Environment
-
{{env.name}}={{env.value}} -
-
-
-
diff --git a/pkg/kubernetes/views/container-page-inline.html b/pkg/kubernetes/views/container-page-inline.html deleted file mode 100644 index bc83700c7..000000000 --- a/pkg/kubernetes/views/container-page-inline.html +++ /dev/null @@ -1,23 +0,0 @@ -
-

Container

-
- - -
- -

Logs

-
- - -
- -

Shell

-
- - -
-
- -
-

The container '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/container-page.html b/pkg/kubernetes/views/container-page.html deleted file mode 100644 index b663911c5..000000000 --- a/pkg/kubernetes/views/container-page.html +++ /dev/null @@ -1,7 +0,0 @@ -
-

{{ container.spec.name }}

-

{{ target }}

- -
- -
diff --git a/pkg/kubernetes/views/container-panel.html b/pkg/kubernetes/views/container-panel.html deleted file mode 100644 index 84e15d2b9..000000000 --- a/pkg/kubernetes/views/container-panel.html +++ /dev/null @@ -1,23 +0,0 @@ -
- -
-
- -
-
- - -
-
- - -
diff --git a/pkg/kubernetes/views/containers-listing.html b/pkg/kubernetes/views/containers-listing.html deleted file mode 100644 index acc098be0..000000000 --- a/pkg/kubernetes/views/containers-listing.html +++ /dev/null @@ -1,43 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Containers

-
NamePodProjectNamespaceNodeStatus
- - {{container.spec.name}}{{item.metadata.name}}{{item.metadata.namespace}}{{item.spec.nodeName}}{{name}}
diff --git a/pkg/kubernetes/views/containers-page.html b/pkg/kubernetes/views/containers-page.html deleted file mode 100644 index 1aaf9f74a..000000000 --- a/pkg/kubernetes/views/containers-page.html +++ /dev/null @@ -1,4 +0,0 @@ - - - -
diff --git a/pkg/kubernetes/views/dashboard-page.html b/pkg/kubernetes/views/dashboard-page.html deleted file mode 100644 index baf4d0bfd..000000000 --- a/pkg/kubernetes/views/dashboard-page.html +++ /dev/null @@ -1,215 +0,0 @@ - - - - -
-
- - -
-
- -
-
-

{{pods.length}} Pods

-
-

- - {{status.pods.Pending.length}} - - - {{status.pods.Failed.length}} - - - {{status.pods.Unknown.length}} - - - - - All running - - - No pods deployed - - -

-
-
-
-

{{volumes.length}} Volumes

-
-

- - {{status.volumes.Pending.length}} - - - {{status.volumes.Released.length}} - - - {{status.volumes.Failed.length}} - - - {{status.volumes.Available.length}} - - - - All in use - - - No volumes in use - - -

-

- - - - {{status.volumes.PendingClaims.length}} - pending volume claims - - -

-
-
-
-

{{nodes.length}} Nodes

-
-

- - {{status.nodes.Pending.length}} - - - {{status.nodes.Terminated.length}} - - - {{status.nodes.NotReady.length}} - - - {{status.nodes.OutOfDisk.length}} - - - - All healthy - - - - No nodes in cluster - - -

-
-
-
- -
-
-
-
- - -
-

Services

-
-
-
-
- - -
-

Could not list services

-

{{failure.message}}

-
-
-
- -
-

No services present

-

You can deploy an application to your cluster.

-
- - - - - - - - - - - - - - - - - - - - -
NameAddressContainersProjectNamespace
{{service.metadata.name}}{{serviceContainers(service)}}{{service.metadata.namespace}} - - -
-
-
-
-
-
- -
-

Nodes

-
-
- - - - - - - - - - - - - - - -
NameContainers
{{node.metadata.name}}{{nodeContainers(node)}} - -
-
-
-
diff --git a/pkg/kubernetes/views/default-panel.html b/pkg/kubernetes/views/default-panel.html deleted file mode 100644 index 78d46d142..000000000 --- a/pkg/kubernetes/views/default-panel.html +++ /dev/null @@ -1,2 +0,0 @@ -
-
diff --git a/pkg/kubernetes/views/deploy.html b/pkg/kubernetes/views/deploy.html deleted file mode 100644 index a2bb2746a..000000000 --- a/pkg/kubernetes/views/deploy.html +++ /dev/null @@ -1,64 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/deploymentconfig-body.html b/pkg/kubernetes/views/deploymentconfig-body.html deleted file mode 100644 index 4c27f7735..000000000 --- a/pkg/kubernetes/views/deploymentconfig-body.html +++ /dev/null @@ -1,46 +0,0 @@ -
-
-
-
Project
-
Namespace
-
{{ item.metadata.namespace }}
-
Created
-
{{ item.metadata.creationTimestamp | dateRelative }}
-
Replicas
-
{{ item.spec.replicas }}
- -
Strategy
-
{{item.spec.strategy.type}}
- -
Latest Version
-
{{ item.status.latestVersion }}
-
Not deployed
-
-
-
-
-
Deployment Causes
-
{{ item.status.details.message }}
-
- {{ cause.type }} - - - {{ cause.imageTrigger.from.name }} - -
-
-
-
Triggers
-
- {{ trigger.type }} - - - {{ trigger.imageChangeParams.from.name }} - -
-
-
-
Labels
-
none -
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/deploymentconfig-page.html b/pkg/kubernetes/views/deploymentconfig-page.html deleted file mode 100644 index cfe76a45b..000000000 --- a/pkg/kubernetes/views/deploymentconfig-page.html +++ /dev/null @@ -1,26 +0,0 @@ -
-
- -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
-

Deployment Config

-
- -

Template

-
- - - - -
-
- -
-

The deployment config '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/deploymentconfig-panel.html b/pkg/kubernetes/views/deploymentconfig-panel.html deleted file mode 100644 index 95de37291..000000000 --- a/pkg/kubernetes/views/deploymentconfig-panel.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
- -
- -
-
-
- - - - -
diff --git a/pkg/kubernetes/views/details-page.html b/pkg/kubernetes/views/details-page.html deleted file mode 100644 index 08a6b15b3..000000000 --- a/pkg/kubernetes/views/details-page.html +++ /dev/null @@ -1,196 +0,0 @@ -
- -
- - -
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-

Services

-
NameProjectNamespaceAddressesState
- - {{item.metadata.name}}{{item.metadata.namespace}} - Ready - Not Ready -
-
-

Routes

-
NameProjectNamespaceHost
- - {{item.metadata.name}}{{item.metadata.namespace}}{{item.spec.host}}
-

Deployment Configs

-
NameProjectNamespaceLatest Version
- - {{item.metadata.name}}{{item.metadata.namespace}}{{ item.status.latestVersion }}Not deployed
-

Replication Controllers

-
NameProjectNamespaceReplicas
- - {{item.metadata.name}}{{item.metadata.namespace}}{{ item.spec.replicas }}{{ item.status.replicas }} of {{ item.spec.replicas }}
-

Pods

-
NameProjectNamespaceAddressState
- - {{item.metadata.name}}{{item.metadata.namespace}}{{item.status.podIP}}{{ podStatus(item) }}
-
diff --git a/pkg/kubernetes/views/file-button.html b/pkg/kubernetes/views/file-button.html deleted file mode 100644 index f3f97e7c0..000000000 --- a/pkg/kubernetes/views/file-button.html +++ /dev/null @@ -1,6 +0,0 @@ - - diff --git a/pkg/kubernetes/views/filter-bar.html b/pkg/kubernetes/views/filter-bar.html deleted file mode 100644 index 7b2fb049f..000000000 --- a/pkg/kubernetes/views/filter-bar.html +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/filter-project.html b/pkg/kubernetes/views/filter-project.html deleted file mode 100644 index 00657de43..000000000 --- a/pkg/kubernetes/views/filter-project.html +++ /dev/null @@ -1,19 +0,0 @@ -
- - -
diff --git a/pkg/kubernetes/views/group-delete.html b/pkg/kubernetes/views/group-delete.html deleted file mode 100644 index 3b942db4a..000000000 --- a/pkg/kubernetes/views/group-delete.html +++ /dev/null @@ -1,23 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/group-page.html b/pkg/kubernetes/views/group-page.html deleted file mode 100644 index f252d1719..000000000 --- a/pkg/kubernetes/views/group-page.html +++ /dev/null @@ -1,48 +0,0 @@ -
-
- -
-

- - {{ group().metadata.name }} -

-

- - {{ groupName }} -

- Show all Projects -
-
-
- - - - - - - - - - - - - - - - - - -
Group Members
{{ user }} - -
- - - Add Member - -
-
-
-
-

The group '{{ groupName }}' does not exist.

-
diff --git a/pkg/kubernetes/views/group-panel.html b/pkg/kubernetes/views/group-panel.html deleted file mode 100644 index 85a88f97d..000000000 --- a/pkg/kubernetes/views/group-panel.html +++ /dev/null @@ -1,36 +0,0 @@ -
-
- -
-

{{ group().metadata.name }}

-
-
-
- - - - - - - - - - - - - - - - - - -
Group Members
{{ user }} - -
- - - Add Member - -
-
-
diff --git a/pkg/kubernetes/views/image-delete.html b/pkg/kubernetes/views/image-delete.html deleted file mode 100644 index dbc448dd4..000000000 --- a/pkg/kubernetes/views/image-delete.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/image-page.html b/pkg/kubernetes/views/image-page.html deleted file mode 100644 index d0f4ebc65..000000000 --- a/pkg/kubernetes/views/image-page.html +++ /dev/null @@ -1,36 +0,0 @@ -
-
- -
-

- - {{ stream.metadata.namespace }}/{{ stream.metadata.name}}:{{ tag.tag }} -

- -
- -
-

Image

-
- - - - -
- -

Container

-
- - -
- -

Metadata

-
- - - - -
-
diff --git a/pkg/kubernetes/views/images-page.html b/pkg/kubernetes/views/images-page.html deleted file mode 100644 index e711c0847..000000000 --- a/pkg/kubernetes/views/images-page.html +++ /dev/null @@ -1,23 +0,0 @@ - - - -
- - - - - -
- - - New image stream - -

Images

-
- - - - -
diff --git a/pkg/kubernetes/views/imagestream-delete.html b/pkg/kubernetes/views/imagestream-delete.html deleted file mode 100644 index cb37b2068..000000000 --- a/pkg/kubernetes/views/imagestream-delete.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/imagestream-modify.html b/pkg/kubernetes/views/imagestream-modify.html deleted file mode 100644 index 2eac2c1e6..000000000 --- a/pkg/kubernetes/views/imagestream-modify.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/imagestream-page.html b/pkg/kubernetes/views/imagestream-page.html deleted file mode 100644 index 2d1a9f63f..000000000 --- a/pkg/kubernetes/views/imagestream-page.html +++ /dev/null @@ -1,35 +0,0 @@ -
-
- - -
-

- - {{ stream.metadata.namespace }}/{{ stream.metadata.name}} -

- Show all image streams -
- -
-

Image Stream

-
- - - - -
-

Images

- - - -

Metadata

-
- - -
-
diff --git a/pkg/kubernetes/views/item-delete.html b/pkg/kubernetes/views/item-delete.html deleted file mode 100644 index a7807f9f0..000000000 --- a/pkg/kubernetes/views/item-delete.html +++ /dev/null @@ -1,13 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/node-add.html b/pkg/kubernetes/views/node-add.html deleted file mode 100644 index 0bcd8ea60..000000000 --- a/pkg/kubernetes/views/node-add.html +++ /dev/null @@ -1,52 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/node-alerts.html b/pkg/kubernetes/views/node-alerts.html deleted file mode 100644 index f0282422f..000000000 --- a/pkg/kubernetes/views/node-alerts.html +++ /dev/null @@ -1,13 +0,0 @@ -
- - {{ nodeCondition(item, 'Ready').message }} -
-
- - The node doesn't have enough disk space. -
-
- - The node doesn't have enough free memory. -
- diff --git a/pkg/kubernetes/views/node-body.html b/pkg/kubernetes/views/node-body.html deleted file mode 100644 index 5e86083e3..000000000 --- a/pkg/kubernetes/views/node-body.html +++ /dev/null @@ -1,61 +0,0 @@ -
-
-
Created
-
{{ item.metadata.creationTimestamp | dateRelative }}
-
Address
-
- {{item.metadata.name}} - {{item.metadata.name}} -
-
IP
-
{{ nodeIPAddress(item) }}
-
Unknown
-
OS
-
{{item.status.nodeInfo.osImage}}
-
Machine ID
-
{{item.status.nodeInfo.machineID}}
-
Boot ID
-
{{item.status.nodeInfo.bootID}}
-
Kernel Version
-
{{item.status.nodeInfo.kernelVersion}}
-
Container Runtime Version
-
{{item.status.nodeInfo.containerRuntimeVersion}}
-
Kubelet Version
-
{{item.status.nodeInfo.kubeletVersion}}
-
Proxy Version
-
{{item.status.nodeInfo.kubeProxyVersion}}
-
-
-
-
-
Labels
-
{{key}}={{value}}
-
none
-
-
-
-
-
-
Status
-
- Ready - Not Ready - Unknown -
-
Reason
-
{{ready.reason }}
-
Message
-
{{ready.reason }}
-
Last Heartbeat
-
{{ready.lastHeartbeatTime | dateRelative }}
-
Last Status Change
-
{{ready.lastTransitionTime | dateRelative }}
-
-
-
-
-
Annotations
-
{{key}}={{value}}
-
none
-
-
diff --git a/pkg/kubernetes/views/node-capacity.html b/pkg/kubernetes/views/node-capacity.html deleted file mode 100644 index 639dc965b..000000000 --- a/pkg/kubernetes/views/node-capacity.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
-
{{ key | formatCapacityName }}
-
{{ value | formatCapacityValue:key }}
-
-
-
-
-
Scheduled Pods
-
{{ pod.metadata.name }}
-
No pods scheduled
-
-
diff --git a/pkg/kubernetes/views/node-delete.html b/pkg/kubernetes/views/node-delete.html deleted file mode 100644 index 054deeda6..000000000 --- a/pkg/kubernetes/views/node-delete.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/node-page.html b/pkg/kubernetes/views/node-page.html deleted file mode 100644 index 95cbc4361..000000000 --- a/pkg/kubernetes/views/node-page.html +++ /dev/null @@ -1,24 +0,0 @@ -
-
- -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
- -
-

Node

-
- -

Capacity

-
-
-
- -
-

The node '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/node-panel.html b/pkg/kubernetes/views/node-panel.html deleted file mode 100644 index 51b5dcde1..000000000 --- a/pkg/kubernetes/views/node-panel.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
- -
- -
- -
- -
-
- -
-
-
-
-
diff --git a/pkg/kubernetes/views/node-stats.html b/pkg/kubernetes/views/node-stats.html deleted file mode 100644 index 4248231d3..000000000 --- a/pkg/kubernetes/views/node-stats.html +++ /dev/null @@ -1,9 +0,0 @@ -
-
-
-
-
-
-
-
-
diff --git a/pkg/kubernetes/views/nodes-page.html b/pkg/kubernetes/views/nodes-page.html deleted file mode 100644 index 1073f0111..000000000 --- a/pkg/kubernetes/views/nodes-page.html +++ /dev/null @@ -1,74 +0,0 @@ -
-
- - -
-
- -
-
-
-
-
-
-

OS Versions

-
-
-
-
-
-
- -
- - - - - - - - - - - - - - - - - - - - - - - - - -
- - - Add Kubernetes Node - -

Nodes

-
NameOperating SystemAddressStatus
- -
- -
-
{{item.metadata.name}} -
{{item.status.nodeInfo.osImage}}
-
{{ nodeIPAddress(item) }} - - {{ nodeStatus(item) }} -
-
diff --git a/pkg/kubernetes/views/pod-body.html b/pkg/kubernetes/views/pod-body.html deleted file mode 100644 index ebd03a1f3..000000000 --- a/pkg/kubernetes/views/pod-body.html +++ /dev/null @@ -1,30 +0,0 @@ -
-
-
-
Project
-
Namespace
-
{{ pod.metadata.namespace }}
-
Created
-
{{ pod.metadata.creationTimestamp | dateRelative }}
-
Restart Policy
-
{{ pod.spec.restartPolicy }}
-
Service Account
-
{{ pod.spec.serviceAccountName }}
-
DNS Policy
-
{{ pod.spec.dnsPolicy }}
-
Phase
-
{{pod.status.phase}}
-
Node
-
{{pod.spec.host}}
-
Pod Address
-
{{pod.status.podIP}}
-
-
-
-
-
Labels
-
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/pod-container.html b/pkg/kubernetes/views/pod-container.html deleted file mode 100644 index 4e2f8848e..000000000 --- a/pkg/kubernetes/views/pod-container.html +++ /dev/null @@ -1,7 +0,0 @@ -
-

{{ pod.metadata.name }} / {{ container.spec.name }}

-

{{ target }}

- -
- -
diff --git a/pkg/kubernetes/views/pod-page.html b/pkg/kubernetes/views/pod-page.html deleted file mode 100644 index 6430e79e5..000000000 --- a/pkg/kubernetes/views/pod-page.html +++ /dev/null @@ -1,41 +0,0 @@ -
-
- -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
-

Pod

-
- - -
- -

Volumes

-
-

{{ podVolume.name }}

-
-
-
-
Mount Location
-
- None -
-
{{ name }}
-
{{ data.mountPath }}
-
-
-
-
- -

Containers

-
- -
-

The pod '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/pod-panel.html b/pkg/kubernetes/views/pod-panel.html deleted file mode 100644 index 4de545a49..000000000 --- a/pkg/kubernetes/views/pod-panel.html +++ /dev/null @@ -1,62 +0,0 @@ -
-
-
- -
- -
-
- - -
-
- - -
-
-
-

{{ container.spec.name }}

- - -
-
-
-
-

{{ container.spec.name }}

- - -
-
- -
-
-
-
-
-
Mount Location
-
- None -
-
{{ name }}
-
{{ data.mountPath }}
-
-
-
-
-
-
diff --git a/pkg/kubernetes/views/project-body.html b/pkg/kubernetes/views/project-body.html deleted file mode 100644 index f92236aae..000000000 --- a/pkg/kubernetes/views/project-body.html +++ /dev/null @@ -1,113 +0,0 @@ -

- - Project access policy allows anonymous users to pull images. Grant additional push or admin access to specific members below. - -

-

- - Project access policy allows any authenticated user to pull images. Grant additional push or admin access to specific members below. - -

-

- - Project access policy only allows specific members to access images. Grant access to specific members below. - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Project MembersRoles
-
- - {{ user.metadata.name }} -
-
-
- - -
-
- -
-
- - -
-
- - {{ group.metadata.name }} -
-
-
- - -
-
- - -
- - - Add Member - -
diff --git a/pkg/kubernetes/views/project-delete.html b/pkg/kubernetes/views/project-delete.html deleted file mode 100644 index fab242893..000000000 --- a/pkg/kubernetes/views/project-delete.html +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/pkg/kubernetes/views/pvc-body.html b/pkg/kubernetes/views/pvc-body.html deleted file mode 100644 index d6d0b2e82..000000000 --- a/pkg/kubernetes/views/pvc-body.html +++ /dev/null @@ -1,54 +0,0 @@ -
-
Volume Type
-
Persistent Volume
-
Claim Name
-
{{ item.metadata.name }}
-
Volume
-
- {{ item.spec.volumeName }} - {{ item.spec.volumeName }} - No Volume Bound -
- -
Status
-
{{ item.status.phase }}
-
Message
-
{{ item.status.message }}
- -
Access Modes
-
-
-
Requested
-
- {{ mode | accessModeLabel }}, -
-
Actual
-
- {{ mode | accessModeLabel }}, -
-
-
- -
Capacity
-
-
-
Requested
-
-
-
{{ key | formatCapacityName }}
-
{{ value | formatCapacityValue:key }}
-
-
-
- -
-
Actual
-
-
-
{{ key | formatCapacityName }}
-
{{ value | formatCapacityValue:key }}
-
-
-
-
-
diff --git a/pkg/kubernetes/views/pvc-delete.html b/pkg/kubernetes/views/pvc-delete.html deleted file mode 100644 index 8abdbd071..000000000 --- a/pkg/kubernetes/views/pvc-delete.html +++ /dev/null @@ -1,17 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/registry-dashboard-page.html b/pkg/kubernetes/views/registry-dashboard-page.html deleted file mode 100644 index ce41bfc92..000000000 --- a/pkg/kubernetes/views/registry-dashboard-page.html +++ /dev/null @@ -1,162 +0,0 @@ -
-
- -
-

Welcome to the Image Registry

-

In order to begin pushing images to the registry, you need to create a project.

- -
- -
-
-
- - - -
-
- - - - -
- - - - - - {{ project.metadata.name }} - -
-
- -
-
-
-

Images pushed recently

- - -
-
-
-
- {{ data.tags[0].items[0].created | dateRelative }}
-
- {{ data.stream.metadata.namespace}}/{{data.stream.metadata.name }}
- - -
- All images -
-
-
- -
-

No images pushed

-

In order to begin pushing images to the registry, use the commands below.

-
- -
-
-
-
-
-

- - Login commands -

-
-
-

- Log into the registry: - - - -

-
- - Your login credentials do not give you access to use the docker registry from the command line. -
-$ sudo docker login -p {{settings.registry.password}} -u unused {{settings.registry.host}} -

- Log into OpenShift command line tools: - - - -

-$ oc login --token {{settings.registry.password}} {{settings.registry.openshifthost}} -
-
-
-
-
-
-

- - Image commands -

-
-
-
-

- Push an image: - - - -

-$ sudo docker tag myimage {{settings.registry.host}}/project/name:tag -$ sudo docker push {{settings.registry.host}}/project/name -
-

- Pull an image: - - - -

-$ sudo docker pull {{settings.registry.host}}/project/name:tag -
-
-
diff --git a/pkg/kubernetes/views/remove-role-dialog.html b/pkg/kubernetes/views/remove-role-dialog.html deleted file mode 100644 index d63c6bd33..000000000 --- a/pkg/kubernetes/views/remove-role-dialog.html +++ /dev/null @@ -1,10 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/replicationcontroller-body.html b/pkg/kubernetes/views/replicationcontroller-body.html deleted file mode 100644 index 1f3474dea..000000000 --- a/pkg/kubernetes/views/replicationcontroller-body.html +++ /dev/null @@ -1,21 +0,0 @@ -
-
-
-
Project
-
Namespace
-
{{ item.metadata.namespace }}
-
Created
-
{{ item.metadata.creationTimestamp | dateRelative }}
-
Replicas
-
{{ item.spec.replicas }}
-
{{ item.status.replicas }} - of {{ item.spec.replicas }}
-
-
-
-
-
Labels
-
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/replicationcontroller-modify.html b/pkg/kubernetes/views/replicationcontroller-modify.html deleted file mode 100644 index 4dc385e2b..000000000 --- a/pkg/kubernetes/views/replicationcontroller-modify.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/replicationcontroller-page.html b/pkg/kubernetes/views/replicationcontroller-page.html deleted file mode 100644 index bde9750cc..000000000 --- a/pkg/kubernetes/views/replicationcontroller-page.html +++ /dev/null @@ -1,31 +0,0 @@ -
-
- - -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
-

Replication Controller

-
- -

Pods

-
- -

Template

-
- - - - -
-
- -
-

The replication controller '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/replicationcontroller-panel.html b/pkg/kubernetes/views/replicationcontroller-panel.html deleted file mode 100644 index 728ccdd07..000000000 --- a/pkg/kubernetes/views/replicationcontroller-panel.html +++ /dev/null @@ -1,28 +0,0 @@ -
-
- - -
- -
-
- -
-
- -
-
- - - - -
diff --git a/pkg/kubernetes/views/replicationcontroller-pods.html b/pkg/kubernetes/views/replicationcontroller-pods.html deleted file mode 100644 index 6c059f94c..000000000 --- a/pkg/kubernetes/views/replicationcontroller-pods.html +++ /dev/null @@ -1,15 +0,0 @@ -
-
-
-
Pod Replicated
-
{{ pod.metadata.name }}
-
No pods replicated
-
-
-
-
-
Pod Selector
-
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/route-body.html b/pkg/kubernetes/views/route-body.html deleted file mode 100644 index 7bd46a980..000000000 --- a/pkg/kubernetes/views/route-body.html +++ /dev/null @@ -1,32 +0,0 @@ -
-
-
-
Project
-
Namespace
-
{{ item.metadata.namespace }}
-
Created
-
{{ item.metadata.creationTimestamp | dateRelative }}
-
Host
-
{{ item.spec.host }}
- -
TLS Termination
-
yes
-
no
- -
{{ item.spec.to.kind }} -
{{item.spec.to.name}}
-
-
-
-
-
Labels
-
{{key}}={{value}}
-
none
-
-
-
Annotations
-
{{key}}={{value}}
-
none
-
-
-
diff --git a/pkg/kubernetes/views/route-modify.html b/pkg/kubernetes/views/route-modify.html deleted file mode 100644 index 70eefa7f0..000000000 --- a/pkg/kubernetes/views/route-modify.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/route-page.html b/pkg/kubernetes/views/route-page.html deleted file mode 100644 index d83f122b7..000000000 --- a/pkg/kubernetes/views/route-page.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- - -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
-

Route

-
-
- -
-

The route '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/route-panel.html b/pkg/kubernetes/views/route-panel.html deleted file mode 100644 index fbdeeb2bc..000000000 --- a/pkg/kubernetes/views/route-panel.html +++ /dev/null @@ -1,13 +0,0 @@ -
-
- - -
- -
-
-
diff --git a/pkg/kubernetes/views/service-body.html b/pkg/kubernetes/views/service-body.html deleted file mode 100644 index 849860f9f..000000000 --- a/pkg/kubernetes/views/service-body.html +++ /dev/null @@ -1,30 +0,0 @@ -
-
-
-
Project
-
Namespace
-
{{ item.metadata.namespace }}
-
Created
-
{{ item.metadata.creationTimestamp | dateRelative }}
-
IP
-
{{ item.spec.clusterIP }}
-
Type
-
{{ item.spec.type }}
-
Ports
-
-
None
-
- {{portMapping.port}}/{{portMapping.protocol}} → {{portMapping.nodePort || portMapping.targetPort}} -
-
-
Session Affinity
-
{{ item.spec.sessionAffinity }}
-
-
-
-
-
Labels
-
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/service-endpoint.html b/pkg/kubernetes/views/service-endpoint.html deleted file mode 100644 index 9cb6a5800..000000000 --- a/pkg/kubernetes/views/service-endpoint.html +++ /dev/null @@ -1,19 +0,0 @@ -
-
-
-
Pod Endpoints
-
- {{ address.ip }} → {{ address.targetRef.name }}
-
-
-
Pod Endpoints
-
No pods selected
-
-
-
-
-
Pod Selector
-
{{key}}={{value}}
-
-
-
diff --git a/pkg/kubernetes/views/service-modify.html b/pkg/kubernetes/views/service-modify.html deleted file mode 100644 index c09e3fb95..000000000 --- a/pkg/kubernetes/views/service-modify.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/service-page.html b/pkg/kubernetes/views/service-page.html deleted file mode 100644 index 7656ecf99..000000000 --- a/pkg/kubernetes/views/service-page.html +++ /dev/null @@ -1,20 +0,0 @@ -
-
- -
-

{{ item.metadata.name }}

-

{{ target }}

- -
- -
-

Service

-
-

Endpoints

-
-
- -
-

The service '{{ target }}' does not exist.

-
diff --git a/pkg/kubernetes/views/service-panel.html b/pkg/kubernetes/views/service-panel.html deleted file mode 100644 index e082cb60b..000000000 --- a/pkg/kubernetes/views/service-panel.html +++ /dev/null @@ -1,16 +0,0 @@ -
-
-
- -
- -
-
-
-
-
-
diff --git a/pkg/kubernetes/views/topology-page.html b/pkg/kubernetes/views/topology-page.html deleted file mode 100644 index c674f7da2..000000000 --- a/pkg/kubernetes/views/topology-page.html +++ /dev/null @@ -1,92 +0,0 @@ - - - -
- -
- - - - - diff --git a/pkg/kubernetes/views/user-add-membership.html b/pkg/kubernetes/views/user-add-membership.html deleted file mode 100644 index 96515bca0..000000000 --- a/pkg/kubernetes/views/user-add-membership.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/user-body.html b/pkg/kubernetes/views/user-body.html deleted file mode 100644 index 518a5ae63..000000000 --- a/pkg/kubernetes/views/user-body.html +++ /dev/null @@ -1,72 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Member ofRole
-
- - {{ member.metadata.name }} -
-
-
- - -
-
- - -
-
- - {{ member.metadata.name }} -
-
- - - -
- - - Add Membership - -
diff --git a/pkg/kubernetes/views/user-delete.html b/pkg/kubernetes/views/user-delete.html deleted file mode 100644 index 09b4b9c7f..000000000 --- a/pkg/kubernetes/views/user-delete.html +++ /dev/null @@ -1,27 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/user-group-add.html b/pkg/kubernetes/views/user-group-add.html deleted file mode 100644 index fa0358a52..000000000 --- a/pkg/kubernetes/views/user-group-add.html +++ /dev/null @@ -1,32 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/user-group-remove.html b/pkg/kubernetes/views/user-group-remove.html deleted file mode 100644 index bc3f32704..000000000 --- a/pkg/kubernetes/views/user-group-remove.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/user-modify.html b/pkg/kubernetes/views/user-modify.html deleted file mode 100644 index 51434fc43..000000000 --- a/pkg/kubernetes/views/user-modify.html +++ /dev/null @@ -1,29 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/user-page.html b/pkg/kubernetes/views/user-page.html deleted file mode 100644 index 6b231db02..000000000 --- a/pkg/kubernetes/views/user-page.html +++ /dev/null @@ -1,30 +0,0 @@ -
-
- - -
-

- - {{ user().metadata.name }} -

-

- - {{ userName }} -

- -
-
-

User

-
-
Identities
-
{{ identity }}
-
-

Membership

-
-
-
-

The user '{{ userName }}' does not exist.

-
diff --git a/pkg/kubernetes/views/user-panel.html b/pkg/kubernetes/views/user-panel.html deleted file mode 100644 index 0af554110..000000000 --- a/pkg/kubernetes/views/user-panel.html +++ /dev/null @@ -1,82 +0,0 @@ -
- - -
-
-

{{ user().metadata.name }}

- -
-
-
-
-
-
Identities
-
{{ identity }}
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - -
Member ofRole
{{ member.metadata.name }} -
- - -
-
- - -
{{ member.metadata.name }} - - -
- - - Add Membership - -
-
diff --git a/pkg/kubernetes/views/user-remove-membership.html b/pkg/kubernetes/views/user-remove-membership.html deleted file mode 100644 index a3845df84..000000000 --- a/pkg/kubernetes/views/user-remove-membership.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - diff --git a/pkg/kubernetes/views/volume-body.html b/pkg/kubernetes/views/volume-body.html deleted file mode 100644 index b4e5031ce..000000000 --- a/pkg/kubernetes/views/volume-body.html +++ /dev/null @@ -1,144 +0,0 @@ -
Volume Type
-
{{ volume | formatVolumeType }}
- -
PD Name
-
{{ volume.gcePersistentDisk.pdName }}
-
Filesystem Type
-
{{ volume.gcePersistentDisk.fsType }}
-
Partition
-
{{ volume.gcePersistentDisk.partition | formatPartitionNumber }}
-
Read Only
-
{{ volume.gcePersistentDisk.readOnly | formatReadOnly }}
- - -
Volume ID
-
{{ volume.awsElasticBlockStore.volumeID }}
-
Filesystem Type
-
{{ volume.awsElasticBlockStore.fsType }}
-
Partition
-
{{ volume.awsElasticBlockStore.partition | formatPartitionNumber }}
-
Read Only
-
{{ volume.awsElasticBlockStore.readOnly | formatReadOnly }}
- - -
Repository URL
-
{{ volume.gitRepo.repository }}
-
Revision
-
{{ volume.gitRepo.revision }}
-
Directory
-
{{ volume.gitRepo.directory }}
- -
Name
-
{{ volume.secret.secretName }}
- -
Medium
-
{{ volume.emptyDir.medium }}
- -
Path
-
{{ volume.hostPath.path }}
- -
Endpoint Name
-
{{ volume.glusterfs.endpoints }}
-
Volume Name
-
{{ volume.glusterfs.path }}
-
Read Only
-
{{ volume.glusterfs.readOnly | formatReadOnly }}
- -
Server
-
{{ volume.nfs.server }}
-
Path
-
{{ volume.nfs.path }}
-
Read Only
-
{{ volume.nfs.readOnly | formatReadOnly }}
- -
Monitors
-
- {{ monitor }}, -
-
Image Name
-
{{ volume.rbd.image }}
-
Pool Name
-
{{ volume.rbd.pool }}
-
Filesystem Type
-
{{ volume.rbd.fsType }}
-
User
-
volume.rbd.user
-
admin
-
Key Ring Path
-
{{ volume.rbd.keyring }}
-
Secret Volume
-
{{ volume.rbd.secretRef.name }}
-
Read Only
-
{{ volume.rbd.readOnly | formatReadOnly }}
- - -
Target Portal
-
{{ volume.iscsi.targetPortal }}
-
Qualified Name
-
{{ volume.iscsi.iqn }}
-
Logical Unit Number
-
{{ volume.iscsi.lun }}
-
Interface
-
{{ volume.iscsi.iscsiInterface }}
-
Filesystem Type
-
{{ volume.iscsi.fsType }}
-
Read Only
-
{{ volume.iscsi.readOnly | formatReadOnly }}
- - -
Volume ID
-
{{ volume.cinder.volumeID }}
-
Filesystem Type
-
{{ volume.cinder.fsType }}
-
Read Only
-
{{ volume.cinder.readOnly | formatReadOnly }}
- - -
Ceph Monitors
-
- {{ monitor }}, -
-
Path
-
{{ volume.cephfs.path }}
-
User
-
volume.cephfs.user
-
admin
-
Secret File
-
{{ volume.cephfs.secretFile }}
-
Secret Volume
-
{{ volume.cephfs.secretRef.name }}
-
Read Only
-
{{ volume.cephfs.readOnly | formatReadOnly }}
- - -
Target World Wide Names
-
- {{ wwn }}, -
-
Logical Unit Number
-
{{ volume.fc.lun }}
-
Filesystem Type
-
{{ volume.fc.fsType }}
-
Read Only
-
{{ volume.fc.readOnly | formatReadOnly }}
- -
Flocker Dataset Name
-
{{ volume.flocker.datasetName }}
- -
Driver
-
{{ volume.flexVolume.driver }}
-
Options
-
{{ volume.flexVolume.options }}
-
Filesystem Type
-
{{ volume.flexVolume.fsType }}
-
Secret Volume
-
{{ volume.flexVolume.secretRef.name }}
-
Read Only
-
{{ volume.flexVolume.readOnly | formatReadOnly }}
- -
Share Name
-
{{ volume.azureFile.shareName }}
-
Secret Name
-
{{ volume.azureFile.secretName }}
-
Read Only
-
{{ volume.azureFile.readOnly | formatReadOnly }}
diff --git a/pkg/kubernetes/views/volumes-page.html b/pkg/kubernetes/views/volumes-page.html deleted file mode 100644 index 8edc8e172..000000000 --- a/pkg/kubernetes/views/volumes-page.html +++ /dev/null @@ -1,78 +0,0 @@ -
- -
- -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - Register New Volume - -

Persistent Volumes

-
NameTypeStatus
- - {{ item.metadata.name }}{{ item.spec | formatVolumeType }}{{ item.status.phase}}Unknown
No volumes are present.{{pvFailure}}
- - - - - - - - - - - - - - - - - - - - - - - - -
-

Pending Volume Claims

-
NameProjectNamespaceSizeWhen
{{ item.metadata.name }}{{ item.metadata.namespace }}{{ item.spec.resources.requests.storage }}{{ item.metadata.creationTimestamp | dateRelative }}
-
diff --git a/pkg/lib/angular-dialog.js b/pkg/lib/angular-dialog.js deleted file mode 100644 index cd035ab7d..000000000 --- a/pkg/lib/angular-dialog.js +++ /dev/null @@ -1,385 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -(function() { - var angular = require('angular'); - require('angular-bootstrap-npm/dist/angular-bootstrap.js'); - - angular.module('ui.cockpit', [ - 'ui.bootstrap', - ]) - - /* - * Implements a directive that works with ui-bootstrap's - * $modal service. Implements Cockpit dialog HIG behavior. - * - * This wraps and provides a default implementation - * of result and cancel where the dialog is closed when either method - * is called. - */ - .directive('modalDialog', [ - "$q", - function($q) { - return { - restrict: 'E', - transclude: true, - template: '', - link: function(scope, element, attrs) { - scope.cancel = function() { - scope.$dismiss(); - }; - - scope.result = function(success, result) { - /* Close dialog on success */ - if (success) - scope.$close(result); - }; - }, - }; - } - ]) - - /* - * Implements a directive that works with ui-bootstrap's - * $modal service. Implements Cockpit dialog HIG behavior. - * - * To use this directive your parent scope must implement a result - * and cancel method. See for the default implementation. - * - * This dialog treats a button with .btn-cancel class as a cancel - * button. Clicking it will call the cancel method or (see below) cancel - * a completion promise. - * - * From inside the dialog, you can invoke the following methods on - * the scope: - * - * failure(ex) - * failure([ex1, ex2]) - * - * Displays errors either globally or on fields. The ex.message or - * ex.toString() is displayed as the failure message. If ex.target - * is a valid CSS selector, then the failure message will be displayed - * under the selected field. - * - * failure() - * failure(null) - * - * Clears all failures from display. - * - * complete(promise) - * complete(data) - * - * Complete the dialog. If a promise is passed, then the dialog will - * enter into a wait state until the promise completes. If promise resolves - * then the result method with be called with the resolve value. If the promise - * rejects, then failures will be displayed by invoking failure() above. - * - * While the promise is completing, all .form-control and .btn will - * be disabled. If promise.cancel() is a method, then the .btn-cancel - * will remain clickable, and clicking it will cancel the promise, and - * when the promise completes, will call the cancel method. - */ - .directive('modalGroup', [ - "$q", - function($q) { - return { - restrict: 'E', - transclude: true, - template: '', - link: function(scope, element, attrs) { - var state = null; - - function detach() { - if (state) - state.detach(); - state = null; - } - - scope.complete = function(thing) { - var buttonSel = scope.modalGroupButtonSel || ".modal-footer"; - var errorAfter = scope.modalGroupErrorAfter || false; - - detach(); - if (!thing || !thing.then) - thing = $q(thing); - state = new DialogState(element, buttonSel, errorAfter, thing, scope); - }; - - scope.failure = function(/* ... */) { - var errors; - var n = arguments.length; - if (n === 0) { - errors = null; - } else if (n === 1) { - errors = arguments[0]; - } else { - errors = []; - errors.push.apply(errors, arguments); - } - - if (!errors) { - detach(); - return; - } - - var defer = $q.defer(); - defer.reject(errors); - scope.complete(defer.promise); - }; - - /* Dialog cancellation before promises kick in */ - function dismissDialog() { - scope.cancel(); - } - - var cancel = queryFirst(element, ".btn-cancel"); - cancel.on("click", dismissDialog); - scope.$on("$routeChangeStart", dismissDialog); - - scope.$on("$destroy", function() { - cancel.off("click", dismissDialog); - detach(); - }); - }, - }; - } - ]); - - function queryAll(element, selector) { - var list; - var result = []; - var j, i, jlen; - var len = element.length; - for (i = 0; i < len; i++) { - list = element[i].querySelectorAll(selector); - if (list) { - for (j = 0, jlen = list.length; j < jlen; j++) - result.push(list[j]); - } - } - return angular.element(result); - } - - function queryFirst(element, selector) { - var result = null; - var i; - var len = element.length; - for (i = 0; !result && i < len; i++) - result = element[i].querySelector(selector); - return angular.element(result); - } - - /* - * This state object handles one of three different states. - * This does not exist in the case "before" these states are relevant. - * - * state = null: pending - * state = true: succeeded - * state = false: failed - */ - function DialogState(element, btnSel, errorAfter, promise, scope) { - var state = null; - var result = null; - - /* Set to true when cancel was requested */ - var cancelled = false; - var detached = false; - - /* The wait field elements */ - var disabled = []; - var wait = angular.element("
"); - wait.append(angular.element("
")); - var notify = angular.element(""); - wait.append(notify); - - this.detach = detachState; - - if (!promise) { - detachState(); - return; - } - - promise.then(function(data) { - result = data; - if (promise) - changeState(true); - }, function(data) { - result = data; - if (promise) - changeState(false); - }, function(data) { - if (promise) - notifyWait(data); - }); - - window.setTimeout(function() { - if (promise && scope && state === null) { - changeState(null); - scope.$digest(); - } - }, 0); - - function changeState(value) { - if (detached) - return; - state = value; - if (cancelled) { - scope.cancel(); - } else if (state === null) { - clearErrors(); - displayWait(); - } else if (state === true) { - clearErrors(); - clearWait(); - scope.result(true, result); - } else if (state === false) { - clearWait(); - displayErrors(result); - scope.result(false, result); - } else { - console.warn("invalid dialog state", state); - } - } - - function detachState() { - scope = null; - promise = null; - clearErrors(); - clearWait(); - } - - function displayErrors(errors) { - clearErrors(); - - if (!angular.isArray(errors)) - errors = [errors]; - errors.forEach(function(error) { - var target = null; - /* Each error can have a target field */ - if (error.target) - target = queryFirst(element, error.target); - if (target && target[0]) - fieldError(target, error); - else - globalError(error); - }); - } - - function globalError(error) { - var alert = angular.element("
"); - var message = error.message || error.toString(); - console.warn(message); - alert.text(message); - alert.prepend(angular.element("")); - - var wrapper = queryFirst(element, btnSel); - if (wrapper.length) { - if (errorAfter) - wrapper.append(alert); - else - wrapper.prepend(alert); - } else { - element.append(alert); - } - } - - function fieldError(target, error) { - var message = angular.element("
"); - message.text(error.message || error.toString()); - var wrapper = target.parent(); - wrapper.addClass("has-error"); - target.after(message); - wrapper.on("keypress change", handleClear); - } - - function handleClear(ev) { - var target = ev.target; - while (target !== this) { - clearError(angular.element(target)); - target = target.parentNode; - } - } - - function clearError(target) { - var wrapper = target.parent(); - queryAll(wrapper, ".dialog-error").remove(); - wrapper.removeClass("has-error"); - wrapper.off("keypress change", handleClear); - } - - function clearErrors() { - var messages = queryAll(element, ".dialog-error"); - angular.forEach(messages, function(message) { - clearError(angular.element(message)); - }); - } - - function handleCancel(ev) { - if (promise.cancel) - promise.cancel(); - cancelled = true; - ev.stopPropagation(); - ev.preventDefault(); - return false; - } - - function notifyWait(data) { - var message = data.message || data; - if (typeof message == "string" || typeof message == "number") - notify.text(message); - else if (!message) - notify.text(""); - } - - function clearWait() { - var control; - while (true) { - control = disabled.pop(); - if (!control) - break; - control.removeAttr("disabled"); - } - wait.remove(); - queryFirst(element, ".btn-cancel").off("click", handleCancel); - } - - function displayWait() { - clearWait(); - - /* Insert the wait area */ - queryFirst(element, btnSel).prepend(wait); - - /* Disable everything and stash previous disabled state */ - function disable(el) { - var control = angular.element(el); - if (control.attr("disabled") || - (promise.cancel && control.hasClass("btn-cancel"))) - return; - disabled.push(control); - control.attr("disabled", "disabled"); - } - - angular.forEach(queryAll(element, ".form-control"), disable); - angular.forEach(queryAll(element, ".form-checkbox"), disable); - angular.forEach(queryAll(element, ".btn"), disable); - - queryFirst(element, ".btn-cancel").on("click", handleCancel); - } - } -}()); diff --git a/pkg/playground/translate.html b/pkg/playground/translate.html index 7c3fae2f8..8c7c4a20e 100644 --- a/pkg/playground/translate.html +++ b/pkg/playground/translate.html @@ -167,44 +167,6 @@
  • Extraction of single quoted strings.
- -
- -

Angular Translations

- -

In Angular use these forms:

- -

- <span translate>Ready</span> - = Ready -

- -

- <span translate translate-context="verb">Ready</span> - = Ready -

- -

- <span translate>Delete '{{ name }}'</span> - = Delete '{{ name }}' -

- - - -

When translating Angular we not support:

-

    -
  • The translatable attribute.
  • -
  • The translate="attr" translating of attribute values.
  • -
  • The {{value|translate}} filter, even though documented on angular-gettext.
  • -
  • The <translate> element
  • -
diff --git a/pkg/playground/translate.js b/pkg/playground/translate.js index 657b8bf97..bc5d7cb98 100644 --- a/pkg/playground/translate.js +++ b/pkg/playground/translate.js @@ -1,8 +1,6 @@ import $ from "jquery"; import cockpit from "cockpit"; import { mustache } from "mustache"; -import angular from 'angular'; -import 'angular-gettext/dist/angular-gettext.js'; const _ = cockpit.gettext; var C_ = cockpit.gettext; @@ -42,13 +40,7 @@ $(function () { $("#mustache-output").empty() .append(output); - var module = angular.module('playgroundTranslate', [ 'gettext' ]); - - module.run(["$rootScope", function($rootScope) { - cockpit.transport.wait(function() { - $rootScope.$digest(); - $("body").show(); - }); - }]); - angular.bootstrap(document, ['playgroundTranslate']); + cockpit.transport.wait(function() { + $("body").show(); + }); }); diff --git a/pkg/shell/index-stub.js b/pkg/shell/index-stub.js deleted file mode 100644 index ab8292282..000000000 --- a/pkg/shell/index-stub.js +++ /dev/null @@ -1,73 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2016 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ - -import $ from "jquery"; -import cockpit from "cockpit"; - -import { machines } from "machines"; -import { new_machine_dialog_manager } from "machine-dialogs"; - -import * as indexes from "./indexes"; - -var default_title = "Cockpit"; -var manifest = cockpit.manifests["shell"] || { }; -if (manifest.title) - default_title = manifest.title; - -var options = { - brand_sel: "#index-brand", - logout_sel: "#go-logout", - oops_sel: "#navbar-oops", - language_sel: "#display-language", - about_sel: "#about-version", - default_title: default_title, - skip_brand_title: true -}; - -/* When alt is held down we display debugging menu items */ -document.addEventListener("click", function(ev) { - var i; - var visible = !!ev.altKey; - var advanced = document.querySelectorAll(".navbar-advanced"); - for (i = 0; i < advanced.length; i++) - advanced[i].style.display = visible ? "block" : "none"; -}, true); - -var machines_inst = machines.instance(); -var loader = machines.loader(machines_inst, true); -var dialogs = new_machine_dialog_manager(machines_inst, { - "no-cockpit": "not-supported", - "not-supported": "not-supported", - "protocol-error": "not-supported", - "authentication-not-supported": "change-auth", - "authentication-failed": "change-auth", - "no-forwarding": "change-auth", - "unknown-hostkey": "unknown-hostkey", - "unknown-host": "unknown-host", - "invalid-hostkey": "invalid-hostkey", - "no-host": "change-port", -}); - -indexes.machines_index(options, machines_inst, loader, dialogs); - -var login_data = cockpit.localStorage.getItem('login-data', true); -if (login_data) { - var data = JSON.parse(login_data); - $("#content-user-name").text(data["displayName"]); -} diff --git a/pkg/shell/stub.html b/pkg/shell/stub.html deleted file mode 100644 index e776c0ccd..000000000 --- a/pkg/shell/stub.html +++ /dev/null @@ -1,192 +0,0 @@ - - - - Cockpit - - - - - - - - - - - -
- - - - - - - - - - -
- - -
- - - -
- -
- - - -
-
-
- - - - - diff --git a/po/po.empty.js b/po/po.empty.js index 9b645f6f7..d284890d5 100644 --- a/po/po.empty.js +++ b/po/po.empty.js @@ -13,47 +13,6 @@ loaded = true; } - function transformAngular(data, prev) { - var key, context, parts, value, result = { }; - for (key in data) { - if (key === "") - continue; - parts = key.split("\u0004"); - value = data[key]; - if (parts[1]) { - context = parts[0]; - key = parts[1]; - } else { - context = "$$noContext"; - key = parts[0]; - } - if (value[0] === null) - value = value[1]; - else - value = value.slice(1); - if (!(key in result)) - result[key] = { }; - result[key][context] = value; - } - return angular.extend(prev, result); - } - - /* Load into angular here */ - if (typeof angular === 'object') { - try { - module = angular.module(["gettext"]); - } catch(ex) { console.log(ex); /* Either no angular or angular-gettext */ }; - if (module) { - loaded = true; - module.run(['gettextCatalog', function(gettextCatalog) { - var lang = data[""]["language"]; - var prev = (gettextCatalog.getCurrentLanguage() == lang) ? gettextCatalog.strings : { }; - gettextCatalog.setStrings(lang, transformAngular(data, prev)); - gettextCatalog.setCurrentLanguage(lang); - }]); - } - } - if (!loaded) root.po = data; diff --git a/src/base1/Makefile.am b/src/base1/Makefile.am index 63066dbdc..337257880 100644 --- a/src/base1/Makefile.am +++ b/src/base1/Makefile.am @@ -120,7 +120,6 @@ base_QUNIT_TESTS = \ dist/base1/test-series.html \ dist/base1/test-cache.html \ dist/base1/test-websocket.html \ - dist/base1/test-stub.html \ dist/base1/test-browser-storage.html \ dist/base1/test-promise.html \ dist/base1/test-protocol.html \ diff --git a/src/base1/test-stub.js b/src/base1/test-stub.js deleted file mode 100644 index 5f50622b8..000000000 --- a/src/base1/test-stub.js +++ /dev/null @@ -1,207 +0,0 @@ -/* global $, cockpit, QUnit, WebSocket */ - -/* Tell cockpit to use an alternate url to connect to test-server */ -window.mock.url = cockpit.transport.uri(); -window.mock.url += "?cockpit-stub"; - -function internal_test(assert, options) { - let done = assert.async(); - assert.expect(2); - var dbus = cockpit.dbus(null, options); - dbus.call("/", "org.freedesktop.DBus.Introspectable", "Introspect") - .done(function(resp) { - assert.ok(String(resp[0]).indexOf(" 0, "unexpected error: " + ex.message); - assert.ok(ex.message.indexOf("/user") > 0, "unexpected error: " + ex.message); - }) - .always(function() { - assert.equal(this.state(), "rejected", "finished successfuly"); - done(); - }); -}); - -QUnit.test("not supported types", function (assert) { - let done = assert.async(); - var failures = 7; - var seen = 0; - assert.expect(failures); - - function failed(ev, ex) { - assert.equal(ex.problem, "not-supported", "not-supported"); - seen++; - if (failures == seen) - done(); - } - - var flist = cockpit.channel({ "payload":"fslist1", "path":"/foo" }); - $(flist).on("close", failed); - - var fwatch = cockpit.channel({ "payload":"fswatch1", "path":"/foo" }); - $(fwatch).on("close", failed); - - var file = cockpit.channel({ "payload":"fsread1", "path":"/foo" }); - $(file).on("close", failed); - - var freplace = cockpit.channel({ "payload":"fsreplace1", "path":"/foo" }); - $(freplace).on("close", failed); - - var spawn = cockpit.channel({ "payload":"stream", "spawn":["sh", "-c", "echo"] }); - $(spawn).on("close", failed); - - var dbus = cockpit.dbus("com.redhat.Cockpit.DBusTests.Test", { "bus": "session" }); - $(dbus).on("close", failed); - - var metrics = cockpit.channel({ payload: "metrics1", - interval: 1000, - source: "internal" }); - $(metrics).on("close", failed); - - window.setTimeout(function () { - done(); - }, 5000); -}); - -QUnit.test("external channel websocket", function (assert) { - let done = assert.async(); - assert.expect(3); - - var query = window.btoa(JSON.stringify({ - payload: "websocket-stream1", - address: "localhost", - port: parseInt(window.location.port, 10), - path: "/cockpit/echosocket/", - })); - - var count = 0; - var ws = new WebSocket("ws://" + window.location.host + "/cockpit/channel/" + - cockpit.transport.csrf_token + '?' + query); - ws.onopen = function() { - assert.ok(true, "websocket is open"); - ws.send("oh marmalade"); - }; - ws.onerror = function() { - assert.ok(false, "websocket error"); - }; - ws.onmessage = function(ev) { - if (count === 0) { - assert.equal(ev.data, "OH MARMALADE", "got payload"); - ws.send("another test"); - count += 1; - } else { - assert.equal(ev.data, "ANOTHER TEST", "got payload again"); - ws.close(1000); - } - }; - ws.onclose = function(ev) { - done(); - }; -}); - -QUnit.start(); diff --git a/src/bridge/Makefile.am b/src/bridge/Makefile.am index c13941c4b..ecc1f0e3c 100644 --- a/src/bridge/Makefile.am +++ b/src/bridge/Makefile.am @@ -1,55 +1,8 @@ noinst_LIBRARIES += \ - libcockpit-stub.a \ libcockpit-bridge.a \ $(NULL) -libcockpit_stub_a_SOURCES = \ - src/bridge/cockpitconnect.c \ - src/bridge/cockpitconnect.h \ - src/bridge/cockpitdbuscache.c \ - src/bridge/cockpitdbuscache.h \ - src/bridge/cockpitdbusinternal.h \ - src/bridge/cockpitdbusinternal.c \ - src/bridge/cockpitdbusjson.c \ - src/bridge/cockpitdbusjson.h \ - src/bridge/cockpitdbusprocess.c \ - src/bridge/cockpitdbusmeta.c \ - src/bridge/cockpitdbusmeta.h \ - src/bridge/cockpitdbusrules.c \ - src/bridge/cockpitdbusrules.h \ - src/bridge/cockpitechochannel.c \ - src/bridge/cockpitechochannel.h \ - src/bridge/cockpitpipechannel.c \ - src/bridge/cockpitpipechannel.h \ - src/bridge/cockpithttpstream.c \ - src/bridge/cockpithttpstream.h \ - src/bridge/cockpitinteracttransport.c \ - src/bridge/cockpitinteracttransport.h \ - src/bridge/cockpitpackages.c \ - src/bridge/cockpitpackages.h \ - src/bridge/cockpitpacketchannel.c \ - src/bridge/cockpitpacketchannel.h \ - src/bridge/cockpitpaths.c \ - src/bridge/cockpitpaths.h \ - src/bridge/cockpitpeer.c \ - src/bridge/cockpitpeer.h \ - src/bridge/cockpitnullchannel.c \ - src/bridge/cockpitnullchannel.h \ - src/bridge/cockpitrouter.c \ - src/bridge/cockpitrouter.h \ - src/bridge/cockpitstream.c \ - src/bridge/cockpitstream.h \ - src/bridge/cockpitwebsocketstream.c \ - src/bridge/cockpitwebsocketstream.h \ - $(NULL) - -libcockpit_stub_a_CFLAGS = \ - -I$(srcdir)/src/bridge \ - -DG_LOG_DOMAIN=\"cockpit-bridge\" \ - $(COCKPIT_CFLAGS) \ - $(NULL) - libcockpit_bridge_METRICS = \ src/bridge/cockpitblocksamples.c \ src/bridge/cockpitblocksamples.h \ @@ -76,19 +29,54 @@ libcockpit_bridge_METRICS = \ libcockpit_bridge_a_SOURCES = \ src/bridge/cockpitconnect.c \ src/bridge/cockpitconnect.h \ + src/bridge/cockpitdbuscache.c \ + src/bridge/cockpitdbuscache.h \ + src/bridge/cockpitdbusinternal.c \ + src/bridge/cockpitdbusinternal.h \ + src/bridge/cockpitdbusjson.c \ + src/bridge/cockpitdbusjson.h \ + src/bridge/cockpitdbusmachines.c \ + src/bridge/cockpitdbusmeta.c \ + src/bridge/cockpitdbusmeta.h \ + src/bridge/cockpitdbusprocess.c \ + src/bridge/cockpitdbusrules.c \ + src/bridge/cockpitdbusrules.h \ src/bridge/cockpitdbussetup.c \ src/bridge/cockpitdbususer.c \ - src/bridge/cockpitdbusmachines.c \ - src/bridge/cockpitpolkitagent.c \ - src/bridge/cockpitpolkitagent.h \ + src/bridge/cockpitechochannel.c \ + src/bridge/cockpitechochannel.h \ + src/bridge/cockpitfslist.c \ + src/bridge/cockpitfslist.h \ src/bridge/cockpitfsread.c \ src/bridge/cockpitfsread.h \ src/bridge/cockpitfsreplace.c \ src/bridge/cockpitfsreplace.h \ src/bridge/cockpitfswatch.c \ src/bridge/cockpitfswatch.h \ - src/bridge/cockpitfslist.c \ - src/bridge/cockpitfslist.h \ + src/bridge/cockpithttpstream.c \ + src/bridge/cockpithttpstream.h \ + src/bridge/cockpitinteracttransport.c \ + src/bridge/cockpitinteracttransport.h \ + src/bridge/cockpitnullchannel.c \ + src/bridge/cockpitnullchannel.h \ + src/bridge/cockpitpackages.c \ + src/bridge/cockpitpackages.h \ + src/bridge/cockpitpacketchannel.c \ + src/bridge/cockpitpacketchannel.h \ + src/bridge/cockpitpaths.c \ + src/bridge/cockpitpaths.h \ + src/bridge/cockpitpeer.c \ + src/bridge/cockpitpeer.h \ + src/bridge/cockpitpipechannel.c \ + src/bridge/cockpitpipechannel.h \ + src/bridge/cockpitpolkitagent.c \ + src/bridge/cockpitpolkitagent.h \ + src/bridge/cockpitrouter.c \ + src/bridge/cockpitrouter.h \ + src/bridge/cockpitstream.c \ + src/bridge/cockpitstream.h \ + src/bridge/cockpitwebsocketstream.c \ + src/bridge/cockpitwebsocketstream.h \ $(libcockpit_bridge_METRICS) \ $(NULL) @@ -98,16 +86,8 @@ libcockpit_bridge_a_CFLAGS = \ $(COCKPIT_BRIDGE_CFLAGS) \ $(NULL) -libcockpit_stub_LIBS = \ - libcockpit-stub.a \ - libcockpit-common.a \ - libwebsocket.a \ - $(COCKPIT_LIBS) \ - $(NULL) - libcockpit_bridge_LIBS = \ libcockpit-bridge.a \ - libcockpit-stub.a \ libcockpit-common.a \ libwebsocket.a \ $(COCKPIT_BRIDGE_LIBS) \ @@ -135,16 +115,6 @@ cockpit_askpass_CFLAGS = \ $(NULL) cockpit_askpass_LDADD = $(libcockpit_bridge_LIBS) -libexec_PROGRAMS += cockpit-stub - -cockpit_stub_SOURCES = src/bridge/stub.c -cockpit_stub_CFLAGS = \ - -I$(srcdir)/src/bridge \ - -DG_LOG_DOMAIN=\"cockpit-bridge\" \ - $(COCKPIT_CFLAGS) \ - $(NULL) -cockpit_stub_LDADD = $(libcockpit_stub_LIBS) - EXTRA_DIST += \ src/bridge/cockpit.pam.insecure \ $(NULL) diff --git a/src/bridge/stub.c b/src/bridge/stub.c deleted file mode 100644 index 4d0c0bf8c..000000000 --- a/src/bridge/stub.c +++ /dev/null @@ -1,345 +0,0 @@ -/* - * This file is part of Cockpit. - * - * Copyright (C) 2015 Red Hat, Inc. - * - * Cockpit is free software; you can redistribute it and/or modify it - * under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation; either version 2.1 of the License, or - * (at your option) any later version. - * - * Cockpit is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with Cockpit; If not, see . - */ -#include "config.h" - -#include "cockpitdbusinternal.h" -#include "cockpitdbusjson.h" -#include "cockpitechochannel.h" -#include "cockpitinteracttransport.h" -#include "cockpithttpstream.h" -#include "cockpitnullchannel.h" -#include "cockpitpackages.h" -#include "cockpitrouter.h" -#include "cockpitwebsocketstream.h" - -#include "common/cockpittransport.h" -#include "common/cockpitassets.h" -#include "common/cockpitchannel.h" -#include "common/cockpitjson.h" -#include "common/cockpitlog.h" -#include "common/cockpitpipetransport.h" -#include "common/cockpittest.h" -#include "common/cockpitunixfd.h" -#include "common/cockpitwebresponse.h" - -#include -#include -#include -#include - -#include -#include - -/* This program is meant to be used in place of cockpit-bridge - * in non-system setting. As such only payloads that make no changes - * to the system or support their own forms of authentication (ei: http) - * should be included here. - */ - -static CockpitPackages *packages = NULL; - -extern gboolean cockpit_dbus_json_allow_external; - -static CockpitPayloadType payload_types[] = { - { "http-stream1", cockpit_http_stream_get_type }, - { "http-stream2", cockpit_http_stream_get_type }, - { "null", cockpit_null_channel_get_type }, - { "echo", cockpit_echo_channel_get_type }, - { "websocket-stream1", cockpit_web_socket_stream_get_type }, - { "dbus-json3", cockpit_dbus_json_get_type }, - { NULL }, -}; - -static void -on_closed_set_flag (CockpitTransport *transport, - const gchar *problem, - gpointer user_data) -{ - gboolean *flag = user_data; - *flag = TRUE; -} - -static void -send_init_command (CockpitTransport *transport, - gboolean interactive) -{ - const gchar *checksum; - JsonObject *object; - GBytes *bytes; - - object = json_object_new (); - json_object_set_string_member (object, "command", "init"); - json_object_set_int_member (object, "version", 1); - - /* - * When in interactive mode pretend we received an init - * message, and don't print one out. - */ - if (interactive) - { - json_object_set_string_member (object, "host", "localhost"); - } - else - { - checksum = cockpit_packages_get_checksum (packages); - if (checksum) - json_object_set_string_member (object, "checksum", checksum); - } - - bytes = cockpit_json_write_bytes (object); - json_object_unref (object); - - if (interactive) - cockpit_transport_emit_recv (transport, NULL, bytes); - else - cockpit_transport_send (transport, NULL, bytes); - g_bytes_unref (bytes); -} - -static gboolean -on_signal_done (gpointer data) -{ - gboolean *closed = data; - *closed = TRUE; - return TRUE; -} - -static CockpitRouter * -setup_router (CockpitTransport *transport) -{ - CockpitRouter *router = NULL; - GList *bridges = NULL; - - packages = cockpit_packages_new (); - bridges = cockpit_packages_get_bridges (packages); - router = cockpit_router_new (transport, payload_types, bridges); - g_list_free (bridges); - return router; -} - -static int -run_bridge (const gchar *interactive) -{ - CockpitTransport *transport; - CockpitRouter *router; - gboolean terminated = FALSE; - gboolean interupted = FALSE; - gboolean closed = FALSE; - guint sig_term; - guint sig_int; - int outfd; - - cockpit_set_journal_logging (G_LOG_DOMAIN, !isatty (2)); - - /* - * This process talks on stdin/stdout. However lots of stuff wants to write - * to stdout, such as g_debug, and uses fd 1 to do that. Reroute fd 1 so that - * it goes to stderr, and use another fd for stdout. - */ - - outfd = dup (1); - if (outfd < 0 || dup2 (2, 1) < 1) - { - g_warning ("bridge couldn't redirect stdout to stderr"); - if (outfd > -1) - close (outfd); - outfd = 1; - } - - sig_term = g_unix_signal_add (SIGTERM, on_signal_done, &terminated); - sig_int = g_unix_signal_add (SIGINT, on_signal_done, &interupted); - - cockpit_dbus_json_allow_external = FALSE; - - cockpit_dbus_internal_startup (interactive != NULL); - - if (interactive) - { - transport = cockpit_interact_transport_new (0, outfd, interactive); - } - else - { - transport = cockpit_pipe_transport_new_fds ("stdio", 0, outfd); - } - - g_resources_register (cockpitassets_get_resource ()); - cockpit_web_failure_resource = "/org/cockpit-project/Cockpit/fail.html"; - - /* Set a path if nothing is set */ - g_setenv ("PATH", "/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin", 0); - - router = setup_router (transport); - cockpit_dbus_process_startup (); - - g_signal_connect (transport, "closed", G_CALLBACK (on_closed_set_flag), &closed); - send_init_command (transport, interactive ? TRUE : FALSE); - - while (!terminated && !closed && !interupted) - g_main_context_iteration (NULL, TRUE); - - g_object_unref (router); - g_object_unref (transport); - - g_source_remove (sig_term); - g_source_remove (sig_int); - - /* So the caller gets the right signal */ - if (terminated) - raise (SIGTERM); - - return 0; -} - -static void -print_rules (void) -{ - CockpitRouter *router = NULL; - CockpitTransport *transport = cockpit_interact_transport_new (0, 1, "--"); - - router = setup_router (transport); - - cockpit_router_dump_rules (router); - - g_object_unref (router); - g_object_unref (transport); -} - -static void -print_version (void) -{ - gint i, offset, len; - - g_print ("Version: %s\n", PACKAGE_VERSION); - g_print ("Protocol: 1\n"); - - g_print ("Payloads: "); - offset = 10; - for (i = 0; payload_types[i].name != NULL; i++) - { - len = strlen (payload_types[i].name); - if (offset + len > 70) - { - g_print ("\n"); - offset = 0; - } - - if (offset == 0) - { - g_print (" "); - offset = 4; - }; - - g_print ("%s ", payload_types[i].name); - offset += len + 1; - } -} - -int -main (int argc, - char **argv) -{ - GOptionContext *context; - GError *error = NULL; - int ret; - - static gboolean opt_packages = FALSE; - static gboolean opt_rules = FALSE; - static gboolean opt_version = FALSE; - static gchar *opt_interactive = NULL; - - static GOptionEntry entries[] = { - { "interact", 0, 0, G_OPTION_ARG_STRING, &opt_interactive, "Interact with the raw protocol", "boundary" }, - { "packages", 0, 0, G_OPTION_ARG_NONE, &opt_packages, "Show Cockpit package information", NULL }, - { "rules", 0, 0, G_OPTION_ARG_NONE, &opt_rules, "Show Cockpit bridge rules", NULL }, - { "version", 0, 0, G_OPTION_ARG_NONE, &opt_version, "Show Cockpit version information", NULL }, - { NULL } - }; - - signal (SIGPIPE, SIG_IGN); - - /* Debugging issues during testing */ -#if WITH_DEBUG - signal (SIGABRT, cockpit_test_signal_backtrace); - signal (SIGSEGV, cockpit_test_signal_backtrace); -#endif - - g_setenv ("GSETTINGS_BACKEND", "memory", TRUE); - g_setenv ("GIO_USE_PROXY_RESOLVER", "dummy", TRUE); - g_setenv ("GIO_USE_VFS", "local", TRUE); - - /* - * All channels that are added here should - * not rely on running as a real user, however - * they may lookup paths, such as run dir or - * home directory. Glib has problems if - * g_get_user_database_entry is called without - * a real user, which it's path functions - * do as a last resort when no environment vars - * are set. So set HOME if it isn't set.. - */ - g_setenv("HOME", "/", FALSE); - - - context = g_option_context_new (NULL); - g_option_context_add_main_entries (context, entries, NULL); - g_option_context_set_description (context, - "cockpit-stub provides a limited number of channels and is meant to be" - "used in place of cockpit-bridge in non-system setting. When\n" - "run from the command line one of the options above must be specified.\n"); - - g_option_context_parse (context, &argc, &argv, &error); - g_option_context_free (context); - - if (error) - { - g_printerr ("cockpit-stub: %s\n", error->message); - g_error_free (error); - return 1; - } - - if (opt_packages) - { - cockpit_packages_dump (); - return 0; - } - else if (opt_rules) - { - print_rules (); - return 0; - } - else if (opt_version) - { - print_version (); - return 0; - } - - if (!opt_interactive && isatty (1)) - { - g_printerr ("cockpit-stub: no option specified\n"); - return 2; - } - - ret = run_bridge (opt_interactive); - - if (packages) - cockpit_packages_free (packages); - - g_free (opt_interactive); - return ret; -} diff --git a/test/common/cdp-driver.js b/test/common/cdp-driver.js index 47696515b..be45f7bce 100755 --- a/test/common/cdp-driver.js +++ b/test/common/cdp-driver.js @@ -91,12 +91,6 @@ function setupLogging(client) { process.stderr.write(details.description || JSON.stringify(details) + "\n"); - // ignore c3 crashes (https://github.com/c3js/c3/issues/2187) - if (details.exception && details.exception.description && - details.exception.description.indexOf("TypeError: Cannot read property 'data_types' of null") >= 0 && - details.exception.description.indexOf("/kubernetes.js") >= 0) - return; - unhandledExceptions.push(details.exception.message || details.exception.description || details.exception.value || diff --git a/test/image-prepare b/test/image-prepare index cab6a69ea..ce911fa43 100755 --- a/test/image-prepare +++ b/test/image-prepare @@ -129,9 +129,7 @@ def run_install_script(machine, do_build, do_install, skips, arg, args): do_install = False skips = list(skips or []) - if "atomic" in machine.image: - skips.append("cockpit-kubernetes") - else: + if "atomic" not in machine.image: skips.append("cockpit-ostree") skip_args = [" --skip '%s'" % skip for skip in skips] diff --git a/test/verify/check-kubernetes b/test/verify/check-kubernetes deleted file mode 100755 index 489644a96..000000000 --- a/test/verify/check-kubernetes +++ /dev/null @@ -1,282 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- - -# This file is part of Cockpit. -# -# Copyright (C) 2015 Red Hat, Inc. -# -# Cockpit is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# Cockpit is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Cockpit; If not, see . - -import unittest - -import parent - -import kubelib -from testlib import * - - -@skipImage("No kubernetes packaged", "debian-stable", "debian-testing", "ubuntu-1804", - "ubuntu-stable", "fedora-i386", "rhel-7-6", "rhel-7-6-distropkg", "rhel-7-7", "rhel-8-0", "rhel-8-0-distropkg", "rhel-8-1", "centos-7") -@skipImage("No cockpit-kubernetes packaged", "continuous-atomic", "fedora-atomic", "rhel-atomic", "fedora-30", "fedora-testing") -@skipPackage("cockpit-kubernetes") -class TestKubernetes(kubelib.KubernetesCase, kubelib.KubernetesCommonTests): - - def setUp(self): - kubelib.KubernetesCase.setUp(self) - m = self.machine - - self.start_kubernetes() - - m.upload(["verify/files/mock-k8s-tiny-app.json"], "/tmp") - self.wait_api_server() - # HACK: https://github.com/cockpit-project/cockpit/issues/9179 ; fixed - # in docker-images.setup, drop this after all images got rebuilt - m.execute("docker tag gcr.io/google_containers/pause-amd64:3.0 k8s.gcr.io/pause-amd64:3.1 || true") - - -@skipImage("No kubernetes packaged", "debian-stable", "debian-testing", "ubuntu-1804", - "ubuntu-stable", "fedora-i386", "rhel-7-6", "rhel-7-6-distropkg", "rhel-7-7", "rhel-8-0", "rhel-8-0-distropkg", "rhel-8-1", "centos-7") -@skipImage("No cockpit-kubernetes packaged", "continuous-atomic", "fedora-atomic", "rhel-atomic", "fedora-30", "fedora-testing") -@skipPackage("cockpit-kubernetes") -class TestConnection(kubelib.KubernetesCase): - - def testConnect(self): - m = self.machine - b = self.browser - - # Connect without starting a kube server - self.login_and_go("/kubernetes") - b.wait_in_text(".curtains-ct", "Couldn't connect to server") - b.wait_in_text(".curtains-ct", "Couldn't find running API server") - self.assertIn("Reconnect", b.text("#kubernetes-reconnect")) - - # Start a kube-apiserver with a 'wrong' http port, forcing use of https - m.execute("echo 'KUBE_API_PORT=\"--port=1111\"' >> /etc/kubernetes/apiserver") - m.execute("sed -i s/8080/1111/g /etc/kubernetes/*") - self.start_kubernetes() - - # Setup the kube stuff in the right place - m.upload(["verify/files/mock-kube-config-basic.json"], "/tmp") - m.execute("mkdir -p /home/admin/.kube/ && mv /tmp/mock-kube-config-basic.json /home/admin/.kube/config") - - # Click the Reconnect button - b.click("#kubernetes-reconnect") - b.wait_in_text("#node-list", "127.0.0.1") - b.logout() - - # Check that this failed as a double check - output = m.execute("curl -sS http://10.111.113.1:8080/api 2>&1 || true") - self.assertIn("Connection refused", output) - - # Check that this failed as a double check - output = m.execute("curl -k -sS https://10.111.113.1:6443/api 2>&1 || true") - self.assertRegex(output, "Unauthorized|No policy matched|Forbidden") - - m.execute("rm -r /home/admin/.kube") - self.login_and_go("/kubernetes") - - b.wait_present(".curtains-ct") - b.click("#kubernetes-connection-tb") - - b.wait_present("modal-dialog") - b.wait_in_text("div.modal-footer div.dialog-error", "Connection Error:") - b.wait_present("#kubernetes-address") - b.wait_present("#kubernetes-cluster") - b.wait_not_present("#kubernetes-user") - - b.wait_present("#kubernetes-cluster ul.dropdown-menu") - b.wait_in_text("#kubernetes-cluster button", "Add New Cluster") - - b.click("#kubernetes-requires-auth") - b.wait_present("#kubernetes-user") - b.wait_present("#kubernetes-username") - b.wait_in_text("#kubernetes-user button", "Add New User") - b.set_val("#kubernetes-address", "") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_present("#kubernetes-address + div.dialog-error") - b.wait_present("#kubernetes-username + div.dialog-error") - - b.set_val("#kubernetes-address", "https://10.111.113.1:6443") - b.set_val("#kubernetes-username", "bad") - b.set_val("#kubernetes-password", "password") - - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_present("modal-dialog input[value='pem']") - b.wait_present("modal-dialog input[value='skip']") - b.wait_in_text("modal-dialog pre", "Certificate:") - b.click("modal-dialog input[value='pem']") - b.click("modal-dialog div.modal-footer button.btn-primary") - - b.wait_present("#kubernetes-address") - b.wait_present("#kubernetes-user") - b.wait_in_text("div.modal-footer div.dialog-error", "Connection Error:") - - # Data not saved - b.wait_in_text("#kubernetes-cluster button", "Add New Cluster") - b.wait_in_text("#kubernetes-user button", "Add New User") - - # Form is - b.wait_val("#kubernetes-address", "https://10.111.113.1:6443") - b.wait_present("#kubernetes-requires-auth:checked") - b.wait_val("#kubernetes-username", "bad") - - b.set_val("#kubernetes-username", "admin") - b.set_val("#kubernetes-password", "fubar") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - b.wait_in_text("#node-list", "127.0.0.1") - - b.wait_not_present("#kubernetes-change-connection") - - # Temp certificate isn't saved - b.reload() - b.enter_page("/kubernetes") - b.wait_present(".curtains-ct") - b.click("#kubernetes-connection-tb") - - b.wait_present("modal-dialog input[value='pem']") - b.click("modal-dialog input[value='skip']") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - b.wait_in_text("#node-list", "127.0.0.1") - - # Reload works - b.reload() - b.enter_page("/kubernetes") - b.wait_in_text("#node-list", "127.0.0.1") - - # Changing works - b.click("#kubernetes-change-connection") - b.wait_present("modal-dialog") - b.wait_present("#kubernetes-cluster") - b.wait_present("#kubernetes-user") - - b.wait_in_text("#kubernetes-cluster button", "10-111-113-1:6443") - b.wait_in_text("#kubernetes-user button", "admin/10-111-113-1:6443") - - b.wait_val("#kubernetes-address", "https://10.111.113.1:6443") - b.wait_present("#kubernetes-requires-auth:checked") - b.wait_val("#kubernetes-username", "admin") - b.wait_present("#kubernetes-skip-verify:checked") - - b.set_val("#kubernetes-address", "https://10.111.113.1:6443") - b.set_val("#kubernetes-username", "scruffy") - b.set_val("#kubernetes-password", "scruffy") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - # Changes took and dropdowns work - b.click("#kubernetes-change-connection") - b.wait_present("modal-dialog") - b.wait_present("#kubernetes-cluster") - b.wait_present("#kubernetes-user") - - b.wait_in_text("#kubernetes-cluster button", "10-111-113-1:6443") - b.click("#kubernetes-cluster button") - b.click("#kubernetes-cluster ul li:last-child a") - b.wait_in_text("#kubernetes-cluster button", "Add New Cluster") - b.wait_val("#kubernetes-address", "") - b.wait_present("#kubernetes-skip-verify:not(:checked)") - - b.click("#kubernetes-cluster button") - b.click("#kubernetes-cluster ul li:first-child a") - b.wait_in_text("#kubernetes-cluster button", "10-111-113-1:6443") - b.wait_val("#kubernetes-address", "https://10.111.113.1:6443") - b.wait_present("#kubernetes-requires-auth:checked") - b.wait_present("#kubernetes-skip-verify:checked") - - b.wait_in_text("#kubernetes-user button", "admin/10-111-113-1:6443") - b.wait_val("#kubernetes-username", "scruffy") - b.click("#kubernetes-user button") - b.click("#kubernetes-user ul li:last-child a") - b.wait_in_text("#kubernetes-user button", "Add New User") - b.wait_val("#kubernetes-username", "") - b.wait_val("#kubernetes-password", "") - b.click("#kubernetes-user button") - b.click("#kubernetes-user ul li:first-child a") - b.wait_in_text("#kubernetes-user button", "admin/10-111-113-1:6443") - b.wait_val("#kubernetes-username", "scruffy") - b.wait_val("#kubernetes-password", "scruffy") - - b.click("modal-dialog div.modal-footer button.btn-cancel") - b.wait_not_present("modal-dialog") - - b.wait_in_text("#node-list", "127.0.0.1") - - self.allow_journal_messages(".*: couldn't connect: Connection refused", - ".*: Unacceptable TLS certificate.*", - ".*: Connection reset by peer.*", - "connection unexpectedly closed by peer", - ".*: Error sending data: Broken pipe.*") - - -@skipImage("No kubernetes packaged", "debian-stable", "debian-testing", "ubuntu-1804", - "ubuntu-stable", "fedora-i386", "rhel-7-6", "rhel-7-6-distropkg", "rhel-7-7", "rhel-8-0", "rhel-8-0-distropkg", "rhel-8-1", "centos-7") -@unittest.skipIf(True, "Nulecule deploys temporarily removed.") -@skipPackage("cockpit-kubernetes") -class TestNulecule(kubelib.KubernetesCase): - - def setUp(self): - kubelib.KubernetesCase.setUp(self) - - self.start_kubernetes() - self.wait_api_server() - - def testDeployDialog(self): - b = self.browser - m = self.machine - - self.login_and_go("/kubernetes") - b.wait_in_text("#node-list", "127.0.0.1") - - # 1)check atomic version - output = m.execute("atomic -v 2>&1") - self.assertTrue(float(output) >= 1.1) - - # 2) fail invalid image - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "submod/helloapache1") - b.set_val("#deploy-app-namespace", "mynamespace") - b.dialog_complete("#deploy-app-dialog", result="fail") - b.dialog_cancel("#deploy-app-dialog") - - # 3) pass when valid image - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "submod/helloapache:0.1.11") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - self.allow_journal_messages('Could not find any image matching "submod/helloapache:0.1.11".') - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.dialog_cancel("#deploy-app-dialog") - - # 4) fail when atomic is not installed - m.needs_writable_usr() - m.execute("rm /usr/bin/atomic") - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "submod/helloapache") - b.set_val("#deploy-app-namespace", "mynamespace") - b.dialog_complete("#deploy-app-dialog", result="fail") - b.dialog_cancel("#deploy-app-dialog") - - -if __name__ == '__main__': - test_main() diff --git a/test/verify/check-openshift b/test/verify/check-openshift deleted file mode 100755 index 232188b4f..000000000 --- a/test/verify/check-openshift +++ /dev/null @@ -1,401 +0,0 @@ -#!/usr/bin/python3 -# -*- coding: utf-8 -*- - -# This file is part of Cockpit. -# -# Copyright (C) 2015 Red Hat, Inc. -# -# Cockpit is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# Cockpit is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Cockpit; If not, see . - -import os -import unittest - -import parent -from kubelib import * -from testlib import * - - -# NOTE: Both TestOpenshift and TestRegistry are in this single file to -# prevent them from being run concurrently. Both use a 'openshift' -# machine, and we can only run a single one of those at the same time. - -base_dir = os.path.dirname(os.path.realpath(__file__)) - - -def wait_healthz(openshift): - # Openshift prints "ok" on /healthz/ready when it's ready - healthz = "curl -sk --stderr - https://localhost:8443/healthz/ready || true" - wait(lambda: "ok" == openshift.execute(healthz), delay=5, tries=150) - - -@skipImage("Kubernetes not packaged", "debian-stable", "debian-testing", "ubuntu-1804", "ubuntu-stable", "fedora-i386") -@skipImage("No cockpit-kubernetes packaged", "continuous-atomic", "fedora-atomic", "rhel-atomic", "rhel-8-0", "rhel-8-0-distropkg", "rhel-8-1", "fedora-30", "fedora-testing") -class TestOpenshift(MachineCase, OpenshiftCommonTests): - provision = { - "machine1": {"address": "10.111.113.1/20"}, - "openshift": {"image": "openshift", "forward": {30000: 30000, 8443: 8443}} - } - - def setUp(self): - super(TestOpenshift, self).setUp() - - self.openshift = self.machines['openshift'] - self.openshift.upload(["verify/files/mock-app-openshift.json"], "/tmp") - self.kubeconfig = os.path.join(self.tmpdir, "config") - self.openshift.download("/root/.kube/config", self.kubeconfig) - - m = self.machine - m.execute("mkdir -p /home/admin/.kube") - m.upload([self.kubeconfig], "/home/admin/.kube/config") - m.execute("chown -R admin:admin /home/admin/.kube") - - wait_healthz(self.openshift) - wait(lambda: "marmalade" in self.openshift.execute("oc get projects"), delay=5) - - self.openshift.execute("oc project default") - - # Expect the default container user limitations during testing - self.openshift.execute( - "oc patch securitycontextconstraints restricted -p '{ \"runAsUser\": { \"type\": \"MustRunAsRange\" } }'") - - self.browser.wait_timeout(120) - - # This happens with docker restarts and during startup polling - self.allow_journal_messages('.*received truncated HTTP response.*') - self.allow_journal_messages(".*api/.*couldn't connect.*") - - def testConnect(self): - m = self.machine - b = self.browser - - # Make sure we can write to kubeconfig - m.execute("chown -R admin:admin /home/admin/.kube") - self.login_and_go("/kubernetes") - - b.wait_in_text("#service-list", "docker-registry") - b.click("a[href='#/volumes']") - b.wait_in_text(".pv-listing", "No volumes are present") - b.click("a[href='#/']") - - b.click("#kubernetes-change-connection") - b.wait_present("modal-dialog") - b.wait_present("#kubernetes-cluster") - b.wait_not_present("#kubernetes-username") - b.wait_not_present("#kubernetes-password") - b.wait_not_present("#kubernetes-token") - - b.wait_in_text("#kubernetes-cluster button", "10-111-112-101:8443") - b.wait_in_text("#kubernetes-user button", "system:admin/10-111-112-101:8443") - b.wait_in_text("modal-dialog .modal-body", "Client Certificate") - - b.click("#kubernetes-user button") - b.click("#kubernetes-user ul li:last-child a") - b.wait_in_text("#kubernetes-user button", "Add New User") - b.wait_not_present("#kubernetes-token") - b.wait_val("#kubernetes-username", "") - b.wait_val("#kubernetes-password", "") - b.set_val("#kubernetes-username", "new-user") - b.set_val("#kubernetes-password", "new-user") - - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - # scruffy isn't a admin - b.wait_not_in_text("#service-list", "docker-registry") - b.click("a[href='#/volumes']") - b.wait_in_text(".pv-listing", "cannot watch all") - b.click("a[href='#/']") - - b.click("#kubernetes-change-connection") - b.wait_present("modal-dialog") - b.wait_present("#kubernetes-cluster") - b.wait_not_present("#kubernetes-username") - b.wait_not_present("#kubernetes-password") - b.wait_present("#kubernetes-token") - - b.wait_in_text("#kubernetes-cluster button", "10-111-112-101:8443") - b.wait_in_text("#kubernetes-user button", "new-user/10-111-112-101:8443") - b.wait_not_in_text("modal-dialog .modal-body", "Client Certificate") - self.assertFalse(b.val("#kubernetes-token") == "") - - b.logout() - - # Test the saved kube config file - m.execute("rm /home/admin/.kube/config") - m.upload([self.kubeconfig], "/home/admin/.kube/config") - m.execute("chown -R admin:admin /home/admin/.kube") - - self.login_and_go("/kubernetes") - - b.wait_in_text("#service-list", "docker-registry") - - @unittest.skipIf(True, "Nulecule deploys temporarily removed.") - def testDeployDialog(self): - b = self.browser - m = self.machine - b.wait_timeout(240) - m.execute("systemctl start docker") - # m.execute("docker pull submod/helloapache") - tmpfile = os.path.join(self.tmpdir, "oc") - self.openshift.download("/usr/bin/oc", tmpfile) - m.upload([tmpfile], "/usr/local/bin") - - self.login_and_go("/kubernetes") - b.wait_in_text("#service-list", "registry") - - # 1)check atomic version - output = m.execute("atomic -v 2>&1") - self.assertTrue(float(output) >= 1.1) - - # 2)check provider is supported - m.execute("mkdir /var/tmp/invalid-app1") - m.execute("""echo -e ' -FROM busybox -MAINTAINER cockpit -LABEL io.projectatomic.nulecule.atomicappversion="0.1.11" \ - RUN="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} run \${OPT3} /atomicapp" \ - STOP="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} stop \${OPT3} /atomicapp" \ - INSTALL="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} install \${OPT3} --destination /atomicapp /application-entity" \ - io.projectatomic.nulecule.providers="kubernetes" \ - io.projectatomic.nulecule.specversion=0.0.2 \ - io.projectatomic.nulecule.atomicappversion="0.1.11" -' > /var/tmp/invalid-app1/Dockerfile""") - m.execute("docker build -t test/invalid-app1 /var/tmp/invalid-app1") - m.execute("rm -rf /var/tmp/invalid-app1") - - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "test/invalid-app1") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.is_visible(".modal-footer .alert") - self.assertEqual(b.text(".modal-footer .alert"), "No supported providers found.") - b.dialog_cancel("#deploy-app-dialog") - - # 3)check atomicappversion is supported - m.execute("mkdir /var/tmp/invalid-app2") - m.execute("""echo -e ' -FROM busybox -MAINTAINER cockpit -LABEL io.projectatomic.nulecule.atomicappversion="0.1.11" \ - RUN="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} run \${OPT3} /atomicapp" \ - STOP="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} stop \${OPT3} /atomicapp" \ - INSTALL="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} install \${OPT3} --destination /atomicapp /application-entity" \ - io.projectatomic.nulecule.providers="kubernetes,openshift" \ - io.projectatomic.nulecule.specversion=0.0.2 \ - io.projectatomic.nulecule.atomicappversion="0.0.11" -' > /var/tmp/invalid-app2/Dockerfile""") - m.execute("docker build -t test/invalid-app2 /var/tmp/invalid-app2") - m.execute("rm -rf /var/tmp/invalid-app2") - - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "test/invalid-app2") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.is_visible(".modal-footer .alert") - self.assertEqual(b.text(".modal-footer .alert"), "atomicapp version 0.0.11 is not supported.") - b.dialog_cancel("#deploy-app-dialog") - - # 5)check for all metadata - m.execute("mkdir /var/tmp/invalid-app4") - m.execute("""echo -e ' -FROM busybox -MAINTAINER cockpit -LABEL io.projectatomic.nulecule.providers="kubernetes,openshift" -' > /var/tmp/invalid-app4/Dockerfile""") - m.execute("docker build -t test/invalid-app4 /var/tmp/invalid-app4") - m.execute("rm -rf /var/tmp/invalid-app4") - - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "test/invalid-app4") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.is_visible(".modal-footer .alert") - self.assertEqual(b.text(".modal-footer .alert"), "This image is not a supported Nulecule image") - b.dialog_cancel("#deploy-app-dialog") - - # 6)check when atomicapp is not available - m.execute("mkdir /var/tmp/invalid-app5") - m.execute("""echo -e ' -FROM busybox -MAINTAINER cockpit -LABEL io.projectatomic.nulecule.atomicappversion="0.1.11" \ - RUN="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} run \${OPT3} /atomicapp" \ - STOP="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run -v /:/host --net=host --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} stop \${OPT3} /atomicapp" \ - INSTALL="docker run -it --rm \${OPT1} --privileged -v `pwd`:/atomicapp -v /run:/run --name \${NAME} -e NAME=\${NAME} -e IMAGE=\${IMAGE} \${IMAGE} -v \${OPT2} install \${OPT3} --destination /atomicapp /application-entity" \ - io.projectatomic.nulecule.providers="kubernetes,openshift" \ - io.projectatomic.nulecule.specversion=0.0.2 \ - io.projectatomic.nulecule.atomicappversion="0.1.11" -' > /var/tmp/invalid-app5/Dockerfile""") - m.execute("docker build -t test/invalid-app5 /var/tmp/invalid-app5") - m.execute("rm -rf /var/tmp/invalid-app5") - - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "test/invalid-app5") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.is_visible(".modal-footer .alert") - self.assertEqual(b.text(".modal-footer .alert"), "Image failed to install.") - b.dialog_cancel("#deploy-app-dialog") - - # 7) fail when Unable to pull Nulecule app - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "submod/helloapache1") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.is_visible(".modal-footer .alert") - self.assertEqual(b.text(".modal-footer .alert"), "Unable to pull Nulecule app image.") - b.dialog_cancel("#deploy-app-dialog") - - # 8) check if app can be deployed - b.click("#deploy-app") - b.wait_popup("deploy-app-dialog") - b.set_val("#deploy-app-type", "nulecule") - b.set_val("#deploy-app-nulecule-image", "submod/helloapache:0.1.11") - b.set_val("#deploy-app-namespace", "mynamespace") - b.click("#deploy-app-start") - self.allow_journal_messages('Could not find any image matching "submod/helloapache:0.1.11".') - b.wait_not_attr("#deploy-app-start", "disabled", "disabled") - b.click("#deploy-app-start") - b.wait_popdown("deploy-app-dialog") - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present(".details-listing tbody[data-id='pods/default/helloapache'] th") - self.assertEqual(b.text(".details-listing tbody[data-id='pods/default/helloapache'] th"), "helloapache") - - def testReconnectChangeCert(self): - m = self.machine - b = self.browser - - # Try to connect with an old and non-matching client cert - old_cert = ('LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUREVENDQWZXZ0F3SUJBZ0lCQnpBTkJna3Foa2' - 'lHOXcwQkFRc0ZBREFtTVNRd0lnWURWUVFEREJ0dmNHVnUKYzJocFpuUXRjMmxuYm1WeVFERTBPVEEy' - 'T0RFMk16RXdIaGNOTVRjd016STRNRFl4TXpVeVdoY05NVGt3TXpJNApNRFl4TXpVeldqQTNNUjR3SE' - 'FZRFZRUUtFeFZ6ZVhOMFpXMDZZMngxYzNSbGNpMWhaRzFwYm5NeEZUQVRCZ05WCkJBTVRESE41YzNS' - 'bGJUcGhaRzFwYmpDQ0FTSXdEUVlKS29aSWh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUIKQU5Rel' - 'J5SzUzQUhmdlZnME5GTHRSSENhMTEyK3l5a0xXdG14bjAxb2JTMy85VmovQU1UdmZwNVRkUlhKNjF' - 'WcAo3L0N1L1pkQ3RDc1pyNnJpYVMxbUJGcmtTSkZJdmFjN2NNa3k2M0tVVXNaQmU5ZGFLdG1OMmhY' - 'TUt0VitESStvCjJFQVJNWlV5YTZIMzJXZUpzRGM0L1lscUR5TFAxYVR3NWNwRTJPY3dWQTdoQ1dCS' - 'ysyajIvZTl6RDhrYzM2R24KNG0wZWd3YWxlZ2UwTXFaUk1BbTFkenRpS3I1UWZ4MG9ZVUY3Z0JIYm' - 'RjM253cGZ6a3M2K1F4Tkl6V0hlRmN2WApxcXpsMGxnT2ZGeWc0VWptYzhFcTBiKy9ER3lYSGlHNXN' - 'vVmw1RGlVa1RKRjNrcURCZVVjZWNZaEx1VDd4emxzClk0bldYVFprc3lJMXVoZFJmS2NnbVZjQ0F3' - 'RUFBYU0xTURNd0RnWURWUjBQQVFIL0JBUURBZ1dnTUJNR0ExVWQKSlFRTU1Bb0dDQ3NHQVFVRkJ3T' - 'UNNQXdHQTFVZEV3RUIvd1FDTUFBd0RRWUpLb1pJaHZjTkFRRUxCUUFEZ2dFQgpBRy9rTElnQ2YwK2' - '1MZ1VXcWZjS2NLN0Nmdm9PbS9qL0FUSW1MR0YvSUtvQTRCWGhqMG5EcEszeVd3ZGt4d0hZCmxxUDh' - 'xZ1NyQ1FaNkVoSlpMSWtjQWovTUlTUEUvSlJPa3R5TWFTMis4OGhqeGpxdUhucnZ5ODA5ZlJ5QzhF' - 'R2kKeVIyRzhtNGJ5MEJrOWhENkVxbDYxb21VU0MzL2ozR3lPUGNZWDJEQjZsU2h4ZlFJVEpqUWNKQ' - '0oyMnNDdlBBOApVeU9EaUgrNllZSVdtVFN5a2kzazk0Q3NOZXlRbERjNzh3a1BseUdrN0p1anFIK2p' - 'KaURXSDQ2TXE3TTNaVVArCmowQWxhd3dtdllsRjBVZEIwdGRCenZWR21RbTRudEwwSkhVMGFqRnUy' - 'QTYvTjJmT3VrZWI0TDR6elBzSkJFNHIKaUUyNWRJUlAvWHRoM0tjRFYyYkxtMUk9Ci0tLS0tRU5EI' - 'ENFUlRJRklDQVRFLS0tLS0K') - old_key = ('LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcEFJQkFBS0NBUUVBMUROSElybmNBZC' - 's5V0RRMFV1MUVjSnJYWGI3TEtRdGEyYkdmVFdodExmLzFXUDhBCnhPOStubE4xRmNuclZXbnY4Szc5' - 'bDBLMEt4bXZxdUpwTFdZRVd1UklrVWk5cHp0d3lUTHJjcFJTeGtGNzExb3EKMlkzYUZjd3ExWDRNa' - 'jZqWVFCRXhsVEpyb2ZmWlo0bXdOemo5aVdvUElzL1ZwUERseWtUWTV6QlVEdUVKWUVyNwphUGI5Nz' - 'NNUHlSemZvYWZpYlI2REJxVjZCN1F5cGxFd0NiVjNPMklxdmxCL0hTaGhRWHVBRWR0MXplZkNsL09' - 'TCnpyNURFMGpOWWQ0Vnk5ZXFyT1hTV0E1OFhLRGhTT1p6d1NyUnY3OE1iSmNlSWJteWhXWGtPSlNS' - 'TWtYZVNvTUYKNVJ4NXhpRXU1UHZIT1d4amlkWmRObVN6SWpXNkYxRjhweUNaVndJREFRQUJBb0lCQ' - 'UNxbjNDYlk0YWJteVBNUQpHMnlJRVhmcFNGMnAyc0QzYlYzUlhNcDhzV1hMekJBRndxdlQwTW9XME' - 'xSK2tIWHRBN1NJR0tYdFhMWkZSWkMrClRwSTNyYXh2c3o2eE5wNkZUbGpEaVp6UXdBcm1ZdlNaUlg' - 'vU0NnTFR0ZENRdEFtMDBUT2Z3UzNTb3R3K0xFK3AKMStoaDVtVlhFby9XNDRWeWYxNjNsRHAwOXBD' - 'K3dpS0ZEa2JHVExBdnA1bnFaMnhtZDRyNzhyMi9TZmZ2YUplZQpJSlpwbENMYzMyQkVZaE4yeDRIa' - 'HpqQkhOdTJwYkFXS2twUDVjWkZNS3QwSUkrRTN0UUNWMlkrYVZvNTY0TzRGCjZxMmFUUzVxMnRuaW' - 'VBTS9uay8zN3hkNUVoNjRpMU8vQTU2YzdoZmxkMDVQMC9PdU9OY2dsaVVYRG44cnFvOUoKdXpFQ1F' - 'ORUNnWUVBN0xOeWRQQlhkdEZRZ3NrWG56UlVYM3hhYWFCYU8xYnJYZzVmUnlMVm5DY2thWlRORXlE' - 'dAp3eURxSGRUOGtRNXNIcXZ3WDNxNXR1elZBZ3NJUlhvcTZIUGtxRWdLeFZIclhTNzY1OFhLUnR1S' - 'GswbE11ZkQxCnVPVVBaTTJYNVR4NXRmTmh1Zlh3dXZqTkdyN0E3ZEw4VUFiY3ZtS2VuSnF2bDNJZX' - 'I0cVpkdDBDZ1lFQTVZQncKZ2pNTGJRZStEUzd1QmdsOFVmdGl5YnZCbDdTSEQ4T2RWamVOdzNEZjJ' - 'uckltQVdLTVhNTk5GWldwbmhhc0g3Swp1bWtMQWdMNWFEWXJhaFJHN2ZwMGd0YnN0RVE5Uit2dFVp' - 'azMxaFNHUS83dFBENU1LaU1jcFpnazhYUXI5UnlFCkVEN285bWFvUEZibnJKbFl5VXNQY0FCN3Y1W' - 'FNxaVdqeFZMODI4TUNnWUVBNUhoSk1DcVVvZkZqL3ZsUFBiSnIKQmtlbmxYRGI1NDc4WEtzT3VFRW' - 'RZajQ5M1ZOdHB0c1A1RnF1MytDbmNQUTAxRjR1QkZzWFMwUEtUdENMU1ZTawplZjd6WktNMUVrVUN' - 'JODJuRFhSU3pKWTFoS3NwemdpUmhjaERWWTlFNEZYQlBTa1EyVWhVOW9RVXBZNGQ5dkRCCjdoVFJt' - 'VXJqd2xGa3o0K3RvczdyVmxrQ2dZRUF4RW8vY0V5aVNDV29HblI2Sm5XMGZCWUxuMGxVUWlHb3B3W' - 'UQKS3Z1bTUzTkNNd1p6VFByb0FIVkw1T2kzZ2ZoTWNNcHhNRkNwbHBYZXBaQTNQNnFLSS83ajZnaF' - 'RPYmRueG56MgpaU0JWM21kOWt1aVdGY0dldVNlQTErMHlJOFhkMXU0RjBqTk1ZM3JZQjR1NDZQbmJ' - 'ZNGNzYy9vbDNXNFNXVzZLCkRUcDJoS3NDZ1lCSlpMQys3Uy9zRGVqdkl0MTZ2Q3JzbDJlWlFsb1p0' - 'clNoVCtTb0hmR1NPRXZkMXp1NStBL3UKaVVDYyt1SHdUa1c0RVpMTEdBYkUzTG1xSllJcXNkNVpUW' - 'UkxWTZ1TGoyV1NGWFZYUXVLanVlTDZJdGttc1dvZgpyMHFtQU93RHdFVDFvRXlNVUJoOTJVMmhxSHR' - 'aamlMdkxQdDc5aUhacDNtTnlLVjc5QXY3dVE9PQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=') - - m.execute("sed -i '/client-certificate-data:/ s/:.*$/: %s/; /client-key-data:/ s/:.*$/: %s/' /home/admin/.kube/config" % ( - old_cert, old_key)) - m.execute("chown -R admin:admin /home/admin/.kube") - self.login_and_go("/kubernetes") - - b.wait_in_text(".curtains-ct", "Couldn't connect to server") - b.wait_in_text(".curtains-ct", "Unauthorized") - b.wait_present(".curtains-ct #kubernetes-reconnect") - - # now provide a good certificate, and reconnect - m.upload([self.kubeconfig], "/home/admin/.kube/config") - m.execute("chown -R admin:admin /home/admin/.kube") - - b.click("#kubernetes-reconnect") - b.wait_present("#service-list") - - -@skipImage("Kubernetes not packaged", "debian-stable", "debian-testing", "ubuntu-1804", "ubuntu-stable", "fedora-i386") -@skipImage("No cockpit-kubernetes packaged", "continuous-atomic", "fedora-atomic", "rhel-atomic", "rhel-8-0", "rhel-8-0-distropkg", "rhel-8-1", "fedora-30", "fedora-testing") -class TestRegistry(MachineCase, RegistryTests): - provision = { - "machine1": {"address": "10.111.113.1/20"}, - "openshift": {"image": "openshift"} - } - registry_root = "/kubernetes/registry" - - def setup_user(self, user, password): - tmpfile = os.path.join(self.tmpdir, "kubeconfig") - self.openshift.execute('printf "{0}\r\n{1}\r\n" | oc login'.format(user, password)) - self.openshift.download("/root/.kube/config", tmpfile) - with open(tmpfile, "r") as f: - self.machine.execute("mkdir -p /home/admin/.kube && cat > /home/admin/.kube/config", input=f.read()) - - def setUp(self): - super(TestRegistry, self).setUp() - - self.openshift = self.machines['openshift'] - - # Sync over the kube config file - tmpfile = os.path.join(self.tmpdir, "config") - self.openshift.download("/root/.kube/config", tmpfile) - with open(tmpfile, "r") as f: - self.machine.execute("mkdir -p /home/admin/.kube && cat > /home/admin/.kube/config", input=f.read()) - wait_healthz(self.openshift) - wait(lambda: "marmalade" in self.openshift.execute("oc get projects"), delay=5) - self.openshift.execute("oc project default") - - self.browser.wait_timeout(120) - - # This happens with docker restarts and during startup polling - self.allow_journal_messages('.*received truncated HTTP response.*') - self.allow_journal_messages(".*/api.*couldn't connect.*") - - -if __name__ == '__main__': - test_main() diff --git a/test/verify/check-pages b/test/verify/check-pages index d2afab3f3..9c7849efb 100755 --- a/test/verify/check-pages +++ b/test/verify/check-pages @@ -206,11 +206,6 @@ OnCalendar=daily self.assertEqual(b.text("#ngettext-context-disks-1"), u"$0 Datenträger fehlt") self.assertEqual(b.text("#ngettext-context-disks-2"), u"$0 Datenträger fehlen") - # Angular - self.assertEqual(b.text("#angular-translate"), "Bereit") - self.assertEqual(b.text("#angular-context"), "Bereiten") - self.assertEqual(b.text("#angular-interpolate"), u"'Marmalade' löschen!!!") - # Log out and check that login page is translated now b.logout() b.wait_visible('#password-group') @@ -353,11 +348,6 @@ OnCalendar=daily self.assertEqual(b.text('#ngettext-context-disks-1'), u'$0 disco não encontrado') self.assertEqual(b.text('#ngettext-context-disks-2'), u'$0 discos não encontrados') - # Angular - self.assertEqual(b.text('#angular-translate'), 'Pronto') - self.assertEqual(b.text('#angular-context'), 'Pronto') - self.assertEqual(b.text('#angular-interpolate'), 'Deletar \'Marmalade\'') - # Log out and check that login page is translated now b.logout() b.wait_text('#password-group > label', 'Senha') diff --git a/test/verify/files/embed-cockpit.html b/test/verify/files/embed-cockpit.html index 50423f643..a8e54a5a9 100644 --- a/test/verify/files/embed-cockpit.html +++ b/test/verify/files/embed-cockpit.html @@ -102,19 +102,6 @@

-
-

- - Kubernetes - -

-
-

- -

-
-

diff --git a/test/verify/files/mock-kube-config-basic.json b/test/verify/files/mock-kube-config-basic.json deleted file mode 100644 index b035d1a3d..000000000 --- a/test/verify/files/mock-kube-config-basic.json +++ /dev/null @@ -1 +0,0 @@ -{"kind":"Config","apiVersion":"v1","preferences":{},"clusters":[{"name":"local","cluster":{"server":"https://10.111.113.1:6443","insecure-skip-tls-verify":true}}],"users":[{"name":"admin","user":{"username":"admin","password":"fubar"}}],"contexts":[{"name":"local","context":{"cluster":"local","user":"admin"}}],"current-context":"local"} diff --git a/test/verify/files/mock-kube-multi.json b/test/verify/files/mock-kube-multi.json deleted file mode 100644 index f7fa1ea09..000000000 --- a/test/verify/files/mock-kube-multi.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "kind":"List", - "apiVersion":"v1", - "items": [{ - "kind":"Pod", - "metadata": { - "name": "multi-pod", - "labels": { - "name":"mock" - } - }, - "spec": { - "containers": [{ - "name": "mock-container", - "image": "busybox:buildroot-2014.02", - "command": [ - "/bin/sh", "-c", "for x in $(seq 1 1000); do echo 'HelloMessage.' >&2; sleep 1; done" - ], - "ports": [{ - "containerPort":9949, - "protocol":"TCP" - }] - },{ - "name": "second-container", - "image": "busybox:buildroot-2014.02", - "command": [ - "/bin/sh", "-c", "sleep 100000" - ] - }] - } - }] -} diff --git a/test/verify/kubelib.py b/test/verify/kubelib.py deleted file mode 100644 index dc5ee4127..000000000 --- a/test/verify/kubelib.py +++ /dev/null @@ -1,1563 +0,0 @@ -# -*- coding: utf-8 -*- - -# This file is part of Cockpit. -# -# Copyright (C) 2016 Red Hat, Inc. -# -# Cockpit is free software; you can redistribute it and/or modify it -# under the terms of the GNU Lesser General Public License as published by -# the Free Software Foundation; either version 2.1 of the License, or -# (at your option) any later version. -# -# Cockpit is distributed in the hope that it will be useful, but -# WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public License -# along with Cockpit; If not, see . - -import os -import re -import subprocess -import sys -import time - -import testlib - -base_dir = os.path.dirname(os.path.realpath(__file__)) - -__all__ = ( - 'KubernetesCase', - 'KubernetesCommonTests', - 'OpenshiftCommonTests', - 'RegistryTests', -) - - -class KubernetesCase(testlib.MachineCase): - provision = { - "machine1": {"address": "10.111.113.1/20"} - } - - def setUp(self): - testlib.MachineCase.setUp(self) - self.browser.wait_timeout(120) - - def stop_kubernetes(self): - try: - self.machine.execute('/etc/kubernetes/stop-kubernetes') - except subprocess.CalledProcessError: - self.machine.execute("systemctl stop kube-apiserver") - - def start_kubernetes(self): - # kubelet needs the config to register to the API server - self.machine.upload(["verify/files/mock-kube-config-basic.json"], "/etc/kubernetes/kubeconfig") - self.machine.execute( - """sed -i '/KUBELET_ARGS=/ { s%"$% --kubeconfig=/etc/kubernetes/kubeconfig"% }' /etc/kubernetes/kubelet""") - - # disable imagefs eviction to protect our docker images - self.machine.execute( - """sed -i '/KUBELET_ARGS=/ { s/"$/ --eviction-hard=imagefs.available<0% --eviction-soft=imagefs.available<0%"/ }' /etc/kubernetes/kubelet""") - - # HACK: default systemd cgroup driver has been broken for a long time (https://bugzilla.redhat.com/show_bug.cgi?id=1558425) - if self.machine.image in ["fedora-30"]: - self.machine.execute(""" -sed -i 's/--cgroup-driver=systemd/--cgroup-driver=cgroupfs/' /etc/kubernetes/kubelet -sed -i 's/native.cgroupdriver=systemd/native.cgroupdriver=cgroupfs/' /usr/lib/systemd/system/docker.service -systemctl daemon-reload -systemctl try-restart docker""") - - # HACK: These are the default container secrets that which conflict - # with kubernetes secrets and cause the pod to not start - self.machine.execute("rm -rf /usr/share/rhel/secrets/* || true") - self.machine.execute("systemctl start docker || journalctl -u docker") - - # disable swap, newer kubernetes versions don't like it: - # failed to run Kubelet: Running with swap on is not supported, please - # disable swap! or set --fail-swap-on flag to false - self.machine.execute("swapoff --all --verbose") - - self.machine.execute( - "echo 'KUBE_API_ADDRESS=\"$KUBE_API_ADDRESS --bind-address=10.111.113.1\"' >> /etc/kubernetes/apiserver") - try: - self.machine.execute('/etc/kubernetes/start-kubernetes') - except subprocess.CalledProcessError: - self.machine.execute( - "systemctl start etcd kube-apiserver kube-controller-manager kube-scheduler kube-proxy kubelet") - - # HACK: https://github.com/GoogleCloudPlatform/kubernetes/issues/8311 - # Work around for the fact that kube-apiserver doesn't notify about startup - # We wait until available or timeout. - def wait_api_server(self, address="127.0.0.1", port=8080, timeout=120, scheme='http'): - waiter = """ - for a in $(seq 0 {timeout}); do - if curl -o /dev/null -k -s {scheme}://{address}:{port}; then - if kubectl get all | grep -q s.*v.*c.*/kubernetes; then - exit 0 - fi - fi - sleep 0.5 - done - echo "Timed out waiting for service/kubernetes to appear" >&2 - exit 1 - """.format(**locals()) - self.machine.execute(script=waiter) - - -class VolumeTests(object): - - def testPendingClaim(self): - b = self.browser - m = self.machine - - if hasattr(self, "openshift"): - m = self.openshift - - self.login_and_go("/kubernetes") - b.wait_in_text(".dashboard-status:nth-child(2)", "No volumes in use") - b.wait_not_present(".pvc-notice a") - - m.upload(["verify/files/mock-volume-tiny-app.json"], "/tmp") - m.execute("kubectl create -f /tmp/mock-volume-tiny-app.json") - - # By adding another volume claim more issues are found - m.execute("kubectl create namespace another && kubectl create --namespace=another -f /tmp/mock-volume-tiny-app.json") - - b.wait_in_text(".pvc-notice a", "2") - b.wait_in_text(".pvc-notice a", "pending volume claims") - b.click(".pvc-notice a") - b.wait_present(".pvc-listing") - - b.wait_present("tbody[data-id='default/mock-volume-claim']") - b.click("tbody[data-id='default/mock-volume-claim'] td:last-child button.btn-danger") - - b.wait_in_text("modal-dialog .modal-body", "mock-volume-claim") - b.wait_in_text("modal-dialog .modal-body ul", "mock-volume-") - b.wait_not_in_text("modal-dialog .modal-body ul", "mock-volume-claim") - b.click("modal-dialog button.btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present("tbody[data-id='default/mock-volume-claim']") - - m.execute("kubectl delete rc/mock-volume") - m.upload(["verify/files/mock-volume-tiny-app.json"], "/tmp") - m.execute("kubectl create -f /tmp/mock-volume-tiny-app.json") - - b.wait_in_text("tbody[data-id='default/mock-volume-claim']", "5Gi") - b.click("tbody[data-id='default/mock-volume-claim'] tr") - - b.wait_present("modal-dialog") - b.wait_present("modal-dialog #modify-access-ReadWriteMany:checked") - b.wait_present("modal-dialog #modify-access-ReadWriteOnce:not(:checked)") - b.wait_present("modal-dialog #modify-access-ReadOnlyMany:not(:checked)") - b.wait_val("modal-dialog #modify-capacity", "5Gi") - b.set_val("modal-dialog #modify-name", "pv1") - b.set_val("modal-dialog #nfs-modify-server", "10.111.112.101") - b.set_val("modal-dialog #modify-path", "/nfsexport") - b.set_val("modal-dialog #modify-policy-Retain", "Retain") - b.click("modal-dialog .modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - b.wait_present(".pv-listing tbody[data-id='pv1']") - - m.execute("kubectl delete namespace another", timeout=600) - b.wait_not_present(".pvc-listing") - - def testVolumes(self): - b = self.browser - m = self.machine - - # If openshift use, nfs pv for tests - # Otherwise use hostPath - pv_id = "pv2" - pv1_size = "1Gi" - pv2_size = "5Gi" - if hasattr(self, "openshift"): - pv_id = "pv1" - pv1_size = "5Gi" - pv2_size = "1Gi" - m = self.openshift - - self.login_and_go("/kubernetes") - b.click("#kubernetes-volumes") - b.wait_present(".pv-listing") - - b.click("#register-volume") - b.click("modal-dialog #volume-type button ") - b.click("#volume-type #volume-type-nfs") - b.wait_in_text("modal-dialog #volume-type button", "NFS") - - b.set_val("modal-dialog #modify-name", "A Bad Name") - b.set_val("modal-dialog #modify-capacity", "invalid") - b.set_val("modal-dialog #nfs-modify-server", "a bad server") - b.set_val("modal-dialog #modify-path", "tmp") - b.set_val("modal-dialog #modify-read-only", "tmp") - b.click("modal-dialog .modal-footer button.btn-primary") - - b.wait_present("modal-dialog tr:nth-child(2) div.dialog-error") - b.wait_present("modal-dialog tr:nth-child(3) div.dialog-error") - b.wait_present("modal-dialog tr:nth-child(5) div.dialog-error") - b.wait_present("modal-dialog tr:nth-child(6) div.dialog-error") - b.wait_present("modal-dialog tr:nth-child(7) div.dialog-error") - - b.set_val("modal-dialog #modify-name", "pv1") - b.set_val("modal-dialog #modify-capacity", pv1_size) - b.set_val("modal-dialog #nfs-modify-server", "10.111.112.101") - b.set_val("modal-dialog #modify-path", "/nfsexport") - b.set_val("modal-dialog #modify-policy-Retain", "Retain") - b.click("modal-dialog #modify-policy-Retain") - b.click("modal-dialog #modify-access-ReadWriteMany") - - b.click("modal-dialog .modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present(".pv-listing tbody[data-id='pv1']") - - b.click("#register-volume") - b.click("modal-dialog #volume-type button ") - b.click("#volume-type #volume-type-hostPath") - b.wait_in_text("modal-dialog #volume-type button", "Host Path") - - b.set_val("modal-dialog #modify-name", "pv2") - b.set_val("modal-dialog #modify-capacity", pv2_size) - b.wait_not_present("modal-dialog #nfs-modify-server") - b.set_val("modal-dialog #modify-path", "/tmp") - b.click("modal-dialog #modify-policy-Retain") - b.click("modal-dialog #modify-access-ReadWriteMany") - - b.click("modal-dialog .modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present(".pv-listing tbody[data-id='pv2']") - - m.upload(["verify/files/fc-volume.json"], "/tmp") - m.execute("kubectl create -f /tmp/fc-volume.json") - b.wait_present(".pv-listing tbody[data-id='fc-volume']") - - b.click(".pv-listing tbody[data-id='pv2'] th") - b.wait_present(".content-filter") - b.wait_in_text(".listing-ct-inline", "/tmp") - b.wait_in_text(".listing-ct-inline", "This volume has not been claimed") - b.click(".content-filter button.pficon-edit") - b.wait_present("modal-dialog") - - b.wait_not_present("modal-dialog input#modify-name") - b.wait_in_text("modal-dialog span#modify-name", "pv2") - b.wait_not_present("modal-dialog input#modify-capacity") - b.wait_in_text("modal-dialog span#modify-capacity", pv2_size) - b.wait_not_present("modal-dialog input#modify-path") - b.wait_in_text("modal-dialog span#modify-path", "/tmp") - - b.click("modal-dialog button.btn-default") - b.wait_not_present("modal-dialog") - - b.click("a.hidden-xs") - b.click(".pv-listing tbody[data-id='fc-volume'] th") - b.wait_present(".content-filter") - b.wait_present(".content-filter button.btn-delete") - b.wait_not_present(".content-filter button.pficon-edit") - b.click(".content-filter button.btn-delete") - b.wait_present("modal-dialog") - b.click("modal-dialog .modal-footer button.btn-danger") - b.wait_present(".pv-listing") - b.wait_not_present(".pv-listing tbody[data-id='fc-volume']") - - base_sel = ".pv-listing tbody[data-id='{}']".format(pv_id) - b.wait_present(base_sel) - b.click("{} td.listing-ct-toggle".format(base_sel)) - b.wait_in_text("{} tr.listing-ct-item td:last-child".format(base_sel), "Available") - - m.upload(["verify/files/mock-volume-tiny-app.json"], "/tmp") - m.execute("kubectl create -f /tmp/mock-volume-tiny-app.json") - - b.wait_in_text("{} tr.listing-ct-item td:last-child".format(base_sel), "Bound") - b.click("{} .listing-ct-panel ul.nav-tabs li:nth-child(2) a".format(base_sel)) - b.wait_in_text("{} .listing-ct-panel".format(base_sel), "mock-volume-claim") - b.wait_in_text("{} .listing-ct-panel ".format(base_sel), "default / mock-volume") - - pods = m.execute( - 'kubectl get pods --output=template --template="{{ range .items }}{{.metadata.name}}|{{ end }}"') - pod = [x for x in pods.split("|") if x.startswith("mock-volume")][0] - pod_id = "pods/default/{}".format(pod) - - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present("#content .details-listing tbody[data-id='{}']".format(pod_id)) - b.click("#content .details-listing tbody[data-id='{}'] td.listing-ct-toggle".format(pod_id)) - b.wait_present(".listing-ct-panel ul.nav-tabs") - b.click(".listing-ct-panel ul.nav-tabs li:last-child a".format(pod_id)) - b.wait_present(".listing-ct-body") - b.wait_js_func("ph_count_check", ".listing-ct-body div.well", 2) - - volumes = m.execute( - 'kubectl get pods/%s --output=template --template="{{ range .spec.volumes }}{{.name}}|{{ end }}"' % pod) - secret = [x for x in volumes.split("|") if x.startswith("default-token")][0] - - b.wait_in_text(".listing-ct-body div[data-id='{}']".format(secret), "Secret") - b.wait_in_text(".listing-ct-body div[data-id='{}']".format(secret), "mock-volume-container") - b.wait_in_text(".listing-ct-body div[data-id='{}']".format(secret), - "/var/run/secrets/kubernetes.io/serviceaccount") - b.wait_in_text(".listing-ct-body div[data-id='host-tmp']", "Persistent Volume") - b.wait_in_text(".listing-ct-body div[data-id='host-tmp']", "mock-volume-claim") - b.wait_in_text(".listing-ct-body div[data-id='host-tmp']", "mock-volume-container") - b.wait_in_text(".listing-ct-body div[data-id='host-tmp']", "/mount-path-tmp") - b.wait_present(".listing-ct-body div[data-id='host-tmp'] a[href='#/volumes/{}']".format(pv_id)) - - -class KubernetesCommonTests(VolumeTests): - - def add_node(self, b, name, address): - b.wait_present("modal-dialog") - b.set_val("#node-name", name) - b.set_val("#node-address", address) - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - - def check_logs(self, b): - # Check that container log output shows up - b.click("#content .containers-listing tbody:first-of-type tr.listing-ct-item td.listing-ct-toggle") - b.wait_in_text("#content .containers-listing tbody.open tr.listing-ct-item td:last-child", "running") - b.click("tbody.open .listing-ct-panel .listing-ct-head li a.logs") - b.wait_in_text("tbody.open .listing-ct-panel pre", "HelloMessage.") - - def check_shell(self, b): - b.click("tbody.open .listing-ct-panel .listing-ct-head li a.shell") - b.wait_in_text("tbody.open .listing-ct-panel div.terminal", "#") - b.focus('tbody.open .listing-ct-panel .terminal') - b.key_press("whoami\r") - b.wait_in_text("tbody.open .listing-ct-panel div.terminal", "root") - - def testDelete(self): - b = self.browser - m = self.machine - b.wait_timeout(120) - - self.login_and_go("/kubernetes") - b.wait_in_text("#node-list", "127.0.0.1") - - m.execute("kubectl create -f /tmp/mock-k8s-tiny-app.json") - b.wait_in_text("#service-list", "mock") - - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present("#content .details-listing tbody[data-id='services/default/mock']") - self.assertEqual(b.text(".details-listing tbody[data-id='services/default/mock'] th"), "mock") - b.wait_present("#content .details-listing tbody[data-id='replicationcontrollers/default/mock']") - self.assertEqual(b.text(".details-listing tbody[data-id='replicationcontrollers/default/mock'] th"), "mock") - b.wait_present(".details-listing tbody[data-id^='pods/default/'] th") - podl = m.execute( - 'kubectl get pods --output=template --template="{{ range .items }}{{.metadata.name}}|{{ end }}"').split("|") - b.wait_present(".details-listing tbody[data-id='pods/default/" + podl[0] + "'] th") - self.assertEqual(b.text(".details-listing tbody[data-id='pods/default/" + podl[0] + "'] th"), podl[0]) - - b.click(".details-listing tbody[data-id='services/default/mock'] td.listing-ct-toggle") - b.click(".details-listing tbody[data-id='services/default/mock'] .delete-entity") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present(".details-listing tbody[data-id='services/default/mock']") - - b.click(".details-listing tbody[data-id='replicationcontrollers/default/mock'] td.listing-ct-toggle") - b.click(".details-listing tbody[data-id='replicationcontrollers/default/mock'] .delete-entity") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present(".details-listing tbody[data-id='replicationcontrollers/default/mock']") - - b.click(".details-listing tbody[data-id='pods/default/" + podl[0] + "'] td.listing-ct-toggle") - b.wait_visible(".details-listing tbody[data-id='pods/default/" + podl[0] + "'] .delete-pod") - b.click(".details-listing tbody[data-id='pods/default/" + podl[0] + "'] .delete-pod") - b.wait_in_text("modal-dialog .modal-body", "Deleting a Pod will") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present(".details-listing tbody[data-id='pods/default/" + podl[0] + "']") - - def testDashboard(self): - m = self.machine - b = self.browser - - self.login_and_go("/kubernetes") - b.wait_in_text("#node-list", "127.0.0.1") - - m.execute("kubectl create -f /tmp/mock-k8s-tiny-app.json") - b.wait_in_text("#service-list", "mock") - - # Successfully deploy via dialog - b.click("#deploy-app") - b.wait_present("modal-dialog") - b.upload_file("#deploy-app-manifest-file", os.path.join(base_dir, "files/mock-k8s-tiny-app.json")) - b.wait_val("#deploy-app-namespace", "") - b.set_val("#deploy-app-namespace", "mynamespace1") - b.click("#deploy-app-namespace-group > span button") - b.wait_in_text("#deploy-app-namespace-group ul", "default") - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - b.wait_in_text("#service-list", "mynamespace1") - b.wait_in_text("#service-list", "default") - - # Fail deploy via dialog - b.click("#deploy-app") - b.wait_present("modal-dialog") - b.upload_file("#deploy-app-manifest-file", os.path.join(base_dir, "files/mock-k8s-tiny-app.json")) - b.set_val("#deploy-app-namespace", "!!!!") - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_present("modal-dialog .dialog-error") - b.click("modal-dialog .btn-cancel") - b.wait_not_present("modal-dialog") - - # Successfully add node via dialog - b.click("#add-node") - self.add_node(b, "mynode", "myaddress") - b.wait_in_text("#node-list", "mynode") - - # Fail add node via dialog - b.click("#add-node") - b.wait_present("modal-dialog") - b.set_val("#node-name", "!!!!") - b.set_val("#node-address", "!!!!") - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_present("modal-dialog .dialog-error") - b.click("modal-dialog .btn-cancel") - b.wait_not_present("modal-dialog") - - # Make sure pod has started - b.wait_text("#service-list tr[data-name='mock']:first-of-type td.containers", "1") - - # Adjust the service - b.click("#services-enable-change") - b.click("#service-list tr[data-name='mock']:first-of-type button") - b.set_val("modal-dialog input.adjust-replica", 2) - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - b.click("#services-enable-change") - b.wait_in_text("#service-list tr[data-name='mock']:first-of-type td.containers", "2") - - # Check that clicking on service goes to containers - b.click("#service-list tr[data-name='mock']:first-of-type td.containers") - b.wait_present("#content .containers-listing tbody tr th") - self.assertEqual(b.text("#content .containers-listing tbody:first-of-type tr th"), "mock-container") - - self.check_logs(b) - self.check_shell(b) - - # Check that service shows up on listing view - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present(".details-listing tbody[data-id='services/default/mock']") - self.assertEqual(b.text(".details-listing tbody[data-id='services/default/mock'] th"), "mock") - b.wait_present(".details-listing tbody[data-id='replicationcontrollers/default/mock']") - self.assertEqual( - b.text(".details-listing tbody[data-id='replicationcontrollers/default/mock'] tr.listing-ct-item th"), "mock") - b.wait_not_present("#routes") - b.wait_not_present("#deployment-configs") - - # Click on the service to expand into a panel - b.click(".details-listing tbody[data-id='services/default/mock'] td.listing-ct-toggle") - b.wait_in_text(".details-listing tbody[data-id='services/default/mock'] tr.listing-ct-panel", "mock") - - # Other services should still be present - self.assertTrue(b.is_present(".details-listing tbody:not(.open) tr.listing-ct-item")) - - # Click into service - b.click(".details-listing tbody[data-id='services/mynamespace1/mock'] tr.listing-ct-item") - b.wait_in_text(".listing-ct-inline", "Service") - b.wait_in_text(".listing-ct-inline", "Endpoints") - b.wait_text(".content-filter h3", "mock") - b.click("a.hidden-xs") - b.wait_present("#content .details-listing") - b.wait_present(".details-listing tbody[data-id='services/mynamespace1/mock']") - b.wait_not_present("#pods") - b.wait_not_present("#replication-controllers") - - b.wait_in_text(".type-filter button", "Services") - b.click(".type-filter .btn.dropdown-toggle") - b.click(".type-filter li:first-child a") - b.wait_present("#pods") - b.wait_present("#replication-controllers") - - # Back to dashboard - b.click("a[href='#/']") - b.wait_in_text("#service-list", "mock") - - # Switch to filtered view - b.click(".namespace-filter .btn.dropdown-toggle") - b.click(".namespace-filter li:last-child a") - b.wait_in_text("#service-list", "mynamespace1") - b.wait_not_in_text("#service-list", "default") - - # Deploy app in a namespace that isn't selected - b.click("#deploy-app") - b.wait_present("modal-dialog") - b.upload_file("#deploy-app-manifest-file", os.path.join(base_dir, "files/mock-k8s-tiny-app.json")) - b.wait_val("#deploy-app-namespace", "mynamespace1") - b.set_val("#deploy-app-namespace", "mynamespace2") - b.click("modal-dialog .btn-primary") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - - # mynamespace2 is now selected - b.wait_in_text("#service-list", "mynamespace2") - b.wait_not_in_text("#service-list", "default") - b.wait_not_in_text("#service-list", "mynamespace1") - b.wait_js_cond('window.location.hash == "#/?namespace=mynamespace2"') - b.wait_in_text(".namespace-filter button", "mynamespace2") - - def testNodes(self): - m = self.machine - b = self.browser - - self.login_and_go("/kubernetes") - b.wait_in_text("#node-list", "127.0.0.1") - - # localhost node should be up and healthy - b.wait_present(".card-pf-aggregate-status .pficon-ok") - b.wait_not_present(".card-pf-aggregate-status .pficon-error-circle-o") - b.wait_in_text("#content", "All healthy") - - b.click("#node-list tbody tr:first-child") - - b.wait_in_text(".listing-ct-inline", "Node") - b.wait_in_text(".listing-ct-inline", "Capacity") - b.wait_in_text(".listing-ct-inline", "KubeletReady") - b.wait_text(".content-filter h3", "127.0.0.1") - b.click("a.hidden-xs") - - # Add some nodes - b.wait_present(".nodes-listing") - b.wait_present("#add-node") - - for l in ['a', 'b', 'c', 'd']: - b.click("#add-node") - self.add_node(b, "{}-mynode".format(l), "{}-myaddress".format(l)) - b.wait_present(".nodes-listing tbody[data-id='{}-mynode']".format(l)) - - # Check inner page - b.click(".nodes-listing tbody[data-id='a-mynode'] tr.listing-ct-item") - b.wait_text(".content-filter h3", "a-mynode") - b.click("a.hidden-xs") - - # Delete from inner page - b.wait_present(".nodes-listing") - b.click(".nodes-listing tbody[data-id='a-mynode'] tr.listing-ct-item") - b.click(".content-filter button.btn-danger") - b.wait_in_text("modal-dialog .modal-body", "a-mynode") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - b.wait_present(".nodes-listing") - b.wait_present(".nodes-listing tbody[data-id='127.0.0.1']") - b.wait_not_present(".nodes-listing tbody[data-id='a-mynode']") - - # Check panel - b.click(".nodes-listing tbody[data-id='127.0.0.1'] tr.listing-ct-item td.listing-ct-toggle") - b.wait_present(".nodes-listing tbody[data-id='127.0.0.1'] tr.listing-ct-panel") - self.assertTrue(b.is_visible(".nodes-listing tbody[data-id='127.0.0.1'] tr.listing-ct-panel")) - b.wait_in_text("tbody[data-id='127.0.0.1'] tr.listing-ct-panel", "Ready") - b.click(".nodes-listing tbody[data-id='127.0.0.1'] tr.listing-ct-panel a.machine-jump") - - is_docker = m.execute("docker ps | grep 'cockpit/kubernetes' || true") - if is_docker: - # When running as a container, localhost only has kubernetes - b.wait_present(".dashboard-cards") - b.click("a[href='#/nodes']") - else: - # Normally it goes to system - b.enter_page("/system") - b.switch_to_top() - b.click("li.dashboard-link a[href='/kubernetes']") - b.enter_page("/kubernetes") - - # Delete from panel - b.click(".nodes-listing tbody[data-id='b-mynode'] tr.listing-ct-item td.listing-ct-toggle") - b.wait_present(".nodes-listing tbody[data-id='b-mynode'] tr.listing-ct-panel") - self.assertTrue(b.is_visible(".nodes-listing tbody[data-id='b-mynode'] tr.listing-ct-panel")) - b.wait_in_text("tbody[data-id='b-mynode'] tr.listing-ct-panel", "Unknown") - b.click("tbody[data-id='b-mynode'] .listing-ct-actions button.btn-delete") - b.wait_in_text("modal-dialog .modal-body", "b-mynode") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - b.wait_not_present(".nodes-listing tbody[data-id='b-mynode']") - - # Delete multiple - b.wait_present(".nodes-listing") - b.click(".content-filter button.fa-check") - b.wait_present(".content-filter button.fa-check.active") - b.wait_present(".content-filter button.btn-danger.disabled") - b.click("tbody[data-id='c-mynode'] td.listing-ct-toggle input[type=checkbox]") - b.wait_not_present(".content-filter button.btn-danger.disabled") - b.wait_present(".content-filter button.btn-danger") - b.click("tbody[data-id='c-mynode'] td.listing-ct-toggle input[type=checkbox]") - b.wait_present(".content-filter button.btn-danger.disabled") - b.click("tbody[data-id='c-mynode'] td.listing-ct-toggle input[type=checkbox]") - b.click("tbody[data-id='d-mynode'] td.listing-ct-toggle input[type=checkbox]") - b.click(".content-filter button.btn-danger") - b.wait_in_text("modal-dialog .modal-body", "c-mynode") - b.wait_in_text("modal-dialog .modal-body", "d-mynode") - b.wait_not_in_text("modal-dialog .modal-body", "127.0.0.1") - b.click("modal-dialog .btn-cancel") - b.wait_not_present("modal-dialog") - - b.click(".content-filter button.btn-danger") - b.wait_in_text("modal-dialog .modal-body", "c-mynode") - b.wait_in_text("modal-dialog .modal-body", "d-mynode") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog .dialog-wait-ct") - b.wait_not_present("modal-dialog") - b.wait_not_present(".nodes-listing tbody[data-id='c-mynode']") - b.wait_not_present(".nodes-listing tbody[data-id='d-mynode']") - b.wait_present(".nodes-listing tbody[data-id='127.0.0.1']") - - def testTopology(self): - m = self.machine - b = self.browser - - # The service has loaded and containers instantiated - self.login_and_go("/kubernetes") - m.execute("kubectl create -f /tmp/mock-k8s-tiny-app.json") - b.wait_text("#service-list tr[data-name='mock'] td.containers", "1") - - # Switch to topology view - b.click("a[href='#/topology']") - - # Assert that at least one link between Service and Pod has loaded - b.wait_present("svg line.ServicePod") - - # Make sure that details display works - b.wait_present("svg g.Node") - b.wait_js_func( - """(function() { - var el = ph_select("svg g.Node"); - var i; - for (i = 0; i < el.length; i++) { - var x = el[i].getAttribute("cx"); - var y = el[i].getAttribute("cy"); - if (x && y) { - var ev = new MouseEvent("mousedown", { - bubbles: true, - cancelable: true, - view: window, - button: 0 - }); - - /* Now dispatch the event */ - el[i].dispatchEvent(ev); - return true; - } - } - - })""", "true") - - b.wait_present("div.sidebar-pf-right") - b.wait_in_text("div.sidebar-pf-right kubernetes-object-describer > div", "127.0.0.1") - b.wait_in_text("div.sidebar-pf-right kubernetes-object-describer h3:first", "Node") - - -class OpenshiftCommonTests(VolumeTests): - - def testBasic(self): - b = self.browser - - # populate routes - self.openshift.execute("oc expose service docker-registry --hostname=test.example.com") - - self.login_and_go("/kubernetes") - b.wait_in_text("#service-list", "registry") - - # Switch to detail view - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present("#routes") - b.wait_present("#deployment-configs") - - b.wait_present(".details-listing tbody[data-id='deploymentconfigs/default/docker-registry'] th") - self.assertEqual( - b.text(".details-listing tbody[data-id='deploymentconfigs/default/docker-registry'] th"), "docker-registry") - - b.wait_present(".details-listing tbody[data-id='routes/default/docker-registry'] th") - self.assertEqual( - b.text(".details-listing tbody[data-id='routes/default/docker-registry'] th"), "docker-registry") - - # Switch to images view - b.click("a[href='#/images']") - b.wait_in_text("tbody[data-id='marmalade/busybee'] tr", "0.x") - - # Switch to topology view - b.click("a[href='#/topology']") - b.wait_present("svg line.DeploymentConfigReplicationController") - b.wait_present("svg line.RouteService") - - def testDelete(self): - b = self.browser - - self.login_and_go("/kubernetes") - b.wait_present("#service-list") - - self.openshift.execute("oc create -f /tmp/mock-app-openshift.json") - b.wait_in_text("#service-list", "mock") - - b.click("a[href='#/list']") - b.wait_present("#content .details-listing") - b.wait_present("#routes") - b.wait_present("#deployment-configs") - - b.wait_present(".details-listing tbody[data-id='deploymentconfigs/default/frontend'] th") - b.wait_present(".details-listing tbody[data-id='routes/default/mock'] th") - self.assertEqual(b.is_present(".details-listing tbody[data-id='routes/default/mock'] th"), True) - self.assertEqual(b.is_present(".details-listing tbody[data-id='deploymentconfigs/default/frontend'] th"), True) - - b.click(".details-listing tbody[data-id='routes/default/mock'] td.listing-ct-toggle") - b.click(".details-listing tbody[data-id='routes/default/mock'] .route-delete") - b.wait_in_text("modal-dialog .modal-header", "Delete Route") - b.wait_in_text("modal-dialog .modal-body", "Route 'mock'") - b.click(".modal-footer button.btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present(".details-listing tbody[data-id='routes/default/mock']") - - b.click(".details-listing tbody[data-id='deploymentconfigs/default/frontend'] td.listing-ct-toggle") - b.click(".details-listing tbody[data-id='deploymentconfigs/default/frontend'] .deployment-delete") - b.wait_present("modal-dialog") - b.click(".modal-footer button.btn-danger") - b.wait_not_present("modal-dialog") - b.wait_not_present(".details-listing tbody[data-id='deploymentconfigs/default/frontend']") - - def testNodeNavigation(self): - m = self.machine - b = self.browser - - # Delete lang.sh to avoid weirdly truncated setlocale journal messages - self.openshift.execute("rm /etc/profile.d/lang.sh") - - # Make sure we can find openshift - m.execute("echo '10.111.112.101 f1.cockpit.lan' >> /etc/hosts") - - self.login_and_go("/kubernetes") - b.click("a[href='#/nodes']") - - b.wait_in_text(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-item", "Ready") - - b.click(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-item td.listing-ct-toggle") - b.wait_present(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-panel") - self.assertTrue(b.is_visible(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-panel")) - b.wait_in_text(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-panel", "10.111.112.101") - b.click(".nodes-listing tbody[data-id='f1.cockpit.lan'] tr.listing-ct-panel a.machine-jump") - - b.switch_to_top() - # the troubleshoot button by itself shows/hides multiple times, wait for "Connecting.." to disappear first - b.wait_not_visible(".curtains-ct .spinner") - b.wait_visible("#machine-troubleshoot") - b.click('#machine-troubleshoot') - b.wait_popup('troubleshoot-dialog') - b.wait_in_text('#troubleshoot-dialog', "Fingerprint") - - # We can accept the key - b.click("#troubleshoot-dialog .btn-primary") - b.wait_in_text("#troubleshoot-dialog", 'Log in to') - b.click("#troubleshoot-dialog .modal-footer .btn-default") - b.wait_in_text(".curtains-ct", "Login failed") - - # Refreshing keeps our key - b.reload() - b.wait_visible("#machine-troubleshoot") - b.wait_in_text(".curtains-ct", "Login failed") - b.click('#machine-troubleshoot') - b.wait_popup('troubleshoot-dialog') - b.wait_in_text("#troubleshoot-dialog", 'Log in to') - b.click("#login-type button") - b.click("#login-type li[value=password] a") - b.wait_in_text("#login-type button span", "Type a password") - b.wait_visible("#login-diff-password") - b.wait_not_visible("#login-available") - self.assertEqual(b.val("#login-custom-password"), "") - self.assertEqual(b.val("#login-custom-user"), "") - b.set_val("#login-custom-user", "root") - b.set_val("#login-custom-password", "foobar") - b.click('#troubleshoot-dialog .btn-primary') - b.wait_popdown('troubleshoot-dialog') - - b.wait_not_visible(".curtains-ct") - b.enter_page('/system', "root@10.111.112.101") - b.wait_visible('#system_information_os_text') - b.wait_text_not("#system_information_os_text", "") - b.logout() - - # Nothing was saved - self.assertFalse(m.execute("grep 10.111.112.101 /etc/ssh/ssh_known_hosts || true")) - self.assertFalse(m.execute("grep 10.111.112.101 /etc/cockpit/machines.d/99-webui.json || true")) - - self.allow_hostkey_messages() - self.allow_journal_messages('/usr/libexec/cockpit-pcp: bridge was killed: .*', - '.* host key for server is not known: .*', - 'invalid or unusable locale: .*', - 'connection unexpectedly closed by peer', - 'Error receiving data: Connection reset by peer') - - -class RegistryTests(object): - - def setupDockerRegistry(self): - """Run a docker registry instance and populate it - - The OpenShift registry can pull image streams from localhost:5555 for - testing. - """ - # set up a docker registry with cert, as openshift registry expects https - self.openshift.execute("docker run -d -p 5555:5000 --name testreg " - "-v /openshift.local.config/master/:/certs " - "-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/master.server.crt " - "-e REGISTRY_HTTP_TLS_KEY=/certs/master.server.key " - "registry:2") - self.openshift.execute("while ! curl -s --connect-timeout 1 https://localhost:5555/; do sleep 1; done") - self.addCleanup(self.openshift.execute, "docker rm -f testreg") - - # populate it with some images - self.openshift.execute("docker tag registry:5000/marmalade/juggs:latest localhost:5555/juggs:latest; " - "docker tag registry:5000/marmalade/juggs:2.11 localhost:5555/juggs:2.11; " - "docker push localhost:5555/juggs") - - def testImages(self): - b = self.browser - o = self.openshift - - self.login_and_go(self.registry_root) - b.wait_present(".dashboard-images") - - # The default view should be overwhelmed with pizzazz images - b.wait_in_text(".card-pf-wide.dashboard-images", "pizzazz/monster") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "default/busybox") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "marmalade/busybee") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "marmalade/juggs") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "marmalade/origin") - - # Filter the dashboard to marmalide project - b.click(".dashboard-images .namespace-filter button") - b.wait_visible(".dashboard-images .namespace-filter .dropdown-menu") - b.click(".dashboard-images .namespace-filter a[value='marmalade']") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "pizzazz/") - b.wait_in_text(".card-pf-wide.dashboard-images", "marmalade/busybee") - - # Lets navigate to an image stream - b.click("a[href='#/images/marmalade/busybee']") - b.wait_in_text(".content-filter h3", "marmalade/busybee") - b.click("tbody[data-id='marmalade/busybee:0.x'] tr td.listing-ct-toggle") - b.wait_in_text( - "tbody[data-id='marmalade/busybee:0.x'] .listing-ct-panel dl.registry-image-tags", "marmalade/busybee:0.x") - - # Look at the image layers - b.click(".listing-ct-head li:last-child a") - b.wait_in_text(".listing-ct-body .registry-image-layers", "KiB") - - # Add postgres into the stream - output = o.execute("oc get imagestream --namespace=marmalade --template='{{.spec}}' busybee") - self.assertNotIn("postgres", output) - b.click(".pficon-edit") - b.wait_present("modal-dialog") - b.click("#imagestream-modify-populate button") - b.wait_visible("#imagestream-modify-populate .dropdown-menu") - b.click("#imagestream-modify-populate a[value='pull']") - b.set_val("#imagestream-modify-pull", "postgres") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_in_text("#content", "postgres") - output = o.execute("oc get imagestream --namespace=marmalade --template='{{.spec}}' busybee") - self.assertIn("postgres", output) - - # Remove postgres from the stream - b.click(".pficon-edit") - b.wait_present("modal-dialog") - b.click("#imagestream-modify-populate button") - b.wait_visible("#imagestream-modify-populate .dropdown-menu") - b.click("#imagestream-modify-populate a[value='none']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_not_in_text("#content", "postgres") - output = o.execute("oc get imagestream --namespace=marmalade --template='{{.spec}}' busybee") - self.assertNotIn("postgres", output) - - # Go to the images view and create a new imagestream - b.click("#content a[href='#/images/marmalade']") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.set_val("#imagestream-modify-name", "zero") - b.wait_val("#imagestream-modify-project-text", "marmalade") - b.click("#imagestream-modify-project button") - b.wait_visible("#imagestream-modify-project .dropdown-menu") - b.click("#imagestream-modify-project a[value='default']") - b.wait_val("#imagestream-modify-project-text", "default") - b.set_val("#imagestream-modify-project-text", "###") - b.click(".btn-primary") - b.wait_visible(".dialog-error") - b.set_val("#imagestream-modify-project-text", "default") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - # Switch to the default namespace and look for what we created - b.click("filter-bar .namespace-filter button") - b.wait_visible("filter-bar .namespace-filter .dropdown-menu") - b.click("filter-bar .namespace-filter a[value='default']") - b.wait_visible("tbody[data-id='default/zero']") - - # Go to the images view and check annotations - b.click("tbody[data-id='default/busybox'] th") - b.wait_in_text(".content-filter h3", "default/busybox") - b.wait_in_text("#content", "Annotations") - b.wait_in_text("registry-imagestream-meta dl", "openshift.io/image.dockerRepositoryCheck") - - # Delete the tagged image from its own screen - b.go("#/images/marmalade/busybee:0.x") - b.wait_in_text(".content-filter h3", "marmalade/busybee:0.x") - b.click(".pficon-delete") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog") - - # Should redirect to the imagestream page - b.wait_in_text(".content-filter", "Show all image streams") - b.wait_not_in_text("#content", "0.x") - - # Delete via the main UI - b.click("tbody[data-id='marmalade/busybee:latest'] tr.listing-ct-item td.listing-ct-toggle") - b.wait_in_text( - "tbody[data-id='marmalade/busybee:latest'] .listing-ct-panel dl.registry-image-tags", "marmalade/busybee:latest") - b.click("tbody[data-id='marmalade/busybee:latest'] .listing-ct-head .pficon-delete") - b.click("modal-dialog .btn-danger") - b.wait_not_present("modal-dialog") - - # All tags here have been removed - b.wait_not_in_text("#content", "latest") - - # Show the image on the right screen - b.go("#/images/marmalade/juggs") - b.wait_in_text(".content-filter h3", "marmalade/juggs") - b.click("tbody[data-id='marmalade/juggs:2.9'] tr.listing-ct-item td.listing-ct-toggle") - - # Various labels should show up in this image - b.wait_in_text("tbody[data-id='marmalade/juggs:2.9'] .listing-ct-panel", "Juggs Image") - b.wait_in_text("tbody[data-id='marmalade/juggs:2.9'] registry-image-body dl.dl-horizontal", - "This is a test description of an image. It can be as long as a paragraph, featuring a nice brogrammer sales pitch.") - b.wait_in_text("tbody[data-id='marmalade/juggs:2.9'] registry-image-body dl.dl-horizontal", "http://hipsum.co") - - # And some key labels shouldn't show up on the metadata - b.click("tbody[data-id='marmalade/juggs:2.9'] .listing-ct-head li:last-child a") - b.wait_in_text("tbody[data-id='marmalade/juggs:2.9'] registry-image-meta dl", "build-date=2016-03-04") - - # Check panel navigations - b.go("#/images") - b.wait_in_text("tbody[data-id='marmalade/juggs'] tr", "and 1 other") - b.wait_present("tbody[data-id='marmalade/juggs'] tr td a.registry-image-tag:contains('2.11')") - b.click("tbody[data-id='marmalade/juggs'] tr td.listing-ct-toggle") - b.click("tbody[data-id='marmalade/juggs'] tr.listing-ct-panel ul li:contains('Tags') a") - b.wait_present("tbody[data-id='marmalade/juggs'] tr.listing-ct-panel td table.listing-ct") - b.wait_in_text( - "tbody[data-id='marmalade/juggs'] tr.listing-ct-panel td table.listing-ct tbody[data-id='marmalade/juggs:latest'] tr th", "latest") - b.click( - "tbody[data-id='marmalade/juggs'] tr.listing-ct-panel td table.listing-ct tbody[data-id='marmalade/juggs:latest'] tr") - b.wait_js_cond('window.location.hash == "#/images/marmalade/juggs:latest"') - b.wait_present("#content div.listing-ct-inline") - b.wait_text(".content-filter h3 span", "marmalade/juggs:latest") - - b.go("#/images") - b.wait_in_text("tbody[data-id='marmalade/juggs'] tr", "and 1 other") - b.click("tbody[data-id='marmalade/juggs'] tr td a.registry-image-tag:contains('2.11')") - b.wait_js_cond('window.location.hash == "#/images/marmalade/juggs:2.11"') - b.wait_present("#content div.listing-ct-inline") - b.wait_in_text(".content-filter h3", "marmalade/juggs:2.11") - - b.go("#/images") - b.wait_in_text("tbody[data-id='marmalade/juggs'] tr", "and 1 other") - b.click("tbody[data-id='marmalade/juggs'] tr") - b.wait_js_cond('window.location.hash == "#/images/marmalade/juggs"') - b.wait_present("#content div.listing-ct-inline") - b.wait_in_text(".content-filter h3", "marmalade/juggs") - - def testImageNames(self): - b = self.browser - - self.login_and_go(self.registry_root) - b.wait_present(".dashboard-images") - b.click("#content a[href='#/images/marmalade']") - b.wait_visible("a:contains('New image stream')") - - self.checkImageName(b, "__aaa__", False) - self.checkImageName(b, "_aaa", False) - self.checkImageName(b, "-aaa", False) - self.checkImageName(b, ".aaa", False) - self.checkImageName(b, "aaa_", False) - self.checkImageName(b, "aaa-", False) - self.checkImageName(b, "aaa.", False) - self.checkImageName(b, "a_ a", False) - self.checkImageName(b, "Aa_Bb_Cc", False) - self.checkImageName(b, "aa_bb_cc", True) - self.checkImageName(b, "aa-bb_cc.dd", True) - - def checkImageName(self, b, name, succeed): - b.click("a:contains('New image stream')") - b.wait_present("modal-dialog") - b.wait_visible("#imagestream-modify-name") - b.set_val("#imagestream-modify-project-text", "default") - - b.set_val("#imagestream-modify-name", name) - b.click("modal-dialog .btn-primary") - - if succeed: - b.wait_not_present("modal-dialog") - else: - b.wait_visible(".dialog-error") - b.click(".btn-cancel") - - b.wait_not_present("modal-dialog") - - def testProjectGroups(self): - b = self.browser - - self.login_and_go(self.registry_root) - b.go("#/projects") - b.wait_present("tbody[data-id='marmalade']") - - # Create a new group - b.click("#add-group") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.set_val("#group_name", "Pro-Duction") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("tbody[data-id='marmalade']") - - #group page - b.click("tbody[data-id='Pro-Duction'] tr:first-child td:nth-of-type(2)") - b.wait_in_text(".content-filter h3", "Pro-Duction") - - #add member - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_user_to_group button") - b.wait_visible("#add_user_to_group .dropdown-menu") - b.click(".dropdown-menu a[value='scruffy']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #delete member - b.click("tbody[data-id='scruffy'] tr td:last-child a i.pficon-close") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_user_to_group button") - b.wait_visible("#add_user_to_group .dropdown-menu") - b.click(".dropdown-menu a[value='scruffy']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #delete user - b.wait_in_text(".content-filter h3", "Pro-Duction") - b.click(".content-filter .pficon-delete") - b.wait_present("modal-dialog") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_not_present("tbody[data-id='Pro-Duction']") - - def testProjectUsers(self): - o = self.openshift - b = self.browser - - self.login_and_go(self.registry_root) - b.go("#/projects") - o.execute("oc get projects") - o.execute("oc get rolebinding -n marmalade") - b.wait_present("tbody[data-id='default']") - - # Create a new project - b.click("#add-project") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.set_val("#project-new-name", "testprojectuserproj") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #wait for it - b.wait_present("tbody[data-id='testprojectuserproj']") - o.execute("oc get projects") - - # Create a new user - b.click("#add-user") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.wait_visible("#identities") - b.set_val("#user_name", "testprojectuser") - b.set_val("#identities", "anypassword:abc123") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #wait for it - - #goto user page - b.click("tbody[data-id='testprojectuser'] tr:first-child td:nth-of-type(2)") - b.wait_in_text(".content-filter h3", "testprojectuser") - - #modify user - b.click(".content-filter .pficon-edit") - b.wait_present("modal-dialog") - b.set_val("#identities", "anypassword:abc1234") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_in_text("dl.listing-ct-body dd", "anypassword:abc1234") - - #add project member - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_parent_for_user button") - b.wait_visible("#add_parent_for_user .dropdown-menu") - b.click(".dropdown-menu a[value='testprojectuserproj']") - b.click("#add_role_for_user button") - b.wait_visible("#add_role_for_user .dropdown-menu") - b.click("#add_role_for_user a[value='Admin']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #delete project member X - b.click("tbody[data-id='testprojectuserproj'] tr td:last-child a i.pficon-close") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #add project member again - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_parent_for_user button") - b.wait_visible("#add_parent_for_user .dropdown-menu") - b.click(".dropdown-menu a[value='testprojectuserproj']") - b.click("#add_role_for_user button") - b.wait_visible("#add_role_for_user .dropdown-menu") - b.click("#add_role_for_user a[value='Admin']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #add another role to project member - b.wait_present("tbody[data-id='testprojectuserproj']") - b.click("tbody[data-id='testprojectuserproj'] tr .btn-group button") - b.wait_visible("tbody[data-id='testprojectuserproj'] tr .btn-group .dropdown-menu") - b.click("tbody[data-id='testprojectuserproj'] tr .dropdown-menu a[value='Push']") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("table.listing-ct") - testlib.wait(lambda: re.search(r"registry-editor\s+/registry-editor\s+testprojectuser\b", - o.execute("oc get rolebinding -n testprojectuserproj"))) - - #delete user - b.wait_in_text(".content-filter h3", "testprojectuser") - b.click(".content-filter .pficon-delete") - b.wait_present("modal-dialog") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - # HACK: In order to test issue, log the output to the journal - testlib.wait(lambda: not re.search(r"\btestprojectuser\b", o.execute( - "oc get rolebinding -n testprojectuserproj | logger -s 2>&1"))) - - #add/remove members for other roles - b.go("#/projects/testprojectuserproj") - for (role, perm) in [("Push", "editor"), ("Pull", "viewer")]: - username = "testprojectuser" + role.lower() - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.set_val("#add_member_name", username) - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='%s']" % role) - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("tbody[data-id='%s']" % username) - - testlib.wait(lambda: username in o.execute("oc get rolebinding -n testprojectuserproj"), delay=5) - output = o.execute("oc get rolebinding -n testprojectuserproj") - self.assertRegex(output, "registry-%s\s+/registry-%s\s.*\\b%s\\b" % (perm, perm, username)) - self.assertNotRegex(output, "registry-admin.*%s" % username) - - b.wait_present("tbody[data-id='%s']" % username) - b.click("tbody[data-id='%s'] a i.pficon-close" % username) - b.wait_present("modal-dialog") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("table.listing-ct") - testlib.wait(lambda: username not in o.execute("oc get rolebinding -n testprojectuserproj"), delay=5) - - # try to add user with invalid name from testprojectuserproj page - b.go("#/projects/testprojectuserproj") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.set_val("#add_member_name", "foo ^ bar") - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='Admin']") - b.click(".btn-primary") - b.wait_in_text(".dialog-error", "The member name contains invalid characters.") - - # but email-style user name should be accepted - b.set_val("#add_member_name", "foo@bar.com") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("tbody[data-id='foo@bar.com']") - testlib.wait(lambda: 'foo@bar.com' in o.execute("oc get rolebinding -n testprojectuserproj"), delay=5) - self.assertNotIn('foo ^ bar', o.execute("oc get rolebinding -n testprojectuserproj")) - - # service accounts should be accepted - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.set_val("#add_member_name", "system:janitor:default") - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='Admin']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("tbody[data-id='system:janitor:default']") - testlib.wait(lambda: 'system:janitor:default' in o.execute( - "oc get rolebinding -n testprojectuserproj"), delay=5) - - # they appear on the "All projects" page too - b.go("#/projects/") - b.wait_present("tbody[data-id='foo@bar.com']") - b.wait_present("tbody[data-id='system:janitor:default']") - - # try to add user with invalid name from "All projects" page - b.click("#add-user") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.wait_visible("#identities") - b.set_val("#user_name", "bar ^ baz") - b.set_val("#identities", "anypassword:abc123") - b.click(".btn-primary") - b.wait_in_text(".dialog-error", "The name contains invalid characters.") - - # email-style user name should be accepted - b.set_val("#user_name", "bar@baz.com") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_present("tbody[data-id='bar@baz.com']") - - def testProjectPolicy(self): - o = self.openshift - b = self.browser - - self.login_and_go(self.registry_root) - b.wait_present(".dashboard-images") - b.go("#/projects") - - #wait for it - b.wait_present("tbody[data-id='default']") - - # Create a new project - b.click("#add-project") - b.wait_present("modal-dialog") - b.wait_visible(".modal-body") - b.set_val("#project-new-name", "testprojectpolicyproj") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - #wait for it - b.wait_present("tbody[data-id='testprojectpolicyproj']") - o.execute("oc get projects") - - #goto project page - b.click("tbody[data-id='testprojectpolicyproj'] tr:first-child td:nth-of-type(2)") - b.wait_in_text(".content-filter h3", "testprojectpolicyproj") - - #add user with role - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_member_group button") - b.wait_visible("#add_member_group .dropdown-menu") - b.click("#add_member_group a[value='scruffy']") - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='Admin']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - b.wait_present(".inner-project-listing") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.wait_visible("#add_member_group") - b.click(".btn-primary") - b.wait_present("modal-dialog") - self.assertEqual(b.text(".dialog-error"), "Please select a valid Member.") - b.click(".btn-cancel") - b.wait_not_present("modal-dialog") - - b.wait_present(".inner-project-listing") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.click("#add_member_group button") - b.wait_visible("#add_member_group .dropdown-menu") - b.click("#add_member_group a[value='scruffy']") - b.click(".btn-primary") - b.wait_present("modal-dialog") - self.assertEqual(b.text(".dialog-error"), "Please select a valid Role.") - b.click(".btn-cancel") - b.wait_not_present("modal-dialog") - - # Add a non-existent user - b.wait_present(".inner-project-listing") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.wait_visible("#add_member_group") - b.set_val("#add_member_name", "randomuser") - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='Admin']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - # Add a non-existent user, negative case - b.wait_present(".inner-project-listing") - b.click("a i.pficon-add-circle-o") - b.wait_present("modal-dialog") - b.wait_visible("#add_member_group") - b.set_val("#add_member_name", "") - b.click("#add_role button") - b.wait_visible("#add_role .dropdown-menu") - b.click("#add_role a[value='Admin']") - b.click(".btn-primary") - b.wait_present("modal-dialog") - self.assertEqual(b.text(".dialog-error"), "Please select a valid Member.") - b.click(".btn-cancel") - b.wait_not_present("modal-dialog") - - def testProjectAdmin(self): - o = self.openshift - b = self.browser - - # Log in as scruffy - self.setup_user("scruffy", "scruffy") - self.login_and_go(self.registry_root) - - # Make sure the default view is not visible to non cluster admins - b.wait_visible(".dashboard-images:nth-child(1)") - b.wait_not_in_text(".card-pf-wide.dashboard-images", "default/busybox") - - # Show that the project displays shared access data - b.wait_present("tr[data-name='marmalade']") - b.wait_present("tr[data-name='marmalade'] .fa-lock") - - # Change the project access - b.go("#/projects/marmalade") - b.wait_in_text(".content-filter h3", "marmalade") - b.wait_in_text( - ".listing-ct-body", "Project access policy only allows specific members to access images. Grant access to specific members below.") - b.click(".content-filter .pficon-edit") - b.wait_present("modal-dialog") - b.wait_in_text("#project-access-policy button", "Private: Allow only specific users or groups to pull images") - b.click("#project-access-policy button") - b.wait_visible("#project-access-policy .dropdown-menu") - b.click("#project-access-policy a[value='shared']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_not_in_text( - ".listing-ct-body", "Project access policy allows all authenticated users to pull images. Grant additional access to specific members below.") - output = o.execute("oc policy who-can get --namespace=marmalade imagestreams/layers") - self.assertIn("system:authenticated", output) - self.assertNotIn("system:unauthenticated", output) - - # Look for change in state - b.go("#/") - b.wait_present("tr[data-name='marmalade'] .fa-unlock-alt") - - # Change project to shared - b.go("#/projects/marmalade") - b.wait_in_text(".content-filter h3", "marmalade") - b.click(".content-filter .pficon-edit") - b.wait_present("modal-dialog") - b.wait_in_text("#project-access-policy button", "Shared: Allow any authenticated user to pull images") - b.click("#project-access-policy button") - b.wait_visible("#project-access-policy .dropdown-menu") - b.click("#project-access-policy a[value='anonymous']") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_in_text( - ".listing-ct-body", "Project access policy allows anonymous users to pull images. Grant additional push or admin access to specific members below.") - output = o.execute("oc policy who-can get --namespace=marmalade imagestreams/layers") - self.assertIn("system:unauthenticated", output) - - # Look for change in state - b.go("#/") - b.wait_present("tr[data-name='marmalade'] .fa-unlock") - - # New project doesn't exist - b.go("#/") - b.wait_present(".dashboard-images") - output = o.execute("oc get projects") - self.assertNotIn("llama", output) - b.wait_not_in_text(".dashboard-images:first-child", "llama") - - # Create a new project - b.click("a.new-project-link") - b.wait_present("modal-dialog") - b.set_val("#project-new-name", "invalid...!") - b.click(".btn-primary") - b.wait_visible(".dialog-error") - b.set_val("#project-new-name", "llama") - b.set_val("#project-new-display", "Display llama") - b.set_val("#project-new-description", "Description goes here") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - - # Check that the projcet exists - b.wait_in_text(".dashboard-images:first-child", "llama") - - # Go and modify the project - b.go("#/projects") - b.wait_present("tbody[data-id='llama']") - b.click("tbody[data-id='llama'] tr.listing-ct-item td:nth-of-type(2)") - b.wait_in_text(".content-filter h3", "Display llama (llama)") - b.wait_in_text("#content", "Description goes here") - b.click(".pficon-edit") - b.wait_present("modal-dialog") - b.set_val("#project-new-display", "What the llama say") - b.set_val("#project-new-description", "Blearrrrrrrrgh") - b.click(".btn-primary") - b.wait_not_present("modal-dialog") - b.wait_in_text(".content-filter h3", "What the llama say (llama)") - b.wait_in_text("#content", "Blearrrrrrrrgh") - - # Make sure it showed up in the console - found = False - i = 0 - - class LLAMANotFoundException(Exception): - pass - - while True: - try: - output = o.execute("oc get projects") - if "llama" not in output: - if not found: - sys.stderr.write(output) - found = True - raise LLAMANotFoundException(output) - break - except LLAMANotFoundException: - if i > 60: - raise - i = i + 1 - time.sleep(2) - - def testDockerCommandInfo(self): - o = self.openshift - b = self.browser - - # create push and pull user and login as pushuser - o.execute("oc adm policy add-role-to-user registry-viewer pulluser -n marmalade") - o.execute("oc adm policy add-role-to-user registry-editor pushuser -n marmalade") - o.execute("oc adm policy add-role-to-user registry-viewer pushuser -n pizzazz") - - self.setup_user("pushuser", "a") - self.login_and_go(self.registry_root) - - # always visible on "All projects" page - b.wait_in_text("body", "Pull an image") - b.wait_visible('#docker-push-commands') - b.wait_visible('#docker-pull-commands') - - # push user should not see docker push command on pizzazz overview page (only a viewer there) - b.click(".dashboard-images .namespace-filter button") - b.wait_visible(".dashboard-images .namespace-filter .dropdown-menu") - b.click(".dashboard-images .namespace-filter a[value='pizzazz']") - b.wait_visible('#docker-pull-commands') - b.wait_not_visible('#docker-push-commands') - - # push user should see docker push and pull commands on marmalade overview page - b.click(".dashboard-images .namespace-filter button") - b.wait_visible(".dashboard-images .namespace-filter .dropdown-menu") - b.click(".dashboard-images .namespace-filter a[value='marmalade']") - b.wait_visible('#docker-push-commands') - - # .. and also on the image page - b.go("#/images/marmalade/origin") - b.wait_in_text("body", "push an image to this image stream") - b.wait_in_text("body", "docker tag") - b.wait_in_text("body", "docker push") - b.wait_visible('.registry-imagestream-push') - - # log in as pulluser - b.logout() - self.setup_user("pulluser", "a") - self.login_and_go(self.registry_root) - - # always visible on "All projects" page - b.wait_in_text("body", "Pull an image") - b.wait_visible('#docker-push-commands') - b.wait_visible('#docker-pull-commands') - - # pull user should only see docker pull command, but not push on project specific overview page - b.click(".dashboard-images .namespace-filter button") - b.wait_visible(".dashboard-images .namespace-filter .dropdown-menu") - b.click(".dashboard-images .namespace-filter a[value='marmalade']") - b.wait_visible('#docker-pull-commands') - b.wait_not_visible('#docker-push-commands') - - # and neither the push command on the image page - b.go("#/images/marmalade/origin") - b.wait_in_text("body", "Images") - b.wait_not_visible('.registry-imagestream-push') - - def testImagestreamImport(self): - b = self.browser - self.setupDockerRegistry() - - # Add new "alltags" image stream pulling from localhost:5555/juggs - self.login_and_go("{}#/images/marmalade".format(self.registry_root)) - b.wait_present("a.pull-right span:contains('New image stream')") - b.click("a.pull-right") - b.wait_present("modal-dialog") - b.wait_val("#imagestream-modify-project-text", "marmalade") - b.set_val("#imagestream-modify-name", "alltags") - b.click("#imagestream-modify-populate button") - b.click("#imagestream-modify-populate .dropdown-menu a[value='pull']") - b.set_val("#imagestream-modify-pull", "localhost:5555/juggs") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - # new stream with both "latest" and "2.11" tags should now appear - b.wait_present("tr.imagestream-item th:contains('marmalade/alltags')") - b.wait_in_text('tbody[data-id="marmalade/alltags"] tr', "latest") - b.wait_in_text('tbody[data-id="marmalade/alltags"] tr', "2.11") - - # also check with CLI - output = self.openshift.execute("oc get imagestream --namespace=marmalade alltags") - self.assertIn("localhost:5555/juggs", output) - self.assertIn("latest", output) - self.assertIn("2.11", output) - - # Add new "sometags" image stream pulling only the 2.11 tag - b.click("a.pull-right") - b.wait_present("modal-dialog") - b.wait_val("#imagestream-modify-project-text", "marmalade") - b.wait_js_cond("document.activeElement == document.getElementById('imagestream-modify-name')") - b.set_val("#imagestream-modify-name", "sometags") - b.click("#imagestream-modify-populate button") - b.click("#imagestream-modify-populate .dropdown-menu a[value='tags']") - b.wait_visible("#imagestream-modify-tags") - b.set_val("#imagestream-modify-pull", "localhost:5555/juggs") - # fields.tags is not an element, type manually - b.click("#imagestream-modify-tags") - b.focus("#imagestream-modify-tags") - b.key_press(['2', '.', '1', '1']) - b.focus("modal-dialog div.modal-footer button.btn-primary") - b.click("modal-dialog div.modal-footer button.btn-primary") - b.wait_not_present("modal-dialog") - - # new stream with only "2.11" tags should now appear - b.wait_present('tbody[data-id="marmalade/sometags"]') - b.wait_present("tr.imagestream-item th:contains('marmalade/sometags')") - b.wait_in_text('tbody[data-id="marmalade/sometags"] tr', '2.11') - b.wait_not_in_text('tbody[data-id="marmalade/sometags"] tr', 'latest') - - # also check with CLI - testlib.wait(lambda: '2.11' in self.openshift.execute('oc get imagestream --namespace=marmalade sometags')) - testlib.wait(lambda: 'latest' not in self.openshift.execute( - 'oc get imagestream --namespace=marmalade sometags')) diff --git a/tools/build-debian-copyright b/tools/build-debian-copyright index cea7c61e8..33c06a7a3 100755 --- a/tools/build-debian-copyright +++ b/tools/build-debian-copyright @@ -37,8 +37,6 @@ def template_licenses(template): def module_license(moddir): '''Return License: short name for given module''' - mod = os.path.basename(moddir) - # First check if package.json has a "license" field try: with open(os.path.join(moddir, 'package.json'), encoding='UTF-8') as f: @@ -48,9 +46,6 @@ def module_license(moddir): if l == 'MPL 2.0': # https://github.com/novnc/noVNC/pull/819 return 'MPL-2.0' - if l == 'LGPL 2+': - # https://github.com/kubernetes-ui/container-terminal/pull/32 - return 'LGPL-2.1' return l except (IOError, KeyError): pass @@ -67,12 +62,6 @@ def module_license(moddir): except IndexError: pass - # missing licenses - if mod == 'kubernetes-object-describer' or mod == 'object-describer': - # upstream says "same as what we use for origin and origin-web-console which is Apache" - # https://github.com/kubernetes-ui/object-describer/issues/31 - return 'Apache-2.0' - raise SystemError('Could not determine license from %s' % moddir) diff --git a/tools/cockpit.spec b/tools/cockpit.spec index c8aab9e83..1967ef27f 100644 --- a/tools/cockpit.spec +++ b/tools/cockpit.spec @@ -56,19 +56,6 @@ %define build_subscriptions 1 %endif -# cockpit-kubernetes is RHEL 7 64 bit only -%if 0%{?rhel} >= 7 && 0%{?rhel} < 8 -%ifarch aarch64 x86_64 ppc64le s390x -%define build_kubernetes 1 -%endif -%endif - -%if 0%{?rhel} >= 8 -%global go_scl_prefix go-toolset-7- -%else -%global go_scl_prefix %{nil} -%endif - %if 0%{?rhel} >= 7 %define vdo_on_demand 1 %endif @@ -145,9 +132,6 @@ Recommends: cockpit-packagekit Recommends: subscription-manager-cockpit %endif Suggests: cockpit-pcp -%if 0%{?build_kubernetes} -Suggests: cockpit-kubernetes -%endif Suggests: cockpit-selinux %endif @@ -270,21 +254,6 @@ rm -rf %{buildroot}/%{_datadir}/cockpit/docker touch docker.list %endif -%if 0%{?build_kubernetes} -%if %{defined wip} -%else -rm %{buildroot}/%{_datadir}/cockpit/kubernetes/override.json -%endif -echo '%dir %{_datadir}/cockpit/kubernetes' > kubernetes.list -find %{buildroot}%{_datadir}/cockpit/kubernetes -type f >> kubernetes.list -%else -rm -rf %{buildroot}/%{_datadir}/cockpit/kubernetes -rm -f %{buildroot}/%{_libexecdir}/cockpit-kube-auth -rm -f %{buildroot}/%{_libexecdir}/cockpit-kube-launch -rm %{buildroot}/%{_libexecdir}/cockpit-stub -touch kubernetes.list -%endif - # when not building basic packages, remove their files %if 0%{?build_basic} == 0 for pkg in base1 branding motd kdump networkmanager realmd selinux shell sosreport ssh static systemd tuned users; do @@ -308,15 +277,13 @@ rm -f %{buildroot}%{_datadir}/metainfo/cockpit.appdata.xml # when not building optional packages, remove their files %if 0%{?build_optional} == 0 -for pkg in apps dashboard docker kubernetes machines packagekit pcp playground storaged; do +for pkg in apps dashboard docker machines packagekit pcp playground storaged; do rm -rf %{buildroot}/%{_datadir}/cockpit/$pkg done # files from -tests rm -r %{buildroot}/%{_prefix}/%{__lib}/cockpit-test-assets %{buildroot}/%{_sysconfdir}/cockpit/cockpit.conf # files from -pcp rm -r %{buildroot}/%{_libexecdir}/cockpit-pcp %{buildroot}/%{_localstatedir}/lib/pcp/ -# files from -kubernetes -rm -f %{buildroot}/%{_libexecdir}/cockpit-kube-auth %{buildroot}/%{_libexecdir}/cockpit-kube-launch %{buildroot}/%{_libexecdir}/cockpit-stub # files from -machines rm -f %{buildroot}/%{_prefix}/share/metainfo/org.cockpit-project.cockpit-machines.metainfo.xml # files from -storaged @@ -754,32 +721,6 @@ This package is not yet complete. %endif %endif -%if 0%{?build_kubernetes} - -%package -n cockpit-kubernetes -Summary: Cockpit user interface for Kubernetes cluster -Requires: /usr/bin/kubectl -# Requires: Needs newer localization support -Requires: cockpit-bridge >= %{required_base} -Requires: cockpit-shell >= %{required_base} -BuildRequires: %{go_scl_prefix}golang-bin -BuildRequires: %{go_scl_prefix}golang-src -Provides: cockpit-stub = %{version}-%{release} - -%description -n cockpit-kubernetes -The Cockpit components for visualizing and configuring a Kubernetes -cluster. Installed on the Kubernetes master. This package is not yet complete. - -%if 0%{?rhel} >= 8 -%enable_gotoolset7 -%endif - -%files -n cockpit-kubernetes -f kubernetes.list -%{_libexecdir}/cockpit-kube-auth -%{_libexecdir}/cockpit-kube-launch -%{_libexecdir}/cockpit-stub -%endif - %package -n cockpit-packagekit Summary: Cockpit user interface for packages BuildArch: noarch diff --git a/tools/debian/rules b/tools/debian/rules index 6085dbc99..1d7ab0b32 100755 --- a/tools/debian/rules +++ b/tools/debian/rules @@ -42,11 +42,9 @@ override_dh_install: dpkg-vendor --derives-from ubuntu || rm -r debian/tmp/usr/share/cockpit/branding/ubuntu # unpackaged modules - for m in kdump kubernetes selinux subscriptions; do rm -r debian/tmp/usr/share/cockpit/$$m; done + for m in kdump selinux subscriptions; do rm -r debian/tmp/usr/share/cockpit/$$m; done rm debian/tmp/usr/share/metainfo/org.cockpit-project.cockpit-kdump.metainfo.xml rm debian/tmp/usr/share/metainfo/org.cockpit-project.cockpit-selinux.metainfo.xml - # part of kubernetes - rm -f debian/tmp/usr/lib/cockpit/cockpit-stub dh_install --fail-missing -Xusr/src/debug make install-tests DESTDIR=debian/cockpit-tests diff --git a/tools/debian/source/lintian-overrides b/tools/debian/source/lintian-overrides index f219e91ef..040b5f9d9 100644 --- a/tools/debian/source/lintian-overrides +++ b/tools/debian/source/lintian-overrides @@ -2,8 +2,6 @@ cockpit source: source-is-missing node_modules/* # dist/ is (pre-)built by webpack from pkg/ and node_modules, see webpack.config.js cockpit source: source-is-missing dist/*.js* -# false-positive heuristics, this is actual source -cockpit source: source-is-missing pkg/kubernetes/scripts/test-images.js line length* # pkg/machines/include is symlink to node_components/noVNC/include and content is meant as downloadable resource at runtime cockpit source: source-is-missing pkg/machines/include/* # We prefer a newer debhelper which merged dh-systemd diff --git a/tools/webpack-make b/tools/webpack-make index 7b11d5574..207234525 100755 --- a/tools/webpack-make +++ b/tools/webpack-make @@ -137,7 +137,6 @@ function generateDeps(makefile, stats) { if (!endsWith(output, "manifest.json") && !endsWith(output, "override.json") && !endsWith(output, "shell/index.html") && - !endsWith(output, "shell/stub.html") && !endsWith(output, "shell/simple.html") && !endsWith(output, ".png") && !endsWith(output, ".map") && diff --git a/webpack.config.js b/webpack.config.js index 606f90406..39a230f36 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -24,15 +24,6 @@ var info = { "kdump/kdump.css", ], - "kubernetes/kubernetes": [ - "kubernetes/styles/main.less", - "kubernetes/scripts/main.js", - ], - "kubernetes/registry": [ - "kubernetes/styles/registry.less", - "kubernetes/scripts/registry.js", - ], - "machines/machines": [ "machines/index.js", "machines/machines.less", @@ -91,9 +82,6 @@ var info = { "shell/index.js", "shell/shell.less", ], - "shell/index-stub": [ - "shell/index-stub.js", - ], "shell/index-no-machines": [ "shell/index-no-machines.js", ], @@ -161,15 +149,6 @@ var info = { "storaged/test-util", - "kubernetes/scripts/test-utils", - "kubernetes/scripts/test-images", - "kubernetes/scripts/test-projects", - "kubernetes/scripts/test-nodes", - "kubernetes/scripts/test-kube-client", - "kubernetes/scripts/test-tags", - "kubernetes/scripts/test-connection", - "kubernetes/scripts/test-volumes", - "machines/test-machines", ], @@ -185,10 +164,6 @@ var info = { "kdump/index.html", - "kubernetes/override.json", - "kubernetes/index.html", - "kubernetes/registry.html", - "machines/index.html", "networkmanager/index.html", @@ -217,7 +192,6 @@ var info = { "shell/index.html", "shell/simple.html", "shell/shell.html", - "shell/stub.html", "sosreport/index.html", "sosreport/sosreport.png", @@ -345,8 +319,6 @@ info.tests.forEach(function(test) { }); var aliases = { - "angular": "angular/angular.js", - "angular-route": "angular-route/angular-route.js", "d3": "d3/d3.js", "moment": "moment/moment.js", "term": "term.js-cockpit/src/term.js" @@ -437,16 +409,6 @@ module.exports = { } }] }, - { - test: /[\/]angular\.js$/, - use: [{ - loader: 'exports-loader', - - options: { - angular: true - } - }] - } ], } };