Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-12-19 03:08:35 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-12-19 03:08:35 +0300
commit38877019b7b1bf778edb89e7054e74651933e325 (patch)
treeddbf5618b21add45cad2bcc3e32a04798711ac78 /vendor/gems/kubeclient
parent6de8517e0401612bab93c64a24d5b07bf5f36649 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'vendor/gems/kubeclient')
-rw-r--r--vendor/gems/kubeclient/.gitignore16
-rw-r--r--vendor/gems/kubeclient/CHANGELOG.md247
-rw-r--r--vendor/gems/kubeclient/Gemfile7
-rw-r--r--vendor/gems/kubeclient/LICENSE.txt22
-rw-r--r--vendor/gems/kubeclient/README.md889
-rw-r--r--vendor/gems/kubeclient/RELEASING.md69
-rw-r--r--vendor/gems/kubeclient/Rakefile9
-rw-r--r--vendor/gems/kubeclient/kubeclient.gemspec39
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient.rb35
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb46
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/common.rb661
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/config.rb202
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/entity_list.rb21
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb89
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb19
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb31
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb31
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/http_error.rb25
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb68
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb52
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/resource.rb11
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb4
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/version.rb4
-rw-r--r--vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb97
-rw-r--r--vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml879
-rw-r--r--vendor/gems/kubeclient/test/config/allinone.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/another-ca1.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/another-ca2.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig20
-rw-r--r--vendor/gems/kubeclient/test/config/concatenated-ca.pem57
-rw-r--r--vendor/gems/kubeclient/test/config/execauth.kubeconfig61
-rw-r--r--vendor/gems/kubeclient/test/config/external-ca.pem19
-rw-r--r--vendor/gems/kubeclient/test/config/external-cert.pem20
-rw-r--r--vendor/gems/kubeclient/test/config/external-key.rsa27
-rw-r--r--vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/external.kubeconfig20
-rw-r--r--vendor/gems/kubeclient/test/config/gcpauth.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig25
-rw-r--r--vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig22
-rw-r--r--vendor/gems/kubeclient/test/config/insecure.kubeconfig25
-rw-r--r--vendor/gems/kubeclient/test/config/nouser.kubeconfig15
-rw-r--r--vendor/gems/kubeclient/test/config/oidcauth.kubeconfig24
-rw-r--r--vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig22
-rw-r--r--vendor/gems/kubeclient/test/config/secure.kubeconfig21
-rw-r--r--vendor/gems/kubeclient/test/config/timestamps.kubeconfig25
-rwxr-xr-xvendor/gems/kubeclient/test/config/update_certs_k0s.rb53
-rw-r--r--vendor/gems/kubeclient/test/config/userauth.kubeconfig27
-rw-r--r--vendor/gems/kubeclient/test/json/bindings_list.json10
-rw-r--r--vendor/gems/kubeclient/test/json/component_status.json17
-rw-r--r--vendor/gems/kubeclient/test/json/component_status_list.json52
-rw-r--r--vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json679
-rw-r--r--vendor/gems/kubeclient/test/json/config_map_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/core_api_resource_list.json181
-rw-r--r--vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json129
-rw-r--r--vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json197
-rw-r--r--vendor/gems/kubeclient/test/json/created_endpoint.json28
-rw-r--r--vendor/gems/kubeclient/test/json/created_namespace.json20
-rw-r--r--vendor/gems/kubeclient/test/json/created_secret.json16
-rw-r--r--vendor/gems/kubeclient/test/json/created_security_context_constraint.json65
-rw-r--r--vendor/gems/kubeclient/test/json/created_service.json31
-rw-r--r--vendor/gems/kubeclient/test/json/empty_pod_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/endpoint_list.json48
-rw-r--r--vendor/gems/kubeclient/test/json/entity_list.json56
-rw-r--r--vendor/gems/kubeclient/test/json/event_list.json35
-rw-r--r--vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json217
-rw-r--r--vendor/gems/kubeclient/test/json/limit_range.json23
-rw-r--r--vendor/gems/kubeclient/test/json/limit_range_list.json31
-rw-r--r--vendor/gems/kubeclient/test/json/namespace.json13
-rw-r--r--vendor/gems/kubeclient/test/json/namespace_exception.json8
-rw-r--r--vendor/gems/kubeclient/test/json/namespace_list.json32
-rw-r--r--vendor/gems/kubeclient/test/json/node.json29
-rw-r--r--vendor/gems/kubeclient/test/json/node_list.json37
-rw-r--r--vendor/gems/kubeclient/test/json/node_notice.json160
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume.json37
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claim.json32
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json40
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json8
-rw-r--r--vendor/gems/kubeclient/test/json/persistent_volume_list.json45
-rw-r--r--vendor/gems/kubeclient/test/json/pod.json92
-rw-r--r--vendor/gems/kubeclient/test/json/pod_list.json79
-rw-r--r--vendor/gems/kubeclient/test/json/pod_template_list.json9
-rw-r--r--vendor/gems/kubeclient/test/json/pods_1.json265
-rw-r--r--vendor/gems/kubeclient/test/json/pods_2.json102
-rw-r--r--vendor/gems/kubeclient/test/json/pods_410.json9
-rw-r--r--vendor/gems/kubeclient/test/json/processed_template.json27
-rw-r--r--vendor/gems/kubeclient/test/json/replication_controller.json57
-rw-r--r--vendor/gems/kubeclient/test/json/replication_controller_list.json66
-rw-r--r--vendor/gems/kubeclient/test/json/resource_quota.json46
-rw-r--r--vendor/gems/kubeclient/test/json/resource_quota_list.json54
-rw-r--r--vendor/gems/kubeclient/test/json/secret_list.json44
-rw-r--r--vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json69
-rw-r--r--vendor/gems/kubeclient/test/json/security_context_constraint_list.json375
-rw-r--r--vendor/gems/kubeclient/test/json/service.json33
-rw-r--r--vendor/gems/kubeclient/test/json/service_account.json25
-rw-r--r--vendor/gems/kubeclient/test/json/service_account_list.json82
-rw-r--r--vendor/gems/kubeclient/test/json/service_illegal_json_404.json1
-rw-r--r--vendor/gems/kubeclient/test/json/service_json_patch.json26
-rw-r--r--vendor/gems/kubeclient/test/json/service_list.json97
-rw-r--r--vendor/gems/kubeclient/test/json/service_merge_patch.json26
-rw-r--r--vendor/gems/kubeclient/test/json/service_patch.json25
-rw-r--r--vendor/gems/kubeclient/test/json/service_update.json22
-rw-r--r--vendor/gems/kubeclient/test/json/template.json27
-rw-r--r--vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json75
-rw-r--r--vendor/gems/kubeclient/test/json/template_list.json35
-rw-r--r--vendor/gems/kubeclient/test/json/versions_list.json6
-rw-r--r--vendor/gems/kubeclient/test/json/watch_stream.json3
-rw-r--r--vendor/gems/kubeclient/test/test_common.rb95
-rw-r--r--vendor/gems/kubeclient/test/test_common_url_handling.rb160
-rw-r--r--vendor/gems/kubeclient/test/test_component_status.rb29
-rw-r--r--vendor/gems/kubeclient/test/test_config.rb271
-rw-r--r--vendor/gems/kubeclient/test/test_endpoint.rb54
-rw-r--r--vendor/gems/kubeclient/test/test_exec_credentials.rb225
-rw-r--r--vendor/gems/kubeclient/test/test_gcp_command_credentials.rb27
-rw-r--r--vendor/gems/kubeclient/test/test_google_application_default_credentials.rb15
-rw-r--r--vendor/gems/kubeclient/test/test_guestbook_go.rb237
-rw-r--r--vendor/gems/kubeclient/test/test_helper.rb28
-rw-r--r--vendor/gems/kubeclient/test/test_kubeclient.rb881
-rw-r--r--vendor/gems/kubeclient/test/test_limit_range.rb25
-rw-r--r--vendor/gems/kubeclient/test/test_missing_methods.rb80
-rw-r--r--vendor/gems/kubeclient/test/test_namespace.rb59
-rw-r--r--vendor/gems/kubeclient/test/test_node.rb70
-rw-r--r--vendor/gems/kubeclient/test/test_oidc_auth_provider.rb103
-rw-r--r--vendor/gems/kubeclient/test/test_persistent_volume.rb29
-rw-r--r--vendor/gems/kubeclient/test/test_persistent_volume_claim.rb28
-rw-r--r--vendor/gems/kubeclient/test/test_pod.rb81
-rw-r--r--vendor/gems/kubeclient/test/test_pod_log.rb157
-rw-r--r--vendor/gems/kubeclient/test/test_process_template.rb80
-rw-r--r--vendor/gems/kubeclient/test/test_real_cluster.rb162
-rw-r--r--vendor/gems/kubeclient/test/test_replication_controller.rb47
-rw-r--r--vendor/gems/kubeclient/test/test_resource_list_without_kind.rb78
-rw-r--r--vendor/gems/kubeclient/test/test_resource_quota.rb23
-rw-r--r--vendor/gems/kubeclient/test/test_secret.rb62
-rw-r--r--vendor/gems/kubeclient/test/test_security_context_constraint.rb62
-rw-r--r--vendor/gems/kubeclient/test/test_service.rb357
-rw-r--r--vendor/gems/kubeclient/test/test_service_account.rb26
-rw-r--r--vendor/gems/kubeclient/test/test_watch.rb195
-rw-r--r--vendor/gems/kubeclient/test/txt/pod_log.txt6
-rw-r--r--vendor/gems/kubeclient/test/valid_token_file1
138 files changed, 11981 insertions, 0 deletions
diff --git a/vendor/gems/kubeclient/.gitignore b/vendor/gems/kubeclient/.gitignore
new file mode 100644
index 00000000000..a0afe33a553
--- /dev/null
+++ b/vendor/gems/kubeclient/.gitignore
@@ -0,0 +1,16 @@
+/.bundle/
+/.yardoc
+/Gemfile.lock
+/_yardoc/
+/coverage/
+/doc/
+/pkg/
+/spec/reports/
+/tmp/
+*.bundle
+*.so
+*.o
+*.a
+mkmf.log
+*.idea*
+/Gemfile.dev.rb
diff --git a/vendor/gems/kubeclient/CHANGELOG.md b/vendor/gems/kubeclient/CHANGELOG.md
new file mode 100644
index 00000000000..3237d4a3c2d
--- /dev/null
+++ b/vendor/gems/kubeclient/CHANGELOG.md
@@ -0,0 +1,247 @@
+# Changelog
+
+Notable changes to this project will be documented in this file.
+The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/).
+Kubeclient release versioning follows [SemVer](https://semver.org/).
+
+## 4.9.3 — 2021-03-23
+
+### Fixed
+
+- VULNERABILITY FIX: Previously, whenever kubeconfig did not define custom CA
+ (normal situation for production clusters with public domain and certificate!),
+ `Config` was returning ssl_options[:verify_ssl] hard-coded to `VERIFY_NONE` :-(
+
+ Assuming you passed those ssl_options to Kubeclient::Client, this means that
+ instead of checking server's certificate against your system CA store,
+ it would accept ANY certificate, allowing easy man-in-the middle attacks.
+
+ This is especially dangerous with user/password or token credentials
+ because MITM attacker could simply steal those credentials to the cluster
+ and do anything you could do on the cluster.
+
+ This was broken IN ALL RELEASES MADE BEFORE 2022, ever since
+ [`Kubeclient::Config` was created](https://github.com/ManageIQ/kubeclient/pull/127/files#diff-32e70f2f6781a9e9c7b83ae5e7eaf5ffd068a05649077fa38f6789e72f3de837R41-R48).
+
+- Bug fix: kubeconfig `insecure-skip-tls-verify` field was ignored.
+ When kubeconfig did define custom CA, `Config` was returning hard-coded `VERIFY_PEER`.
+
+ Now we honor it, return `VERIFY_NONE` iff kubeconfig has explicit
+ `insecure-skip-tls-verify: true`, otherwise `VERIFY_PEER`.
+
+- `Config`: fixed parsing of `certificate-authority` file containing concatenation of
+ several certificates. Previously, server's cert was checked against only first CA cert,
+ resulting in possible "certificate verify failed" errors.
+
+ An important use case is a chain of root & intermediate cert(s) - necessary when cluster's CA
+ itself is signed by another custom CA.
+ But also helps when you simply concatenate independent certs. (#461, #552)
+
+ - Still broken (#460): inline `certificate-authority-data` is still parsed using `add_cert`
+ method that handles only one cert.
+
+These don't affect code that supplies `Client` parameters directly,
+only code that uses `Config`.
+
+## 4.9.2 — 2021-05-30
+
+### Added
+- Ruby 3.0 compatibility (#500, #505).
+
+### Removed
+- Reduce .gem size by dropping test/ directory, it's useless at run time (#502).
+
+## 4.9.1 — 2020-08-31
+### Fixed
+- Now should work with apiserver deployed not at root of domain but a sub-path,
+ which is standard with Rancher.
+ Notably, `create_...` methods were sending bad apiVersion and getting 400 error.
+ (#457, hopefully fixes #318, #418 and https://gitlab.com/gitlab-org/gitlab/-/issues/22043)
+
+## 4.9.0 - 2020-08-03
+### Added
+- Support for `user: exec` credential plugins using TLS client auth (#453)
+
+## 4.8.0 — 2020-07-03
+
+### Added
+- Support for server-side apply (#448).
+
+### Fixed
+- Declared forgotten dependency on jsonpath, needed for `gcp` provider with `cmd-path` (#450).
+
+## 4.7.0 — 2020-06-14
+
+### Fixed
+- Ruby 2.7 compatibility: bumped minimum recursive-open-struct to one that works on 2.7 (#439).
+- Ruby 2.7 warnings (#433, #438).
+- Improved watch documentation, including behavior planned to change in 5.0.0 (#436).
+
+### Added
+- Google Application Default Credentials: Added `userinfo.email` to requested scopes, which is necessary for RBAC policies (#441).
+
+## 4.6.0 — 2019-12-30
+
+### Fixed
+- AmazonEksCredentials was sometimes leaving base64 padding that IAM auth of the EKS cluster rejects. Now padding is always stripped. (#424, #423)
+
+### Added
+- Allow calling `watch_foos` methods with a block, simpler to use and guarantees closing the connection. (#425)
+
+- Support `limitBytes` query parameter for `get_pod_log`. (#426)
+
+## 4.5.0 — 2019-09-27
+
+### Added
+- Support `:resourceVersion` parameter in `get_foos` methods (similar to existing support in `watch_foos` methods). (#420)
+
+- Relax dependency on `http` gem to allow both 3.x and 4.x. (#413)
+
+## 4.4.0 — 2019-05-03
+
+### Added
+- GCP configs with `user[auth-provider][name] == 'gcp'` will execute credential plugin (normally the `gcloud config config-helper` subcommand) when the config specifies it in `cmd-path`, `cmd-args` fields (similar to `exec` support). This code path works without `googleauth` gem. Otherwise, `GoogleApplicationDefaultCredentials` path will be tried as before. (#410)
+- `AmazonEksCredentials` helper for obtaining a token to authenticate against Amazon EKS. This is not currently integrated in `Config`, you will need to invoke it yourself. You'll need some aws gems that Kubeclient _does not_ include. (#404, #406)
+
+### Changed
+- OpenID Connect tokens which cannot be validaded because we cannot identify the key they were signed with will be considered expired and refreshed as usual. (#407)
+
+## 4.3.0 — 2019-03-03
+
+### Changed
+- `GoogleApplicationDefaultCredentials` will now automatically be used by `Config` if the `user[auth-provider][name] == 'gcp'` in the provided context. Note that `user[exec]` is checked first in anticipation of this functionality being added to GCP sometime in the future. Kubeclient _does not_ include the required `googleauth` gem, so you will need to include it in your calling application. (#394)
+
+### Added
+- OpenID Connect credentials will automatically be used if the `user[auth-provider][name] == 'oidc'` in the provided context. Note that `user[exec]` is checked first. Kubeclient _does not_ include the required `openid_connect` gem, so you will need to include it in your calling application. (#396)
+
+- Support for `json_patch_#{entity}` and `merge_patch_#{entity}`. `patch_#{entity}` will continue to use strategic merge patch. (#390)
+
+## 4.2.2 — 2019-01-09
+
+### Added
+- New `http_max_redirects` option (#374).
+
+### Changed
+- Default max redirects for watch increased from 4 to 10, to match other verbs (#374).
+
+## 4.2.1 — 2018-12-26
+
+### Fixed
+- For resources that contain dashes in name, there will be an attempt to resolve the method name based on singular name prefix or by replacing the dash in names with underscores (#383).
+
+## 4.2.0 — 2018-12-20
+
+### Added
+- Support `user: exec: ...` credential plugins like in Go client (#363, #375).
+
+### Security
+- Really made `Kubeclient::Config.new(data, nil)` prevent external file lookups. (#372)
+ README documented this since 3.1.1 (#334) but alas that was a lie — absolute paths always worked.
+ Now this also prevents credential plugin execution.
+
+ Even in this mode, using config from untrusted sources is not recommended.
+
+This release included all changes up to 4.1.1, but NOT 4.1.2 which was branched off later (4.2.1 does include same fix).
+
+## 4.1.2 — 2018-12-26
+
+### Fixed
+- For resources that contain dashes in name, there will be an attempt to resolve the method name based on singular name prefix or by replacing the dash in names with underscores (#382).
+
+## 4.1.1 — 2018-12-17
+
+### Fixed
+- Fixed method names for non-suffix plurals such as y -> ies (#377).
+
+## 4.1.0 — 2018-11-28 — REGRESSION
+
+This version broke method names where plural is not just adding a suffix, notably y -> ies (bug #376).
+
+### Fixed
+- Support custom resources with lowercase `kind` (#361).
+- `create_security_context_constraint` now works (#366).
+- `get_security_context_constraints.kind`, `get_endpoints.kind` are now plural as in kubernetes (#366).
+
+### Added
+- Add support for retrieving large lists of objects in chunks (#356).
+
+## 4.0.0 — 2018-07-23
+
+### Removed
+- Bumped officially supported kubernetes versions to >= 1.3.
+- Specifically `proxy_url` no longer works for <= 1.2 (#323).
+
+### Fixed
+- `proxy_url` now works for kubernetes 1.10 and later (#323).
+
+### Changed
+- Switched `http` gem dependency from 2.y to 3.y (#321).
+
+## 3.1.2 — 2018-06-11
+
+### Fixed
+- Fixed `Kubeclient::Config.read` regression, no longer crashes on YAML timestamps (#338).
+
+## 3.1.1 - 2018-06-01 — REGRESSION
+
+In this version `Kubeclient::Config.read` raises Psych::DisallowedClass on legal yaml configs containing a timestamp, for example gcp access-token expiry (bug #337).
+
+### Security
+- Changed `Kubeclient::Config.read` to use `YAML.safe_load` (#334).
+
+ Previously, could deserialize arbitrary ruby classes. The risk depends on ruby classes available in the application; sometimes a class may have side effects - up to arbitrary code execution - when instantiated and/or built up with `x[key] = value` during YAML parsing.
+
+ Despite this fix, using config from untrusted sources is not recommended.
+
+## 3.1.0 - 2018-05-27
+
+### Fixed
+- Fixed watch `.finish` sometimes caused `HTTP::ConnectionError` exception from the reading loop (#315).
+
+### Added
+- `get_pod_log` now has `timestamps`, `since_time` (#319) and `tail_lines` (#326) params.
+- `Kubeclient::Config::Context#namespace` now set, if present in kubeconfig file (#308).
+- Improved README directions for authenticating within a kubernetes cluster (#316).
+- `Kubeclient::GoogleApplicationDefaultCredentials` helper for Google application default credentials (#213). Needs `googleauth` gem.
+- New `as: :parsed` and `as: :parsed_symbolized` formats (#306).
+- Allow setting default `as:` format for the whole client (#299, #305).
+- Relaxed `recursive-open-struct` dependency to allow 1.1+ as well (#313).
+
+## 3.0.0 - 2018-02-04
+### Removed
+- Dropped entity classes (`Kubeclient::Pod` etc.), only `Kubeclient::Resource` exists now (#292, #288).
+- Ruby 2.0, 2.1 no longer supported (#253, #291).
+
+### Fixed
+- Added missing singular `get_security_context_constraint`, fixed `get_security_context_constraints` to mean plural (#261).
+- Fixed `@http_proxy_uri` undefined warning (#261).
+- Documentation fixes & improvements (#225, #229, #243, #296).
+
+### Added
+- `delete_options:` parameter to `delete_*` methods, useful for cascade delete (#267).
+- `as: :raw` option for watch (#285).
+- Now raises `Kubeclient::HttpError`. Rescuing `KubeException` still works but is deprecated. (#195, #288)
+ - 404 error raise `Kubeclient::ResourceNotFoundError`, a subclass of `HttpError` (#233).
+- Include request info in exception message (#221).
+- Ruby 2.4 and 2.5 are now supported & tested (#247, #295).
+
+### Changed
+- `Kubeclient::Config#context(nonexistent_context_name)` raises `KeyError` instead of `RuntimeError`.
+- `update_*`, `delete_*`, `patch_*` now all return `RecursiveOpenStruct` consistently (#290).
+- Many dependencies bumped (#204, #231, #253, #269).
+
+## 2.5.2 - 2018-02-04
+- Watch results are now `RecursiveOpenStruct` inside arrays too (#279).
+- Fixed watch `.finish` sometimes caused `Errno::EBADF` exception from the reading loop (#280).
+- Easing dependency version (#287, #301)
+
+## 2.5.1 - 2017-10-12
+No changes since 2.5.0, fixed packaging mistake.
+
+## [2.5.0 - 2017-10-12 was YANKED]
+
+### Added
+
+- `as: raw` option for `get_*` methods returning a string (#262 via #271).
+
+## 2.4.0 - 2017-05-10
diff --git a/vendor/gems/kubeclient/Gemfile b/vendor/gems/kubeclient/Gemfile
new file mode 100644
index 00000000000..da50b39459f
--- /dev/null
+++ b/vendor/gems/kubeclient/Gemfile
@@ -0,0 +1,7 @@
+source 'https://rubygems.org'
+
+dev_gemfile = File.expand_path('Gemfile.dev.rb', __dir__)
+eval_gemfile(dev_gemfile) if File.exist?(dev_gemfile)
+
+# Specify your gem's dependencies in kubeclient.gemspec
+gemspec
diff --git a/vendor/gems/kubeclient/LICENSE.txt b/vendor/gems/kubeclient/LICENSE.txt
new file mode 100644
index 00000000000..c79ef416c4b
--- /dev/null
+++ b/vendor/gems/kubeclient/LICENSE.txt
@@ -0,0 +1,22 @@
+Copyright (c) 2014 Alissa Bonas
+
+MIT License
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/vendor/gems/kubeclient/README.md b/vendor/gems/kubeclient/README.md
new file mode 100644
index 00000000000..6cf0fb67293
--- /dev/null
+++ b/vendor/gems/kubeclient/README.md
@@ -0,0 +1,889 @@
+# Kubeclient
+
+[![Gem Version](https://badge.fury.io/rb/kubeclient.svg)](http://badge.fury.io/rb/kubeclient)
+[![Build Status](https://travis-ci.org/abonas/kubeclient.svg?branch=master)](https://travis-ci.org/abonas/kubeclient)
+[![Code Climate](http://img.shields.io/codeclimate/github/abonas/kubeclient.svg)](https://codeclimate.com/github/abonas/kubeclient)
+
+A Ruby client for Kubernetes REST api.
+The client supports GET, POST, PUT, DELETE on all the entities available in kubernetes in both the core and group apis.
+The client currently supports Kubernetes REST api version v1.
+To learn more about groups and versions in kubernetes refer to [k8s docs](https://kubernetes.io/docs/api/)
+
+## VULNERABILITY❗
+
+If you use `Kubeclient::Config`, all gem versions released before 2022 could return incorrect `ssl_options[:verify_ssl]`,
+endangering your connection and cluster credentials.
+See [latest CHANGELOG.md](https://github.com/ManageIQ/kubeclient/blob/master/CHANGELOG.md) for details and which versions got a fix.
+Open an issue if you want a backport to another version.
+
+## Installation
+
+Add this line to your application's Gemfile:
+
+```ruby
+gem 'kubeclient'
+```
+
+And then execute:
+
+```Bash
+bundle
+```
+
+Or install it yourself as:
+
+```Bash
+gem install kubeclient
+```
+
+## Usage
+
+Initialize the client:
+
+```ruby
+client = Kubeclient::Client.new('http://localhost:8080/api/', "v1")
+```
+
+Or without specifying version (it will be set by default to "v1")
+
+```ruby
+client = Kubeclient::Client.new('http://localhost:8080/api/')
+```
+
+For A Group Api:
+
+```ruby
+client = Kubeclient::Client.new('http://localhost:8080/apis/batch', 'v1')
+```
+
+Another option is to initialize the client with URI object:
+
+```ruby
+uri = URI::HTTP.build(host: "somehostname", port: 8080)
+client = Kubeclient::Client.new(uri)
+```
+
+### SSL
+
+It is also possible to use https and configure ssl with:
+
+```ruby
+ssl_options = {
+ client_cert: OpenSSL::X509::Certificate.new(File.read('/path/to/client.crt')),
+ client_key: OpenSSL::PKey::RSA.new(File.read('/path/to/client.key')),
+ ca_file: '/path/to/ca.crt',
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', "v1", ssl_options: ssl_options
+)
+```
+
+As an alternative to the `ca_file` it's possible to use the `cert_store`:
+
+```ruby
+cert_store = OpenSSL::X509::Store.new
+cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data))
+ssl_options = {
+ cert_store: cert_store,
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', "v1", ssl_options: ssl_options
+)
+```
+
+For testing and development purpose you can disable the ssl check with:
+
+```ruby
+ssl_options = { verify_ssl: OpenSSL::SSL::VERIFY_NONE }
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', ssl_options: ssl_options
+)
+```
+
+### Authentication
+
+If you are using basic authentication or bearer tokens as described
+[here](https://github.com/GoogleCloudPlatform/kubernetes/blob/master/docs/authentication.md) then you can specify one
+of the following:
+
+```ruby
+auth_options = {
+ username: 'username',
+ password: 'password'
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', auth_options: auth_options
+)
+```
+
+or
+
+```ruby
+auth_options = {
+ bearer_token: 'MDExMWJkMjItOWY1Ny00OGM5LWJlNDEtMjBiMzgxODkxYzYz'
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', auth_options: auth_options
+)
+```
+
+or
+
+```ruby
+auth_options = {
+ bearer_token_file: '/path/to/token_file'
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', auth_options: auth_options
+)
+```
+
+#### Inside a Kubernetes cluster
+
+The [recommended way to locate the API server](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) within the pod is with the `kubernetes.default.svc` DNS name, which resolves to a Service IP which in turn will be routed to an API server.
+
+The recommended way to authenticate to the API server is with a [service account](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/). kube-system associates a pod with a service account and a bearer token for that service account is placed into the filesystem tree of each container in that pod at `/var/run/secrets/kubernetes.io/serviceaccount/token`.
+
+If available, a certificate bundle is placed into the filesystem tree of each container at `/var/run/secrets/kubernetes.io/serviceaccount/ca.crt`, and should be used to verify the serving certificate of the API server.
+
+For example:
+
+```ruby
+auth_options = {
+ bearer_token_file: '/var/run/secrets/kubernetes.io/serviceaccount/token'
+}
+ssl_options = {}
+if File.exist?("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
+ ssl_options[:ca_file] = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
+end
+client = Kubeclient::Client.new(
+ 'https://kubernetes.default.svc',
+ 'v1',
+ auth_options: auth_options,
+ ssl_options: ssl_options
+)
+```
+
+Finally, the default namespace to be used for namespaced API operations is placed in a file at `/var/run/secrets/kubernetes.io/serviceaccount/namespace` in each container. It is recommended that you use this namespace when issuing API commands below.
+
+```ruby
+namespace = File.read('/var/run/secrets/kubernetes.io/serviceaccount/namespace')
+```
+You can find information about tokens in [this guide](https://kubernetes.io/docs/tasks/access-application-cluster/access-cluster/#accessing-the-api-from-a-pod) and in [this reference](http://kubernetes.io/docs/admin/authentication/).
+
+### Non-blocking IO
+
+You can also use kubeclient with non-blocking sockets such as Celluloid::IO, see [here](https://github.com/httprb/http/wiki/Parallel-requests-with-Celluloid%3A%3AIO)
+for details. For example:
+
+```ruby
+require 'celluloid/io'
+socket_options = {
+ socket_class: Celluloid::IO::TCPSocket,
+ ssl_socket_class: Celluloid::IO::SSLSocket
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', socket_options: socket_options
+)
+```
+
+This affects only `.watch_*` sockets, not one-off actions like `.get_*`, `.delete_*` etc.
+
+### Proxies
+
+You can also use kubeclient with an http proxy server such as tinyproxy. It can be entered as a string or a URI object.
+For example:
+```ruby
+proxy_uri = URI::HTTP.build(host: "myproxyhost", port: 8443)
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', http_proxy_uri: proxy_uri
+)
+```
+
+### Redirects
+
+You can optionally not allow redirection with kubeclient. For example:
+
+```ruby
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', http_max_redirects: 0
+)
+```
+
+### Timeouts
+
+Watching configures the socket to never time out (however, sooner or later all watches terminate).
+
+One-off actions like `.get_*`, `.delete_*` have a configurable timeout:
+```ruby
+timeouts = {
+ open: 10, # unit is seconds
+ read: nil # nil means never time out
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', timeouts: timeouts
+)
+```
+
+Default timeouts match `Net::HTTP` and `RestClient`, which unfortunately depends on ruby version:
+- open was infinite up to ruby 2.2, 60 seconds in 2.3+.
+- read is 60 seconds.
+
+If you want ruby-independent behavior, always specify `:open`.
+
+### Discovery
+
+Discovery from the kube-apiserver is done lazily on method calls so it would not change behavior.
+
+It can also be done explicitly:
+
+```ruby
+client = Kubeclient::Client.new('http://localhost:8080/api', 'v1')
+client.discover
+```
+
+It is possible to check the status of discovery
+
+```ruby
+unless client.discovered
+ client.discover
+end
+```
+
+### Kubeclient::Config
+
+If you've been using `kubectl` and have a `.kube/config` file (possibly referencing other files in fields such as `client-certificate`), you can auto-populate a config object using `Kubeclient::Config`:
+
+```ruby
+# assuming $KUBECONFIG is one file, won't merge multiple like kubectl
+config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
+```
+
+This will lookup external files; relative paths will be resolved relative to the file's directory, if config refers to them with relative path.
+This includes external [`exec:` credential plugins][exec] to be executed.
+
+[exec]: https://kubernetes.io/docs/reference/access-authn-authz/authentication/#client-go-credential-plugins
+
+You can also construct `Config` directly from nested data. For example if you have JSON or YAML config data in a variable:
+
+```ruby
+config = Kubeclient::Config.new(YAML.safe_load(yaml_text), nil)
+# or
+config = Kubeclient::Config.new(JSON.parse(json_text), nil)
+```
+
+The 2nd argument is a base directory for finding external files, if config refers to them with relative path.
+Setting it to `nil` disables file lookups, and `exec:` execution - such configs will raise an exception. (A config can be self-contained by using inline fields such as `client-certificate-data`.)
+
+To create a client based on a Config object:
+
+```ruby
+# default context according to `current-context` field:
+context = config.context
+# or to use a specific context, by name:
+context = config.context('default/192-168-99-100:8443/system:admin')
+
+Kubeclient::Client.new(
+ context.api_endpoint,
+ 'v1',
+ ssl_options: context.ssl_options,
+ auth_options: context.auth_options
+)
+```
+
+
+#### Amazon EKS Credentials
+
+On Amazon EKS by default the authentication method is IAM. When running kubectl a temporary token is generated by shelling out to
+the aws-iam-authenticator binary which is sent to authenticate the user.
+See [aws-iam-authenticator](https://github.com/kubernetes-sigs/aws-iam-authenticator).
+To replicate that functionality, the `Kubeclient::AmazonEksCredentials` class can accept a set of IAM credentials and
+contains a helper method to generate the authentication token for you.
+
+This requires a set of gems which are _not_ included in
+`kubeclient` dependencies (`aws-sigv4`) so you should add them to your bundle.
+You will also require either the `aws-sdk` v2 or `aws-sdk-core` v3 gems to generate the required `Aws:Credentials` object to pass to this method.
+
+To obtain a token:
+
+```ruby
+require 'aws-sdk-core'
+# Use keys
+credentials = Aws::Credentials.new(access_key, secret_key)
+# Or a profile
+credentials = Aws::SharedCredentials.new(profile_name: 'default').credentials
+
+auth_options = {
+ bearer_token: Kubeclient::AmazonEksCredentials.token(credentials, eks_cluster_name)
+}
+client = Kubeclient::Client.new(
+ eks_cluster_https_endpoint, 'v1', auth_options: auth_options
+)
+```
+
+Note that this returns a token good for one minute. If your code requires authorization for longer than that, you should plan to
+acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
+
+#### Google GCP credential plugin
+
+If kubeconfig file has `user: {auth-provider: {name: gcp, cmd-path: ..., cmd-args: ..., token-key: ...}}`, the command will be executed to obtain a token.
+(Normally this would be a `gcloud config config-helper` command.)
+
+Note that this returns an expiring token. If your code requires authorization for a long time, you should plan to acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
+
+#### Google's Application Default Credentials
+
+On Google Compute Engine, Google App Engine, or Google Cloud Functions, as well as `gcloud`-configured systems
+with [application default credentials](https://developers.google.com/identity/protocols/application-default-credentials),
+kubeclient can use `googleauth` gem to authorize.
+
+This requires the [`googleauth` gem](https://github.com/google/google-auth-library-ruby) that is _not_ included in
+`kubeclient` dependencies so you should add it to your bundle.
+
+If you use `Config.context(...).auth_options` and the kubeconfig file has `user: {auth-provider: {name: gcp}}`, but does not contain `cmd-path` key, kubeclient will automatically try this (raising LoadError if you don't have `googleauth` in your bundle).
+
+Or you can obtain a token manually:
+
+```ruby
+require 'googleauth'
+
+auth_options = {
+ bearer_token: Kubeclient::GoogleApplicationDefaultCredentials.token
+}
+client = Kubeclient::Client.new(
+ 'https://localhost:8443/api/', 'v1', auth_options: auth_options
+)
+```
+
+Note that this returns a token good for one hour. If your code requires authorization for longer than that, you should plan to
+acquire a new one, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
+
+#### OIDC Auth Provider
+
+If the cluster you are using has OIDC authentication enabled you can use the `openid_connect` gem to obtain
+id-tokens if the one in your kubeconfig has expired.
+
+This requires the [`openid_connect` gem](https://github.com/nov/openid_connect) which is not included in
+the `kubeclient` dependencies so should be added to your own applications bundle.
+
+The OIDC Auth Provider will not perform the initial setup of your `$KUBECONFIG` file. You will need to use something
+like [`dexter`](https://github.com/gini/dexter) in order to configure the auth-provider in your `$KUBECONFIG` file.
+
+If you use `Config.context(...).auth_options` and the `$KUBECONFIG` file has user: `{auth-provider: {name: oidc}}`,
+kubeclient will automatically obtain a token (or use `id-token` if still valid)
+
+Tokens are typically short-lived (e.g. 1 hour) and the expiration time is determined by the OIDC Provider (e.g. Google).
+If your code requires authentication for longer than that you should obtain a new token periodically, see [How to manually renew](#how-to-manually-renew-expired-credentials) section.
+
+Note: id-tokens retrieved via this provider are not written back to the `$KUBECONFIG` file as they would be when
+using `kubectl`.
+
+#### How to manually renew expired credentials
+
+Kubeclient [does not yet](https://github.com/abonas/kubeclient/issues/393) help with this.
+
+The division of labor between `Config` and `Context` objects may change, for now please make no assumptions at which stage `exec:` and `auth-provider:` are handled and whether they're cached.
+The currently guaranteed way to renew is create a new `Config` object.
+
+The more painful part is that you'll then need to create new `Client` object(s) with the credentials from new config.
+So repeat all of this:
+```ruby
+config = Kubeclient::Config.read(ENV['KUBECONFIG'] || '/path/to/.kube/config')
+context = config.context
+ssl_options = context.ssl_options
+auth_options = context.auth_options
+
+client = Kubeclient::Client.new(
+ context.api_endpoint, 'v1',
+ ssl_options: ssl_options, auth_options: auth_options
+)
+# and additional Clients if needed...
+```
+
+#### Security: Don't use config from untrusted sources
+
+`Config.read` is catastrophically unsafe — it will execute arbitrary command lines specified by the config!
+
+`Config.new(data, nil)` is better but Kubeclient was never reviewed for behaving safely with malicious / malformed config.
+It might crash / misbehave in unexpected ways...
+
+#### namespace
+
+Additionally, the `config.context` object will contain a `namespace` attribute, if it was defined in the file.
+It is recommended that you use this namespace when issuing API commands below.
+This is the same behavior that is implemented by `kubectl` command.
+
+You can read it as follows:
+
+```ruby
+puts config.context.namespace
+```
+
+### Supported kubernetes versions
+
+We try to support the last 3 minor versions, matching the [official support policy for Kubernetes](https://github.com/kubernetes/community/blob/master/contributors/design-proposals/release/versioning.md#supported-releases-and-component-skew).
+Kubernetes 1.2 and below have known issues and are unsupported.
+Kubernetes 1.3 presumed to still work although nobody is really testing on such old versions...
+
+## Supported actions & examples:
+
+Summary of main CRUD actions:
+
+```
+get_foos(namespace: 'namespace', **opts) # namespaced collection
+get_foos(**opts) # all namespaces or global collection
+
+get_foo('name', 'namespace', opts) # namespaced
+get_foo('name', nil, opts) # global
+
+watch_foos(namespace: ns, **opts) # namespaced collection
+watch_foos(**opts) # all namespaces or global collection
+watch_foos(namespace: ns, name: 'name', **opts) # namespaced single object
+watch_foos(name: 'name', **opts) # global single object
+
+delete_foo('name', 'namespace', opts) # namespaced
+delete_foo('name', nil, opts) # global
+
+create_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}))
+create_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...})) # global
+
+update_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}))
+update_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...})) # global
+
+patch_foo('name', patch, 'namespace') # namespaced
+patch_foo('name', patch) # global
+
+apply_foo(Kubeclient::Resource.new({metadata: {name: 'name', namespace: 'namespace', ...}, ...}), field_manager: 'myapp', **opts)
+apply_foo(Kubeclient::Resource.new({metadata: {name: 'name', ...}, ...}), field_manager: 'myapp', **opts) # global
+```
+
+These grew to be quite inconsistent :confounded:, see https://github.com/abonas/kubeclient/issues/312 and https://github.com/abonas/kubeclient/issues/332 for improvement plans.
+
+### Get all instances of a specific entity type
+Such as: `get_pods`, `get_secrets`, `get_services`, `get_nodes`, `get_replication_controllers`, `get_resource_quotas`, `get_limit_ranges`, `get_persistent_volumes`, `get_persistent_volume_claims`, `get_component_statuses`, `get_service_accounts`
+
+```ruby
+pods = client.get_pods
+```
+
+Get all entities of a specific type in a namespace:
+
+```ruby
+services = client.get_services(namespace: 'development')
+```
+
+You can get entities which have specific labels by specifying a parameter named `label_selector` (named `labelSelector` in Kubernetes server):
+
+```ruby
+pods = client.get_pods(label_selector: 'name=redis-master')
+```
+
+You can specify multiple labels (that option will return entities which have both labels:
+
+```ruby
+pods = client.get_pods(label_selector: 'name=redis-master,app=redis')
+```
+
+There is also [a limited ability to filter by *some* fields](https://kubernetes.io/docs/concepts/overview/working-with-objects/field-selectors/). Which fields are supported is not documented, you can try and see if you get an error...
+```ruby
+client.get_pods(field_selector: 'spec.nodeName=master-0')
+```
+
+You can ask for entities at a specific version by specifying a parameter named `resource_version`:
+```ruby
+pods = client.get_pods(resource_version: '0')
+```
+but it's not guaranteed you'll get it. See https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions to understand the semantics.
+
+With default (`as: :ros`) return format, the returned object acts like an array of the individual pods, but also supports a `.resourceVersion` method.
+
+With `:parsed` and `:parsed_symbolized` formats, the returned data structure matches kubernetes list structure: it's a hash containing `metadata` and `items` keys, the latter containing the individual pods.
+
+#### Get all entities of a specific type in chunks
+
+```ruby
+continue = nil
+loop do
+ entities = client.get_pods(limit: 1_000, continue: continue)
+ continue = entities.continue
+
+ break if entities.last?
+end
+```
+
+See https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks for more information.
+
+The continue tokens expire after a short amount of time, so similar to a watch if you don't request a subsequent page within aprox. 5 minutes of the previous page being returned the server will return a `410 Gone` error and the client must request the list from the start (i.e. omit the continue token for the next call).
+
+Support for chunking was added in v1.9 so previous versions will ignore the option and return the full collection.
+
+#### Get a specific instance of an entity (by name)
+Such as: `get_service "service name"` , `get_pod "pod name"` , `get_replication_controller "rc name"`, `get_secret "secret name"`, `get_resource_quota "resource quota name"`, `get_limit_range "limit range name"` , `get_persistent_volume "persistent volume name"` , `get_persistent_volume_claim "persistent volume claim name"`, `get_component_status "component name"`, `get_service_account "service account name"`
+
+The GET request should include the namespace name, except for nodes and namespaces entities.
+
+```ruby
+node = client.get_node "127.0.0.1"
+```
+
+```ruby
+service = client.get_service "guestbook", 'development'
+```
+
+Note - Kubernetes doesn't work with the uid, but rather with the 'name' property.
+Querying with uid causes 404.
+
+#### Getting raw responses
+
+To avoid overhead from parsing and building `RecursiveOpenStruct` objects for each reply, pass the `as: :raw` option when initializing `Kubeclient::Client` or when calling `get_` / `watch_` methods.
+The result can then be printed, or searched with a regex, or parsed via `JSON.parse(r)`.
+
+```ruby
+client = Kubeclient::Client.new(as: :raw)
+```
+
+or
+
+```ruby
+pods = client.get_pods as: :raw
+node = client.get_node "127.0.0.1", as: :raw
+```
+
+Other formats are:
+ - `:ros` (default) for `RecursiveOpenStruct`
+ - `:parsed` for `JSON.parse`
+ - `:parsed_symbolized` for `JSON.parse(..., symbolize_names: true)`
+
+### Watch — Receive entities updates
+
+See https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes for an overview.
+
+It is possible to receive live update notices watching the relevant entities:
+
+```ruby
+client.watch_pods do |notice|
+ # process notice data
+end
+```
+
+The notices have `.type` field which may be `'ADDED'`, `'MODIFIED'`, `'DELETED'`, or currently `'ERROR'`, and an `.object` field containing the object. **UPCOMING CHANGE**: In next major version, we plan to raise exceptions instead of passing on ERROR into the block.
+
+For namespaced entities, the default watches across all namespaces, and you can specify `client.watch_secrets(namespace: 'foo')` to only watch in a single namespace.
+
+You can narrow down using `label_selector:` and `field_selector:` params, like with `get_pods` methods.
+
+You can also watch a single object by specifying `name:` e.g. `client.watch_nodes(name: 'gandalf')` (not namespaced so a name is enough) or `client.watch_pods(namespace: 'foo', name: 'bar')` (namespaced, need both params).
+Note the method name is still plural! There is no `watch_pod`, only `watch_pods`. The yielded "type" remains the same — watch notices, it's just they'll always refer to the same object.
+
+You can use `as:` param to control the format of the yielded notices.
+
+#### All watches come to an end!
+
+While nominally the watch block *looks* like an infinite loop, that's unrealistic. Network connections eventually get severed, and kubernetes apiserver is known to terminate watches.
+
+Unfortunately, this sometimes raises an exception and sometimes the loop just exits. **UPCOMING CHANGE**: In next major version, non-deliberate termination will always raise an exception; the block will only exit silenty if stopped deliberately.
+
+#### Deliberately stopping a watch
+
+You can use `break` or `return` inside the watch block.
+
+It is possible to interrupt the watcher from another thread with:
+
+```ruby
+watcher = client.watch_pods
+
+watcher.each do |notice|
+ # process notice data
+end
+# <- control will pass here after .finish is called
+
+### In another thread ###
+watcher.finish
+```
+
+#### Starting watch version
+
+You can specify version to start from, commonly used in "List+Watch" pattern:
+```
+list = client.get_pods
+collection_version = list.resourceVersion
+# or with other return formats:
+list = client.get_pods(as: :parsed)
+collection_version = list['metadata']['resourceVersion']
+
+# note spelling resource_version vs resourceVersion.
+client.watch_pods(resource_version: collection_version) do |notice|
+ # process notice data
+end
+```
+It's important to understand [the effects of unset/0/specific resource_version](https://kubernetes.io/docs/reference/using-api/api-concepts/#resource-versions) as it modifies the behavior of the watch — in some modes you'll first see a burst of synthetic 'ADDED' notices for all existing objects.
+
+If you re-try a terminated watch again without specific resourceVersion, you might see previously seen notices again, and might miss some events.
+
+To attempt resuming a watch from same point, you can try using last resourceVersion observed during the watch. Or do list+watch again.
+
+Whenever you ask for a specific version, you must be prepared for an 410 "Gone" error if the server no longer recognizes it.
+
+#### Watch events about a particular object
+Events are [entities in their own right](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.17/#event-v1-core).
+You can use the `field_selector` option as part of the watch methods.
+
+```ruby
+client.watch_events(namespace: 'development', field_selector: 'involvedObject.name=redis-master') do |notice|
+ # process notice date
+end
+```
+
+### Delete an entity (by name)
+
+For example: `delete_pod "pod name"` , `delete_replication_controller "rc name"`, `delete_node "node name"`, `delete_secret "secret name"`
+
+Input parameter - name (string) specifying service name, pod name, replication controller name.
+
+```ruby
+deleted = client.delete_service("redis-service")
+```
+
+If you want to cascade delete, for example a deployment, you can use the `delete_options` parameter.
+
+```ruby
+deployment_name = 'redis-deployment'
+namespace = 'default'
+delete_options = Kubeclient::Resource.new(
+ apiVersion: 'meta/v1',
+ gracePeriodSeconds: 0,
+ kind: 'DeleteOptions',
+ propagationPolicy: 'Foreground' # Orphan, Foreground, or Background
+)
+client.delete_deployment(deployment_name, namespace, delete_options: delete_options)
+```
+
+### Create an entity
+For example: `create_pod pod_object`, `create_replication_controller rc_obj`, `create_secret secret_object`, `create_resource_quota resource_quota_object`, `create_limit_range limit_range_object`, `create_persistent_volume persistent_volume_object`, `create_persistent_volume_claim persistent_volume_claim_object`, `create_service_account service_account_object`
+
+Input parameter - object of type `Service`, `Pod`, `ReplicationController`.
+
+The below example is for v1
+
+```ruby
+service = Kubeclient::Resource.new
+service.metadata = {}
+service.metadata.name = "redis-master"
+service.metadata.namespace = 'staging'
+service.spec = {}
+service.spec.ports = [{
+ 'port' => 6379,
+ 'targetPort' => 'redis-server'
+}]
+service.spec.selector = {}
+service.spec.selector.name = "redis"
+service.spec.selector.role = "master"
+service.metadata.labels = {}
+service.metadata.labels.app = 'redis'
+service.metadata.labels.role = 'slave'
+client.create_service(service)
+```
+
+### Update an entity
+For example: `update_pod`, `update_service`, `update_replication_controller`, `update_secret`, `update_resource_quota`, `update_limit_range`, `update_persistent_volume`, `update_persistent_volume_claim`, `update_service_account`
+
+Input parameter - object of type `Pod`, `Service`, `ReplicationController` etc.
+
+The below example is for v1
+
+```ruby
+updated = client.update_service(service1)
+```
+
+### Patch an entity (by name)
+For example: `patch_pod`, `patch_service`, `patch_secret`, `patch_resource_quota`, `patch_persistent_volume`
+
+Input parameters - name (string) specifying the entity name, patch (hash) to be applied to the resource, optional: namespace name (string)
+
+The PATCH request should include the namespace name, except for nodes and namespaces entities.
+
+The below example is for v1
+
+```ruby
+patched = client.patch_pod("docker-registry", {metadata: {annotations: {key: 'value'}}}, "default")
+```
+
+`patch_#{entity}` is called using a [strategic merge patch](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#notes-on-the-strategic-merge-patch). `json_patch_#{entity}` and `merge_patch_#{entity}` are also available that use JSON patch and JSON merge patch, respectively. These strategies are useful for resources that do not support strategic merge patch, such as Custom Resources. Consult the [Kubernetes docs](https://kubernetes.io/docs/tasks/run-application/update-api-object-kubectl-patch/#use-a-json-merge-patch-to-update-a-deployment) for more information about the different patch strategies.
+
+### Apply an entity
+
+This is similar to `kubectl apply --server-side` (kubeclient doesn't implement logic for client-side apply). See https://kubernetes.io/docs/reference/using-api/api-concepts/#server-side-apply
+
+For example: `apply_pod`
+
+Input parameters - resource (Kubeclient::Resource) representing the desired state of the resource, field_manager (String) to identify the system managing the state of the resource, force (Boolean) whether or not to override a field managed by someone else.
+
+Example:
+
+```ruby
+service = Kubeclient::Resource.new(
+ metadata: {
+ name: 'redis-master',
+ namespace: 'staging',
+ },
+ spec: {
+ ...
+ }
+)
+
+client.apply_service(service, field_manager: 'myapp')
+```
+
+### Get all entities of all types : all_entities
+
+Makes requests for all entities of each discovered kind (in this client's API group). This method is a convenience method instead of calling each entity's get method separately.
+
+Returns a hash with keys being the *singular* entity kind, in lowercase underscore style. For example for core API group may return keys `"node'`, `"secret"`, `"service"`, `"pod"`, `"replication_controller"`, `"namespace"`, `"resource_quota"`, `"limit_range"`, `"endpoint"`, `"event"`, `"persistent_volume"`, `"persistent_volume_claim"`, `"component_status"`, `"service_account"`. Each key points to an EntityList of same type.
+
+```ruby
+client.all_entities
+```
+
+### Get a proxy URL
+You can get a complete URL for connecting a kubernetes entity via the proxy.
+
+```ruby
+client.proxy_url('service', 'srvname', 'srvportname', 'ns')
+# => "https://localhost.localdomain:8443/api/v1/proxy/namespaces/ns/services/srvname:srvportname"
+```
+
+Note the third parameter, port, is a port name for services and an integer for pods:
+
+```ruby
+client.proxy_url('pod', 'podname', 5001, 'ns')
+# => "https://localhost.localdomain:8443/api/v1/namespaces/ns/pods/podname:5001/proxy"
+```
+
+### Get the logs of a pod
+You can get the logs of a running pod, specifying the name of the pod and the
+namespace where the pod is running:
+
+```ruby
+client.get_pod_log('pod-name', 'default')
+# => "Running...\nRunning...\nRunning...\n"
+```
+
+If that pod has more than one container, you must specify the container:
+
+```ruby
+client.get_pod_log('pod-name', 'default', container: 'ruby')
+# => "..."
+```
+
+If a container in a pod terminates, a new container is started, and you want to
+retrieve the logs of the dead container, you can pass in the `:previous` option:
+
+```ruby
+client.get_pod_log('pod-name', 'default', previous: true)
+# => "..."
+```
+
+Kubernetes can add timestamps to every log line or filter by lines time:
+```ruby
+client.get_pod_log('pod-name', 'default', timestamps: true, since_time: '2018-04-27T18:30:17.480321984Z')
+# => "..."
+```
+`since_time` can be a a `Time`, `DateTime` or `String` formatted according to RFC3339
+
+Kubernetes can fetch a specific number of lines from the end of the logs:
+```ruby
+client.get_pod_log('pod-name', 'default', tail_lines: 10)
+# => "..."
+```
+
+Kubernetes can fetch a specific number of bytes from the log, but the exact size is not guaranteed and last line may not be terminated:
+```ruby
+client.get_pod_log('pod-name', 'default', limit_bytes: 10)
+# => "..."
+```
+
+You can also watch the logs of a pod to get a stream of data:
+
+```ruby
+client.watch_pod_log('pod-name', 'default', container: 'ruby') do |line|
+ puts line
+end
+```
+
+### OpenShift: Process a template
+Returns a processed template containing a list of objects to create.
+Input parameter - template (hash)
+Besides its metadata, the template should include a list of objects to be processed and a list of parameters
+to be substituted. Note that for a required parameter that does not provide a generated value, you must supply a value.
+
+##### Note: This functionality is not supported by K8s at this moment. See the following [issue](https://github.com/kubernetes/kubernetes/issues/23896)
+
+```ruby
+client.process_template template
+```
+
+## Upgrading
+
+Kubeclient release versioning follows [SemVer](https://semver.org/).
+See [CHANGELOG.md](CHANGELOG.md) for full changelog.
+
+#### past version 4.0
+
+Old kubernetes versions < 1.3 no longer supported.
+
+#### past version 3.0
+
+Ruby versions < 2.2 are no longer supported
+
+Specific entity classes mentioned in [past version 1.2.0](#past_version_1.2.0) have been dropped.
+Return values and expected classes are always Kubeclient::Resource.
+Checking the type of a resource can be done using:
+```
+> pod.kind
+=> "Pod"
+```
+
+update_* delete_* and patch_* now return a RecursiveOpenStruct like the get_* methods
+
+The `Kubeclient::Client` class raises `Kubeclient::HttpError` or subclasses now. Catching `KubeException` still works but is deprecated.
+
+`Kubeclient::Config#context` raises `KeyError` instead of `RuntimeError` for non-existent context name.
+
+<a name="past_version_1.2.0">
+
+#### past version 1.2.0
+Replace Specific Entity class references:
+
+```ruby
+Kubeclient::Service
+```
+
+with the generic
+
+```ruby
+Kubeclient::Resource.new
+```
+
+Where ever possible.
+
+## Contributing
+
+1. Fork it ( https://github.com/[my-github-username]/kubeclient/fork )
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Test your changes with `rake test rubocop`, add new tests if needed.
+4. If you added a new functionality, add it to README
+5. Commit your changes (`git commit -am 'Add some feature'`)
+6. Push to the branch (`git push origin my-new-feature`)
+7. Create a new Pull Request
+
+## Tests
+
+This client is tested with Minitest and also uses VCR recordings in some tests.
+Please run all tests before submitting a Pull Request, and add new tests for new functionality.
+
+Running tests:
+```ruby
+rake test
+```
diff --git a/vendor/gems/kubeclient/RELEASING.md b/vendor/gems/kubeclient/RELEASING.md
new file mode 100644
index 00000000000..c8a9a121eda
--- /dev/null
+++ b/vendor/gems/kubeclient/RELEASING.md
@@ -0,0 +1,69 @@
+# Releasing Kubeclient
+
+## Versioning
+Kubeclient release versioning follows [SemVer](https://semver.org/).
+At some point in time it is decided to release version x.y.z.
+
+```bash
+RELEASE_BRANCH="master"
+```
+
+## 0. (once) Install gem-release, needed for several commands here:
+
+```bash
+gem install gem-release
+```
+
+## 1. PR(s) for changelog & bump
+
+Edit `CHANGELOG.md` as necessary. Even if all included changes remembered to update it, you should replace "Unreleased" section header with appropriate "x.y.z — 20yy-mm-dd" header.
+
+Bump `lib/kubeclient/version.rb` manually, or by using:
+```bash
+RELEASE_VERSION=x.y.z
+
+git checkout -b "release-$RELEASE_VERSION" $RELEASE_BRANCH
+# Won't work with uncommitted changes, you have to commit the changelog first.
+gem bump --version $RELEASE_VERSION
+git show # View version bump change.
+```
+
+Open a PR with target branch $RELEASE_BRANCH and get it reviewed & merged (if open for long, remember to update date in CHANGELOG to actual day of release).
+
+## 2. (once) Grabbing an authentication token for rubygems.org api
+```bash
+RUBYGEMS_USERNAME=bob
+curl -u $RUBYGEMS_USERNAME https://rubygems.org/api/v1/api_key.yaml > ~/.gem/credentials; chmod 0600 ~/.gem/credentials
+
+cat ~/.gem/credentials
+# Should look like this:
+:rubygems_api_key: ****
+```
+
+## 3. Actual release
+
+Make sure we're locally after the bump PR *merge commit*:
+```bash
+git checkout $RELEASE_BRANCH
+git status # Make sure there are no local changes
+git pull --ff-only https://github.com/abonas/kubeclient $RELEASE_BRANCH
+git log -n1
+```
+
+Last sanity check:
+```bash
+bundle install
+bundle exec rake test rubocop
+```
+
+Create and push the tag:
+```bash
+gem tag --no-push
+git push --tags --dry-run https://github.com/abonas/kubeclient # Check for unexpected tags
+git push --tags https://github.com/abonas/kubeclient
+```
+
+Release onto rubygems.org:
+```bash
+gem release
+```
diff --git a/vendor/gems/kubeclient/Rakefile b/vendor/gems/kubeclient/Rakefile
new file mode 100644
index 00000000000..a749a9c926e
--- /dev/null
+++ b/vendor/gems/kubeclient/Rakefile
@@ -0,0 +1,9 @@
+require 'bundler/gem_tasks'
+require 'rake/testtask'
+require 'rubocop/rake_task'
+require 'yaml'
+
+task default: %i[test rubocop] # same as .travis.yml
+
+Rake::TestTask.new
+RuboCop::RakeTask.new
diff --git a/vendor/gems/kubeclient/kubeclient.gemspec b/vendor/gems/kubeclient/kubeclient.gemspec
new file mode 100644
index 00000000000..975db8cdb59
--- /dev/null
+++ b/vendor/gems/kubeclient/kubeclient.gemspec
@@ -0,0 +1,39 @@
+# coding: utf-8
+
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'kubeclient/version'
+
+Gem::Specification.new do |spec|
+ spec.name = 'kubeclient'
+ spec.version = Kubeclient::VERSION
+ spec.authors = ['Alissa Bonas']
+ spec.email = ['abonas@redhat.com']
+ spec.summary = 'A client for Kubernetes REST api'
+ spec.description = 'A client for Kubernetes REST api'
+ spec.homepage = 'https://github.com/abonas/kubeclient'
+ spec.license = 'MIT'
+
+ spec.files = Dir.glob("lib/**/*.*")
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+ spec.test_files = []
+ spec.require_paths = ['lib']
+ spec.required_ruby_version = '>= 2.2.0'
+
+ spec.add_development_dependency 'bundler', '>= 1.6'
+ spec.add_development_dependency 'rake', '~> 13.0'
+ spec.add_development_dependency 'minitest', '~> 5.15.0'
+ spec.add_development_dependency 'minitest-rg'
+ spec.add_development_dependency 'webmock', '~> 3.0'
+ spec.add_development_dependency 'vcr'
+ spec.add_development_dependency 'rubocop', '= 0.49.1'
+ spec.add_development_dependency 'googleauth', '~> 0.5.1'
+ spec.add_development_dependency('mocha', '~> 1.5')
+ spec.add_development_dependency 'openid_connect', '~> 1.1'
+ spec.add_development_dependency 'net-smtp'
+
+ spec.add_dependency 'jsonpath', '~> 1.0'
+ spec.add_dependency 'rest-client', '~> 2.0'
+ spec.add_dependency 'recursive-open-struct', '~> 1.1', '>= 1.1.1'
+ spec.add_dependency 'http', '>= 3.0', '< 6.0'
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient.rb b/vendor/gems/kubeclient/lib/kubeclient.rb
new file mode 100644
index 00000000000..eed4872834e
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient.rb
@@ -0,0 +1,35 @@
+require 'json'
+require 'rest-client'
+
+require 'kubeclient/aws_eks_credentials'
+require 'kubeclient/common'
+require 'kubeclient/config'
+require 'kubeclient/entity_list'
+require 'kubeclient/exec_credentials'
+require 'kubeclient/gcp_auth_provider'
+require 'kubeclient/http_error'
+require 'kubeclient/missing_kind_compatibility'
+require 'kubeclient/oidc_auth_provider'
+require 'kubeclient/resource'
+require 'kubeclient/resource_not_found_error'
+require 'kubeclient/version'
+require 'kubeclient/watch_stream'
+
+module Kubeclient
+ # Kubernetes Client
+ class Client
+ include ClientMixin
+ def initialize(
+ uri,
+ version = 'v1',
+ **options
+ )
+ initialize_client(
+ uri,
+ '/api',
+ version,
+ **options
+ )
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb
new file mode 100644
index 00000000000..9b54b9e06cc
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/aws_eks_credentials.rb
@@ -0,0 +1,46 @@
+# frozen_string_literal: true
+
+module Kubeclient
+ # Get a bearer token to authenticate against aws eks.
+ class AmazonEksCredentials
+ class AmazonEksDependencyError < LoadError # rubocop:disable Lint/InheritException
+ end
+
+ class << self
+ def token(credentials, eks_cluster)
+ begin
+ require 'aws-sigv4'
+ require 'base64'
+ require 'cgi'
+ rescue LoadError => e
+ raise AmazonEksDependencyError,
+ 'Error requiring aws gems. Kubeclient itself does not include the following ' \
+ 'gems: [aws-sigv4]. To support auth-provider eks, you must ' \
+ "include it in your calling application. Failed with: #{e.message}"
+ end
+ # https://github.com/aws/aws-sdk-ruby/pull/1848
+ # Get a signer
+ # Note - sts only has ONE endpoint (not regional) so 'us-east-1' hardcoding should be OK
+ signer = Aws::Sigv4::Signer.new(
+ service: 'sts',
+ region: 'us-east-1',
+ credentials: credentials
+ )
+
+ # https://docs.aws.amazon.com/sdk-for-ruby/v3/api/Aws/Sigv4/Signer.html#presign_url-instance_method
+ presigned_url_string = signer.presign_url(
+ http_method: 'GET',
+ url: 'https://sts.amazonaws.com/?Action=GetCallerIdentity&Version=2011-06-15',
+ body: '',
+ credentials: credentials,
+ expires_in: 60,
+ headers: {
+ 'X-K8s-Aws-Id' => eks_cluster
+ }
+ )
+ kube_token = 'k8s-aws-v1.' + Base64.urlsafe_encode64(presigned_url_string.to_s).sub(/=*$/, '') # rubocop:disable Metrics/LineLength
+ kube_token
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/common.rb b/vendor/gems/kubeclient/lib/kubeclient/common.rb
new file mode 100644
index 00000000000..51087fbe888
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/common.rb
@@ -0,0 +1,661 @@
+require 'json'
+require 'rest-client'
+
+module Kubeclient
+ # Common methods
+ # this is mixed in by other gems
+ module ClientMixin
+ ENTITY_METHODS = %w[get watch delete create update patch json_patch merge_patch apply].freeze
+
+ DEFAULT_SSL_OPTIONS = {
+ client_cert: nil,
+ client_key: nil,
+ ca_file: nil,
+ cert_store: nil,
+ verify_ssl: OpenSSL::SSL::VERIFY_PEER
+ }.freeze
+
+ DEFAULT_AUTH_OPTIONS = {
+ username: nil,
+ password: nil,
+ bearer_token: nil,
+ bearer_token_file: nil
+ }.freeze
+
+ DEFAULT_SOCKET_OPTIONS = {
+ socket_class: nil,
+ ssl_socket_class: nil
+ }.freeze
+
+ DEFAULT_TIMEOUTS = {
+ # These do NOT affect watch, watching never times out.
+ open: Net::HTTP.new('127.0.0.1').open_timeout, # depends on ruby version
+ read: Net::HTTP.new('127.0.0.1').read_timeout
+ }.freeze
+
+ DEFAULT_HTTP_PROXY_URI = nil
+ DEFAULT_HTTP_MAX_REDIRECTS = 10
+
+ SEARCH_ARGUMENTS = {
+ 'labelSelector' => :label_selector,
+ 'fieldSelector' => :field_selector,
+ 'resourceVersion' => :resource_version,
+ 'limit' => :limit,
+ 'continue' => :continue
+ }.freeze
+
+ WATCH_ARGUMENTS = {
+ 'labelSelector' => :label_selector,
+ 'fieldSelector' => :field_selector,
+ 'resourceVersion' => :resource_version
+ }.freeze
+
+ attr_reader :api_endpoint
+ attr_reader :ssl_options
+ attr_reader :auth_options
+ attr_reader :http_proxy_uri
+ attr_reader :http_max_redirects
+ attr_reader :headers
+ attr_reader :discovered
+
+ def initialize_client(
+ uri,
+ path,
+ version,
+ ssl_options: DEFAULT_SSL_OPTIONS,
+ auth_options: DEFAULT_AUTH_OPTIONS,
+ socket_options: DEFAULT_SOCKET_OPTIONS,
+ timeouts: DEFAULT_TIMEOUTS,
+ http_proxy_uri: DEFAULT_HTTP_PROXY_URI,
+ http_max_redirects: DEFAULT_HTTP_MAX_REDIRECTS,
+ as: :ros
+ )
+ validate_auth_options(auth_options)
+ handle_uri(uri, path)
+
+ @entities = {}
+ @discovered = false
+ @api_version = version
+ @headers = {}
+ @ssl_options = ssl_options
+ @auth_options = auth_options
+ @socket_options = socket_options
+ # Allow passing partial timeouts hash, without unspecified
+ # @timeouts[:foo] == nil resulting in infinite timeout.
+ @timeouts = DEFAULT_TIMEOUTS.merge(timeouts)
+ @http_proxy_uri = http_proxy_uri ? http_proxy_uri.to_s : nil
+ @http_max_redirects = http_max_redirects
+ @as = as
+
+ if auth_options[:bearer_token]
+ bearer_token(@auth_options[:bearer_token])
+ elsif auth_options[:bearer_token_file]
+ validate_bearer_token_file
+ bearer_token(File.read(@auth_options[:bearer_token_file]))
+ end
+ end
+
+ def method_missing(method_sym, *args, &block)
+ if discovery_needed?(method_sym)
+ discover
+ send(method_sym, *args, &block)
+ else
+ super
+ end
+ end
+
+ def respond_to_missing?(method_sym, include_private = false)
+ if discovery_needed?(method_sym)
+ discover
+ respond_to?(method_sym, include_private)
+ else
+ super
+ end
+ end
+
+ def discovery_needed?(method_sym)
+ !@discovered && ENTITY_METHODS.any? { |x| method_sym.to_s.start_with?(x) }
+ end
+
+ def handle_exception
+ yield
+ rescue RestClient::Exception => e
+ json_error_msg = begin
+ JSON.parse(e.response || '') || {}
+ rescue JSON::ParserError
+ {}
+ end
+ err_message = json_error_msg['message'] || e.message
+ error_klass = e.http_code == 404 ? ResourceNotFoundError : HttpError
+ raise error_klass.new(e.http_code, err_message, e.response)
+ end
+
+ def discover
+ load_entities
+ define_entity_methods
+ @discovered = true
+ end
+
+ def self.parse_definition(kind, name)
+ # Kubernetes gives us 3 inputs:
+ # kind: "ComponentStatus", "NetworkPolicy", "Endpoints"
+ # name: "componentstatuses", "networkpolicies", "endpoints"
+ # singularName: "componentstatus" etc (usually omitted, defaults to kind.downcase)
+ # and want to derive singular and plural method names, with underscores:
+ # "network_policy"
+ # "network_policies"
+ # kind's CamelCase word boundaries determine our placement of underscores.
+
+ if IRREGULAR_NAMES[kind]
+ # In a few cases, the given kind / singularName itself is still plural.
+ # We require a distinct singular method name, so force it.
+ method_names = IRREGULAR_NAMES[kind]
+ else
+ # TODO: respect singularName from discovery?
+ # But how? If it differs from kind.downcase, kind's word boundaries don't apply.
+ singular_name = kind.downcase
+
+ if !(/[A-Z]/ =~ kind)
+ # Some custom resources have a fully lowercase kind - can't infer underscores.
+ method_names = [singular_name, name]
+ else
+ # Some plurals are not exact suffixes, e.g. NetworkPolicy -> networkpolicies.
+ # So don't expect full last word to match.
+ /^(?<prefix>(.*[A-Z]))(?<singular_suffix>[^A-Z]*)$/ =~ kind # "NetworkP", "olicy"
+ if name.start_with?(prefix.downcase)
+ plural_suffix = name[prefix.length..-1] # "olicies"
+ prefix_underscores = ClientMixin.underscore_entity(prefix) # "network_p"
+ method_names = [prefix_underscores + singular_suffix, # "network_policy"
+ prefix_underscores + plural_suffix] # "network_policies"
+ else
+ method_names = resolve_unconventional_method_names(name, kind, singular_name)
+ end
+ end
+ end
+
+ OpenStruct.new(
+ entity_type: kind,
+ resource_name: name,
+ method_names: method_names
+ )
+ end
+
+ def self.resolve_unconventional_method_names(name, kind, singular_name)
+ underscored_name = name.tr('-', '_')
+ singular_underscores = ClientMixin.underscore_entity(kind)
+ if underscored_name.start_with?(singular_underscores)
+ [singular_underscores, underscored_name]
+ else
+ # fallback to lowercase, no separators for both names
+ [singular_name, underscored_name.tr('_', '')]
+ end
+ end
+
+ def handle_uri(uri, path)
+ raise ArgumentError, 'Missing uri' unless uri
+ @api_endpoint = (uri.is_a?(URI) ? uri : URI.parse(uri))
+
+ # This regex will anchor at the last `/api`, `/oapi` or`/apis/:group`) part of the URL
+ # The whole path will be matched and if existing, the api_group will be extracted.
+ re = /^(?<path>.*\/o?api(?:s\/(?<apigroup>[^\/]+))?)$/mi
+ match = re.match(@api_endpoint.path.chomp('/'))
+
+ if match
+ # Since `re` captures 2 groups, match will always have 3 elements
+ # If thus we have a non-nil value in match 2, this is our api_group.
+ @api_group = match[:apigroup].nil? ? '' : match[:apigroup] + '/'
+ @api_endpoint.path = match[:path]
+ else
+ # This is a fallback, for when `/api` was not provided as part of the uri
+ @api_group = ''
+ @api_endpoint.path = @api_endpoint.path.chomp('/') + path
+ end
+ end
+
+ def build_namespace_prefix(namespace)
+ namespace.to_s.empty? ? '' : "namespaces/#{namespace}/"
+ end
+
+ # rubocop:disable Metrics/BlockLength
+ def define_entity_methods
+ @entities.values.each do |entity|
+ # get all entities of a type e.g. get_nodes, get_pods, etc.
+ define_singleton_method("get_#{entity.method_names[1]}") do |options = {}|
+ get_entities(entity.entity_type, entity.resource_name, options)
+ end
+
+ # watch all entities of a type e.g. watch_nodes, watch_pods, etc.
+ define_singleton_method("watch_#{entity.method_names[1]}") do |options = {}, &block|
+ # This method used to take resource_version as a param, so
+ # this conversion is to keep backwards compatibility
+ options = { resource_version: options } unless options.is_a?(Hash)
+
+ watch_entities(entity.resource_name, options, &block)
+ end
+
+ # get a single entity of a specific type by name
+ define_singleton_method("get_#{entity.method_names[0]}") \
+ do |name, namespace = nil, opts = {}|
+ get_entity(entity.resource_name, name, namespace, opts)
+ end
+
+ define_singleton_method("delete_#{entity.method_names[0]}") \
+ do |name, namespace = nil, opts = {}|
+ delete_entity(entity.resource_name, name, namespace, **opts)
+ end
+
+ define_singleton_method("create_#{entity.method_names[0]}") do |entity_config|
+ create_entity(entity.entity_type, entity.resource_name, entity_config)
+ end
+
+ define_singleton_method("update_#{entity.method_names[0]}") do |entity_config|
+ update_entity(entity.resource_name, entity_config)
+ end
+
+ define_singleton_method("patch_#{entity.method_names[0]}") \
+ do |name, patch, namespace = nil|
+ patch_entity(entity.resource_name, name, patch, 'strategic-merge-patch', namespace)
+ end
+
+ define_singleton_method("json_patch_#{entity.method_names[0]}") \
+ do |name, patch, namespace = nil|
+ patch_entity(entity.resource_name, name, patch, 'json-patch', namespace)
+ end
+
+ define_singleton_method("merge_patch_#{entity.method_names[0]}") \
+ do |name, patch, namespace = nil|
+ patch_entity(entity.resource_name, name, patch, 'merge-patch', namespace)
+ end
+
+ define_singleton_method("apply_#{entity.method_names[0]}") do |resource, opts = {}|
+ apply_entity(entity.resource_name, resource, **opts)
+ end
+ end
+ end
+ # rubocop:enable Metrics/BlockLength
+
+ def self.underscore_entity(entity_name)
+ entity_name.gsub(/([a-z])([A-Z])/, '\1_\2').downcase
+ end
+
+ def create_rest_client(path = nil)
+ path ||= @api_endpoint.path
+ options = {
+ ssl_ca_file: @ssl_options[:ca_file],
+ ssl_cert_store: @ssl_options[:cert_store],
+ verify_ssl: @ssl_options[:verify_ssl],
+ ssl_client_cert: @ssl_options[:client_cert],
+ ssl_client_key: @ssl_options[:client_key],
+ proxy: @http_proxy_uri,
+ max_redirects: @http_max_redirects,
+ user: @auth_options[:username],
+ password: @auth_options[:password],
+ open_timeout: @timeouts[:open],
+ read_timeout: @timeouts[:read]
+ }
+ RestClient::Resource.new(@api_endpoint.merge(path).to_s, options)
+ end
+
+ def rest_client
+ @rest_client ||= begin
+ create_rest_client("#{@api_endpoint.path}/#{@api_version}")
+ end
+ end
+
+ # Accepts the following options:
+ # :namespace (string) - the namespace of the entity.
+ # :name (string) - the name of the entity to watch.
+ # :label_selector (string) - a selector to restrict the list of returned objects by labels.
+ # :field_selector (string) - a selector to restrict the list of returned objects by fields.
+ # :resource_version (string) - shows changes that occur after passed version of a resource.
+ # :as (:raw|:ros) - defaults to :ros
+ # :raw - return the raw response body as a string
+ # :ros - return a collection of RecursiveOpenStruct objects
+ # Accepts an optional block, that will be called with each entity,
+ # otherwise returns a WatchStream
+ def watch_entities(resource_name, options = {}, &block)
+ ns = build_namespace_prefix(options[:namespace])
+
+ path = "watch/#{ns}#{resource_name}"
+ path += "/#{options[:name]}" if options[:name]
+ uri = @api_endpoint.merge("#{@api_endpoint.path}/#{@api_version}/#{path}")
+
+ params = {}
+ WATCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
+ uri.query = URI.encode_www_form(params) if params.any?
+
+ watcher = Kubeclient::Common::WatchStream.new(
+ uri,
+ http_options(uri),
+ formatter: ->(value) { format_response(options[:as] || @as, value) }
+ )
+
+ return_or_yield_to_watcher(watcher, &block)
+ end
+
+ # Accepts the following options:
+ # :namespace (string) - the namespace of the entity.
+ # :label_selector (string) - a selector to restrict the list of returned objects by labels.
+ # :field_selector (string) - a selector to restrict the list of returned objects by fields.
+ # :limit (integer) - a maximum number of items to return in each response
+ # :continue (string) - a token used to retrieve the next chunk of entities
+ # :as (:raw|:ros) - defaults to :ros
+ # :raw - return the raw response body as a string
+ # :ros - return a collection of RecursiveOpenStruct objects
+ def get_entities(entity_type, resource_name, options = {})
+ params = {}
+ SEARCH_ARGUMENTS.each { |k, v| params[k] = options[v] if options[v] }
+
+ ns_prefix = build_namespace_prefix(options[:namespace])
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name]
+ .get({ 'params' => params }.merge(@headers))
+ end
+ format_response(options[:as] || @as, response.body, entity_type)
+ end
+
+ # Accepts the following options:
+ # :as (:raw|:ros) - defaults to :ros
+ # :raw - return the raw response body as a string
+ # :ros - return a collection of RecursiveOpenStruct objects
+ def get_entity(resource_name, name, namespace = nil, options = {})
+ ns_prefix = build_namespace_prefix(namespace)
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name + "/#{name}"]
+ .get(@headers)
+ end
+ format_response(options[:as] || @as, response.body)
+ end
+
+ # delete_options are passed as a JSON payload in the delete request
+ def delete_entity(resource_name, name, namespace = nil, delete_options: {})
+ delete_options_hash = delete_options.to_hash
+ ns_prefix = build_namespace_prefix(namespace)
+ payload = delete_options_hash.to_json unless delete_options_hash.empty?
+ response = handle_exception do
+ rs = rest_client[ns_prefix + resource_name + "/#{name}"]
+ RestClient::Request.execute(
+ rs.options.merge(
+ method: :delete,
+ url: rs.url,
+ headers: { 'Content-Type' => 'application/json' }.merge(@headers),
+ payload: payload
+ )
+ )
+ end
+ format_response(@as, response.body)
+ end
+
+ def create_entity(entity_type, resource_name, entity_config)
+ # Duplicate the entity_config to a hash so that when we assign
+ # kind and apiVersion, this does not mutate original entity_config obj.
+ hash = entity_config.to_hash
+
+ ns_prefix = build_namespace_prefix(hash[:metadata][:namespace])
+
+ # TODO: temporary solution to add "kind" and apiVersion to request
+ # until this issue is solved
+ # https://github.com/GoogleCloudPlatform/kubernetes/issues/6439
+ hash[:kind] = entity_type
+ hash[:apiVersion] = @api_group + @api_version
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name]
+ .post(hash.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
+ end
+ format_response(@as, response.body)
+ end
+
+ def update_entity(resource_name, entity_config)
+ name = entity_config[:metadata][:name]
+ ns_prefix = build_namespace_prefix(entity_config[:metadata][:namespace])
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name + "/#{name}"]
+ .put(entity_config.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
+ end
+ format_response(@as, response.body)
+ end
+
+ def patch_entity(resource_name, name, patch, strategy, namespace)
+ ns_prefix = build_namespace_prefix(namespace)
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name + "/#{name}"]
+ .patch(
+ patch.to_json,
+ { 'Content-Type' => "application/#{strategy}+json" }.merge(@headers)
+ )
+ end
+ format_response(@as, response.body)
+ end
+
+ def apply_entity(resource_name, resource, field_manager:, force: true)
+ name = "#{resource[:metadata][:name]}?fieldManager=#{field_manager}&force=#{force}"
+ ns_prefix = build_namespace_prefix(resource[:metadata][:namespace])
+ response = handle_exception do
+ rest_client[ns_prefix + resource_name + "/#{name}"]
+ .patch(
+ resource.to_json,
+ { 'Content-Type' => 'application/apply-patch+yaml' }.merge(@headers)
+ )
+ end
+ format_response(@as, response.body)
+ end
+
+ def all_entities(options = {})
+ discover unless @discovered
+ @entities.values.each_with_object({}) do |entity, result_hash|
+ # method call for get each entities
+ # build hash of entity name to array of the entities
+ method_name = "get_#{entity.method_names[1]}"
+ begin
+ result_hash[entity.method_names[0]] = send(method_name, options)
+ rescue Kubeclient::HttpError
+ next # do not fail due to resources not supporting get
+ end
+ end
+ end
+
+ def get_pod_log(pod_name, namespace,
+ container: nil, previous: false,
+ timestamps: false, since_time: nil, tail_lines: nil, limit_bytes: nil)
+ params = {}
+ params[:previous] = true if previous
+ params[:container] = container if container
+ params[:timestamps] = timestamps if timestamps
+ params[:sinceTime] = format_datetime(since_time) if since_time
+ params[:tailLines] = tail_lines if tail_lines
+ params[:limitBytes] = limit_bytes if limit_bytes
+
+ ns = build_namespace_prefix(namespace)
+ handle_exception do
+ rest_client[ns + "pods/#{pod_name}/log"]
+ .get({ 'params' => params }.merge(@headers))
+ end
+ end
+
+ def watch_pod_log(pod_name, namespace, container: nil, &block)
+ # Adding the "follow=true" query param tells the Kubernetes API to keep
+ # the connection open and stream updates to the log.
+ params = { follow: true }
+ params[:container] = container if container
+
+ ns = build_namespace_prefix(namespace)
+
+ uri = @api_endpoint.dup
+ uri.path += "/#{@api_version}/#{ns}pods/#{pod_name}/log"
+ uri.query = URI.encode_www_form(params)
+
+ watcher = Kubeclient::Common::WatchStream.new(
+ uri, http_options(uri), formatter: ->(value) { value }
+ )
+ return_or_yield_to_watcher(watcher, &block)
+ end
+
+ def proxy_url(kind, name, port, namespace = '')
+ discover unless @discovered
+ entity_name_plural =
+ if %w[services pods nodes].include?(kind.to_s)
+ kind.to_s
+ else
+ @entities[kind.to_s].resource_name
+ end
+ ns_prefix = build_namespace_prefix(namespace)
+ rest_client["#{ns_prefix}#{entity_name_plural}/#{name}:#{port}/proxy"].url
+ end
+
+ def process_template(template)
+ ns_prefix = build_namespace_prefix(template[:metadata][:namespace])
+ response = handle_exception do
+ rest_client[ns_prefix + 'processedtemplates']
+ .post(template.to_h.to_json, { 'Content-Type' => 'application/json' }.merge(@headers))
+ end
+ JSON.parse(response)
+ end
+
+ def api_valid?
+ result = api
+ result.is_a?(Hash) && (result['versions'] || []).any? do |group|
+ @api_group.empty? ? group.include?(@api_version) : group['version'] == @api_version
+ end
+ end
+
+ def api
+ response = handle_exception { create_rest_client.get(@headers) }
+ JSON.parse(response)
+ end
+
+ private
+
+ IRREGULAR_NAMES = {
+ # In a few cases, the given kind itself is still plural.
+ # https://github.com/kubernetes/kubernetes/issues/8115
+ 'Endpoints' => %w[endpoint endpoints],
+ 'SecurityContextConstraints' => %w[security_context_constraint
+ security_context_constraints]
+ }.freeze
+
+ # Format datetime according to RFC3339
+ def format_datetime(value)
+ case value
+ when DateTime, Time
+ value.strftime('%FT%T.%9N%:z')
+ when String
+ value
+ else
+ raise ArgumentError, "unsupported type '#{value.class}' of time value '#{value}'"
+ end
+ end
+
+ def format_response(as, body, list_type = nil)
+ case as
+ when :raw
+ body
+ when :parsed
+ JSON.parse(body)
+ when :parsed_symbolized
+ JSON.parse(body, symbolize_names: true)
+ when :ros
+ result = JSON.parse(body)
+
+ if list_type
+ resource_version =
+ result.fetch('resourceVersion') do
+ result.fetch('metadata', {}).fetch('resourceVersion', nil)
+ end
+
+ # If 'limit' was passed save the continue token
+ # see https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks
+ continue = result.fetch('metadata', {}).fetch('continue', nil)
+
+ # result['items'] might be nil due to https://github.com/kubernetes/kubernetes/issues/13096
+ collection = result['items'].to_a.map { |item| Kubeclient::Resource.new(item) }
+
+ Kubeclient::Common::EntityList.new(list_type, resource_version, collection, continue)
+ else
+ Kubeclient::Resource.new(result)
+ end
+ else
+ raise ArgumentError, "Unsupported format #{as.inspect}"
+ end
+ end
+
+ def load_entities
+ @entities = {}
+ fetch_entities['resources'].each do |resource|
+ next if resource['name'].include?('/')
+ # Not a regular entity, special functionality covered by `process_template`.
+ # https://github.com/openshift/origin/issues/21668
+ next if resource['kind'] == 'Template' && resource['name'] == 'processedtemplates'
+ resource['kind'] ||=
+ Kubeclient::Common::MissingKindCompatibility.resource_kind(resource['name'])
+ entity = ClientMixin.parse_definition(resource['kind'], resource['name'])
+ @entities[entity.method_names[0]] = entity if entity
+ end
+ end
+
+ def fetch_entities
+ JSON.parse(handle_exception { rest_client.get(@headers) })
+ end
+
+ def bearer_token(bearer_token)
+ @headers ||= {}
+ @headers[:Authorization] = "Bearer #{bearer_token}"
+ end
+
+ def validate_auth_options(opts)
+ # maintain backward compatibility:
+ opts[:username] = opts[:user] if opts[:user]
+
+ if %i[bearer_token bearer_token_file username].count { |key| opts[key] } > 1
+ raise(
+ ArgumentError,
+ 'Invalid auth options: specify only one of username/password,' \
+ ' bearer_token or bearer_token_file'
+ )
+ elsif %i[username password].count { |key| opts[key] } == 1
+ raise ArgumentError, 'Basic auth requires both username & password'
+ end
+ end
+
+ def validate_bearer_token_file
+ msg = "Token file #{@auth_options[:bearer_token_file]} does not exist"
+ raise ArgumentError, msg unless File.file?(@auth_options[:bearer_token_file])
+
+ msg = "Cannot read token file #{@auth_options[:bearer_token_file]}"
+ raise ArgumentError, msg unless File.readable?(@auth_options[:bearer_token_file])
+ end
+
+ def return_or_yield_to_watcher(watcher, &block)
+ return watcher unless block_given?
+
+ begin
+ watcher.each(&block)
+ ensure
+ watcher.finish
+ end
+ end
+
+ def http_options(uri)
+ options = {
+ basic_auth_user: @auth_options[:username],
+ basic_auth_password: @auth_options[:password],
+ headers: @headers,
+ http_proxy_uri: @http_proxy_uri,
+ http_max_redirects: http_max_redirects
+ }
+
+ if uri.scheme == 'https'
+ options[:ssl] = {
+ ca_file: @ssl_options[:ca_file],
+ cert: @ssl_options[:client_cert],
+ cert_store: @ssl_options[:cert_store],
+ key: @ssl_options[:client_key],
+ # ruby HTTP uses verify_mode instead of verify_ssl
+ # http://ruby-doc.org/stdlib-1.9.3/libdoc/openssl/rdoc/OpenSSL/SSL/SSLContext.html
+ verify_mode: @ssl_options[:verify_ssl]
+ }
+ end
+
+ options.merge(@socket_options)
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/config.rb b/vendor/gems/kubeclient/lib/kubeclient/config.rb
new file mode 100644
index 00000000000..3598afe83fe
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/config.rb
@@ -0,0 +1,202 @@
+require 'yaml'
+require 'base64'
+require 'pathname'
+
+module Kubeclient
+ # Kubernetes client configuration class
+ class Config
+ # Kubernetes client configuration context class
+ class Context
+ attr_reader :api_endpoint, :api_version, :ssl_options, :auth_options, :namespace
+
+ def initialize(api_endpoint, api_version, ssl_options, auth_options, namespace)
+ @api_endpoint = api_endpoint
+ @api_version = api_version
+ @ssl_options = ssl_options
+ @auth_options = auth_options
+ @namespace = namespace
+ end
+ end
+
+ # data (Hash) - Parsed kubeconfig data.
+ # kcfg_path (string) - Base directory for resolving relative references to external files.
+ # If set to nil, all external lookups & commands are disabled (even for absolute paths).
+ # See also the more convenient Config.read
+ def initialize(data, kcfg_path)
+ @kcfg = data
+ @kcfg_path = kcfg_path
+ raise 'Unknown kubeconfig version' if @kcfg['apiVersion'] != 'v1'
+ end
+
+ # Builds Config instance by parsing given file, with lookups relative to file's directory.
+ def self.read(filename)
+ parsed =
+ if RUBY_VERSION >= '2.6'
+ YAML.safe_load(File.read(filename), permitted_classes: [Date, Time])
+ else
+ YAML.safe_load(File.read(filename), [Date, Time])
+ end
+ Config.new(parsed, File.dirname(filename))
+ end
+
+ def contexts
+ @kcfg['contexts'].map { |x| x['name'] }
+ end
+
+ def context(context_name = nil)
+ cluster, user, namespace = fetch_context(context_name || @kcfg['current-context'])
+
+ if user.key?('exec')
+ exec_opts = expand_command_option(user['exec'], 'command')
+ user['exec_result'] = ExecCredentials.run(exec_opts)
+ end
+
+ client_cert_data = fetch_user_cert_data(user)
+ client_key_data = fetch_user_key_data(user)
+ auth_options = fetch_user_auth_options(user)
+
+ ssl_options = {}
+
+ ssl_options[:verify_ssl] = if cluster['insecure-skip-tls-verify'] == true
+ OpenSSL::SSL::VERIFY_NONE
+ else
+ OpenSSL::SSL::VERIFY_PEER
+ end
+
+ if cluster_ca_data?(cluster)
+ cert_store = OpenSSL::X509::Store.new
+ populate_cert_store_from_cluster_ca_data(cluster, cert_store)
+ ssl_options[:cert_store] = cert_store
+ end
+
+ unless client_cert_data.nil?
+ ssl_options[:client_cert] = OpenSSL::X509::Certificate.new(client_cert_data)
+ end
+
+ unless client_key_data.nil?
+ ssl_options[:client_key] = OpenSSL::PKey.read(client_key_data)
+ end
+
+ Context.new(cluster['server'], @kcfg['apiVersion'], ssl_options, auth_options, namespace)
+ end
+
+ private
+
+ def allow_external_lookups?
+ @kcfg_path != nil
+ end
+
+ def ext_file_path(path)
+ unless allow_external_lookups?
+ raise "Kubeclient::Config: external lookups disabled, can't load '#{path}'"
+ end
+ Pathname(path).absolute? ? path : File.join(@kcfg_path, path)
+ end
+
+ def ext_command_path(path)
+ unless allow_external_lookups?
+ raise "Kubeclient::Config: external lookups disabled, can't execute '#{path}'"
+ end
+ # Like go client https://github.com/kubernetes/kubernetes/pull/59495#discussion_r171138995,
+ # distinguish 3 cases:
+ # - absolute (e.g. /path/to/foo)
+ # - $PATH-based (e.g. curl)
+ # - relative to config file's dir (e.g. ./foo)
+ if Pathname(path).absolute?
+ path
+ elsif File.basename(path) == path
+ path
+ else
+ File.join(@kcfg_path, path)
+ end
+ end
+
+ def fetch_context(context_name)
+ context = @kcfg['contexts'].detect do |x|
+ break x['context'] if x['name'] == context_name
+ end
+
+ raise KeyError, "Unknown context #{context_name}" unless context
+
+ cluster = @kcfg['clusters'].detect do |x|
+ break x['cluster'] if x['name'] == context['cluster']
+ end
+
+ raise KeyError, "Unknown cluster #{context['cluster']}" unless cluster
+
+ user = @kcfg['users'].detect do |x|
+ break x['user'] if x['name'] == context['user']
+ end || {}
+
+ namespace = context['namespace']
+
+ [cluster, user, namespace]
+ end
+
+ def cluster_ca_data?(cluster)
+ cluster.key?('certificate-authority') || cluster.key?('certificate-authority-data')
+ end
+
+ def populate_cert_store_from_cluster_ca_data(cluster, cert_store)
+ if cluster.key?('certificate-authority')
+ cert_store.add_file(ext_file_path(cluster['certificate-authority']))
+ elsif cluster.key?('certificate-authority-data')
+ ca_cert_data = Base64.decode64(cluster['certificate-authority-data'])
+ cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_cert_data))
+ end
+ end
+
+ def fetch_user_cert_data(user)
+ if user.key?('client-certificate')
+ File.read(ext_file_path(user['client-certificate']))
+ elsif user.key?('client-certificate-data')
+ Base64.decode64(user['client-certificate-data'])
+ elsif user.key?('exec_result') && user['exec_result'].key?('clientCertificateData')
+ user['exec_result']['clientCertificateData']
+ end
+ end
+
+ def fetch_user_key_data(user)
+ if user.key?('client-key')
+ File.read(ext_file_path(user['client-key']))
+ elsif user.key?('client-key-data')
+ Base64.decode64(user['client-key-data'])
+ elsif user.key?('exec_result') && user['exec_result'].key?('clientKeyData')
+ user['exec_result']['clientKeyData']
+ end
+ end
+
+ def fetch_user_auth_options(user)
+ options = {}
+ if user.key?('token')
+ options[:bearer_token] = user['token']
+ elsif user.key?('exec_result') && user['exec_result'].key?('token')
+ options[:bearer_token] = user['exec_result']['token']
+ elsif user.key?('auth-provider')
+ options[:bearer_token] = fetch_token_from_provider(user['auth-provider'])
+ else
+ %w[username password].each do |attr|
+ options[attr.to_sym] = user[attr] if user.key?(attr)
+ end
+ end
+ options
+ end
+
+ def fetch_token_from_provider(auth_provider)
+ case auth_provider['name']
+ when 'gcp'
+ config = expand_command_option(auth_provider['config'], 'cmd-path')
+ Kubeclient::GCPAuthProvider.token(config)
+ when 'oidc'
+ Kubeclient::OIDCAuthProvider.token(auth_provider['config'])
+ end
+ end
+
+ def expand_command_option(config, key)
+ config = config.dup
+ config[key] = ext_command_path(config[key]) if config[key]
+
+ config
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb b/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb
new file mode 100644
index 00000000000..2f734560a4b
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/entity_list.rb
@@ -0,0 +1,21 @@
+require 'delegate'
+module Kubeclient
+ module Common
+ # Kubernetes Entity List
+ class EntityList < DelegateClass(Array)
+ attr_reader :continue, :kind, :resourceVersion
+
+ def initialize(kind, resource_version, list, continue = nil)
+ @kind = kind
+ # rubocop:disable Style/VariableName
+ @resourceVersion = resource_version
+ @continue = continue
+ super(list)
+ end
+
+ def last?
+ continue.nil?
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb
new file mode 100644
index 00000000000..016d48ae289
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/exec_credentials.rb
@@ -0,0 +1,89 @@
+# frozen_string_literal: true
+
+module Kubeclient
+ # An exec-based client auth provide
+ # https://kubernetes.io/docs/reference/access-authn-authz/authentication/#configuration
+ # Inspired by https://github.com/kubernetes/client-go/blob/master/plugin/pkg/client/auth/exec/exec.go
+ class ExecCredentials
+ class << self
+ def run(opts)
+ require 'open3'
+ require 'json'
+
+ raise ArgumentError, 'exec options are required' if opts.nil?
+
+ cmd = opts['command']
+ args = opts['args']
+ env = map_env(opts['env'])
+
+ # Validate exec options
+ validate_opts(opts)
+
+ out, err, st = Open3.capture3(env, cmd, *args)
+
+ raise "exec command failed: #{err}" unless st.success?
+
+ creds = JSON.parse(out)
+ validate_credentials(opts, creds)
+ creds['status']
+ end
+
+ private
+
+ def validate_opts(opts)
+ raise KeyError, 'exec command is required' unless opts['command']
+ end
+
+ def validate_client_credentials_status(status)
+ has_client_cert_data = status.key?('clientCertificateData')
+ has_client_key_data = status.key?('clientKeyData')
+
+ if has_client_cert_data && !has_client_key_data
+ raise 'exec plugin didn\'t return client key data'
+ end
+
+ if !has_client_cert_data && has_client_key_data
+ raise 'exec plugin didn\'t return client certificate data'
+ end
+
+ has_client_cert_data && has_client_key_data
+ end
+
+ def validate_credentials_status(status)
+ raise 'exec plugin didn\'t return a status field' if status.nil?
+
+ has_client_credentials = validate_client_credentials_status(status)
+ has_token = status.key?('token')
+
+ if has_client_credentials && has_token
+ raise 'exec plugin returned both token and client data'
+ end
+
+ return if has_client_credentials || has_token
+
+ raise 'exec plugin didn\'t return a token or client data' unless has_token
+ end
+
+ def validate_credentials(opts, creds)
+ # out should have ExecCredential structure
+ raise 'invalid credentials' if creds.nil?
+
+ # Verify apiVersion?
+ api_version = opts['apiVersion']
+ if api_version && api_version != creds['apiVersion']
+ raise "exec plugin is configured to use API version #{api_version}, " \
+ "plugin returned version #{creds['apiVersion']}"
+ end
+
+ validate_credentials_status(creds['status'])
+ end
+
+ # Transform name/value pairs to hash
+ def map_env(env)
+ return {} unless env
+
+ Hash[env.map { |e| [e['name'], e['value']] }]
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb b/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb
new file mode 100644
index 00000000000..b28e54bfd88
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/gcp_auth_provider.rb
@@ -0,0 +1,19 @@
+# frozen_string_literal: true
+
+require 'kubeclient/google_application_default_credentials'
+require 'kubeclient/gcp_command_credentials'
+
+module Kubeclient
+ # Handle different ways to get a bearer token for Google Cloud Platform.
+ class GCPAuthProvider
+ class << self
+ def token(config)
+ if config.key?('cmd-path')
+ Kubeclient::GCPCommandCredentials.token(config)
+ else
+ Kubeclient::GoogleApplicationDefaultCredentials.token
+ end
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb
new file mode 100644
index 00000000000..9c68c1a2847
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/gcp_command_credentials.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Kubeclient
+ # Generates a bearer token for Google Cloud Platform.
+ class GCPCommandCredentials
+ class << self
+ def token(config)
+ require 'open3'
+ require 'shellwords'
+ require 'json'
+ require 'jsonpath'
+
+ cmd = config['cmd-path']
+ args = config['cmd-args']
+ token_key = config['token-key']
+
+ out, err, st = Open3.capture3(cmd, *args.split(' '))
+
+ raise "exec command failed: #{err}" unless st.success?
+
+ extract_token(out, token_key)
+ end
+
+ private
+
+ def extract_token(output, token_key)
+ JsonPath.on(output, token_key.gsub(/^{|}$/, '')).first
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb b/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb
new file mode 100644
index 00000000000..78f99ec9f32
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/google_application_default_credentials.rb
@@ -0,0 +1,31 @@
+# frozen_string_literal: true
+
+module Kubeclient
+ # Get a bearer token from the Google's application default credentials.
+ class GoogleApplicationDefaultCredentials
+ class GoogleDependencyError < LoadError # rubocop:disable Lint/InheritException
+ end
+
+ class << self
+ def token
+ begin
+ require 'googleauth'
+ rescue LoadError => e
+ raise GoogleDependencyError,
+ 'Error requiring googleauth gem. Kubeclient itself does not include the ' \
+ 'googleauth gem. To support auth-provider gcp, you must include it in your ' \
+ "calling application. Failed with: #{e.message}"
+ end
+
+ scopes = [
+ 'https://www.googleapis.com/auth/cloud-platform',
+ 'https://www.googleapis.com/auth/userinfo.email'
+ ]
+
+ authorization = Google::Auth.get_application_default(scopes)
+ authorization.apply({})
+ authorization.access_token
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/http_error.rb b/vendor/gems/kubeclient/lib/kubeclient/http_error.rb
new file mode 100644
index 00000000000..121368c2f17
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/http_error.rb
@@ -0,0 +1,25 @@
+# TODO: remove this on next major version bump
+# Deprected http exception
+class KubeException < StandardError
+ attr_reader :error_code, :message, :response
+
+ def initialize(error_code, message, response)
+ @error_code = error_code
+ @message = message
+ @response = response
+ end
+
+ def to_s
+ string = "HTTP status code #{@error_code}, #{@message}"
+ if @response.is_a?(RestClient::Response) && @response.request
+ string << " for #{@response.request.method.upcase} #{@response.request.url}"
+ end
+ string
+ end
+end
+
+module Kubeclient
+ # Exception that is raised when a http request fails
+ class HttpError < KubeException
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb b/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb
new file mode 100644
index 00000000000..ec88960a546
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/missing_kind_compatibility.rb
@@ -0,0 +1,68 @@
+module Kubeclient
+ module Common
+ # Backward compatibility for old versions where kind is missing (e.g. OpenShift Enterprise 3.1)
+ class MissingKindCompatibility
+ MAPPING = {
+ 'bindings' => 'Binding',
+ 'componentstatuses' => 'ComponentStatus',
+ 'endpoints' => 'Endpoints',
+ 'events' => 'Event',
+ 'limitranges' => 'LimitRange',
+ 'namespaces' => 'Namespace',
+ 'nodes' => 'Node',
+ 'persistentvolumeclaims' => 'PersistentVolumeClaim',
+ 'persistentvolumes' => 'PersistentVolume',
+ 'pods' => 'Pod',
+ 'podtemplates' => 'PodTemplate',
+ 'replicationcontrollers' => 'ReplicationController',
+ 'resourcequotas' => 'ResourceQuota',
+ 'secrets' => 'Secret',
+ 'securitycontextconstraints' => 'SecurityContextConstraints',
+ 'serviceaccounts' => 'ServiceAccount',
+ 'services' => 'Service',
+ 'buildconfigs' => 'BuildConfig',
+ 'builds' => 'Build',
+ 'clusternetworks' => 'ClusterNetwork',
+ 'clusterpolicies' => 'ClusterPolicy',
+ 'clusterpolicybindings' => 'ClusterPolicyBinding',
+ 'clusterrolebindings' => 'ClusterRoleBinding',
+ 'clusterroles' => 'ClusterRole',
+ 'deploymentconfigrollbacks' => 'DeploymentConfigRollback',
+ 'deploymentconfigs' => 'DeploymentConfig',
+ 'generatedeploymentconfigs' => 'DeploymentConfig',
+ 'groups' => 'Group',
+ 'hostsubnets' => 'HostSubnet',
+ 'identities' => 'Identity',
+ 'images' => 'Image',
+ 'imagestreamimages' => 'ImageStreamImage',
+ 'imagestreammappings' => 'ImageStreamMapping',
+ 'imagestreams' => 'ImageStream',
+ 'imagestreamtags' => 'ImageStreamTag',
+ 'localresourceaccessreviews' => 'LocalResourceAccessReview',
+ 'localsubjectaccessreviews' => 'LocalSubjectAccessReview',
+ 'netnamespaces' => 'NetNamespace',
+ 'oauthaccesstokens' => 'OAuthAccessToken',
+ 'oauthauthorizetokens' => 'OAuthAuthorizeToken',
+ 'oauthclientauthorizations' => 'OAuthClientAuthorization',
+ 'oauthclients' => 'OAuthClient',
+ 'policies' => 'Policy',
+ 'policybindings' => 'PolicyBinding',
+ 'processedtemplates' => 'Template',
+ 'projectrequests' => 'ProjectRequest',
+ 'projects' => 'Project',
+ 'resourceaccessreviews' => 'ResourceAccessReview',
+ 'rolebindings' => 'RoleBinding',
+ 'roles' => 'Role',
+ 'routes' => 'Route',
+ 'subjectaccessreviews' => 'SubjectAccessReview',
+ 'templates' => 'Template',
+ 'useridentitymappings' => 'UserIdentityMapping',
+ 'users' => 'User'
+ }.freeze
+
+ def self.resource_kind(name)
+ MAPPING[name]
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb b/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb
new file mode 100644
index 00000000000..ffdfd7e2a5d
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/oidc_auth_provider.rb
@@ -0,0 +1,52 @@
+# frozen_string_literal: true
+
+module Kubeclient
+ # Uses OIDC id-tokens and refreshes them if they are stale.
+ class OIDCAuthProvider
+ class OpenIDConnectDependencyError < LoadError # rubocop:disable Lint/InheritException
+ end
+
+ class << self
+ def token(provider_config)
+ begin
+ require 'openid_connect'
+ rescue LoadError => e
+ raise OpenIDConnectDependencyError,
+ 'Error requiring openid_connect gem. Kubeclient itself does not include the ' \
+ 'openid_connect gem. To support auth-provider oidc, you must include it in your ' \
+ "calling application. Failed with: #{e.message}"
+ end
+
+ issuer_url = provider_config['idp-issuer-url']
+ discovery = OpenIDConnect::Discovery::Provider::Config.discover! issuer_url
+
+ if provider_config.key? 'id-token'
+ return provider_config['id-token'] unless expired?(provider_config['id-token'], discovery)
+ end
+
+ client = OpenIDConnect::Client.new(
+ identifier: provider_config['client-id'],
+ secret: provider_config['client-secret'],
+ authorization_endpoint: discovery.authorization_endpoint,
+ token_endpoint: discovery.token_endpoint,
+ userinfo_endpoint: discovery.userinfo_endpoint
+ )
+ client.refresh_token = provider_config['refresh-token']
+ client.access_token!.id_token
+ end
+
+ def expired?(id_token, discovery)
+ decoded_token = OpenIDConnect::ResponseObject::IdToken.decode(
+ id_token,
+ discovery.jwks
+ )
+ # If token expired or expiring within 60 seconds
+ Time.now.to_i + 60 > decoded_token.exp.to_i
+ rescue JSON::JWK::Set::KidNotFound
+ # Token cannot be verified: the kid it was signed with is not available for discovery
+ # Consider it expired and fetch a new one.
+ true
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/resource.rb b/vendor/gems/kubeclient/lib/kubeclient/resource.rb
new file mode 100644
index 00000000000..08a50c3fe4f
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/resource.rb
@@ -0,0 +1,11 @@
+require 'recursive_open_struct'
+
+module Kubeclient
+ # Represents all the objects returned by Kubeclient
+ class Resource < RecursiveOpenStruct
+ def initialize(hash = nil, args = {})
+ args[:recurse_over_arrays] = true
+ super(hash, args)
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb b/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb
new file mode 100644
index 00000000000..045a83642d7
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/resource_not_found_error.rb
@@ -0,0 +1,4 @@
+module Kubeclient
+ class ResourceNotFoundError < HttpError
+ end
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/version.rb b/vendor/gems/kubeclient/lib/kubeclient/version.rb
new file mode 100644
index 00000000000..bff50841794
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/version.rb
@@ -0,0 +1,4 @@
+# Kubernetes REST-API Client
+module Kubeclient
+ VERSION = '4.9.4-gitlab1'.freeze
+end
diff --git a/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb b/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb
new file mode 100644
index 00000000000..ef676660d53
--- /dev/null
+++ b/vendor/gems/kubeclient/lib/kubeclient/watch_stream.rb
@@ -0,0 +1,97 @@
+require 'json'
+require 'http'
+module Kubeclient
+ module Common
+ # HTTP Stream used to watch changes on entities
+ class WatchStream
+ def initialize(uri, http_options, formatter:)
+ @uri = uri
+ @http_client = nil
+ @http_options = http_options
+ @http_options[:http_max_redirects] ||= Kubeclient::Client::DEFAULT_HTTP_MAX_REDIRECTS
+ @formatter = formatter
+ end
+
+ def each
+ @finished = false
+
+ @http_client = build_client
+ response = @http_client.request(:get, @uri, build_client_options)
+ unless response.code < 300
+ raise Kubeclient::HttpError.new(response.code, response.reason, response)
+ end
+
+ buffer = ''
+ response.body.each do |chunk|
+ buffer << chunk
+ while (line = buffer.slice!(/.+\n/))
+ yield @formatter.call(line.chomp)
+ end
+ end
+ rescue StandardError
+ raise unless @finished
+ end
+
+ def finish
+ @finished = true
+ @http_client.close unless @http_client.nil?
+ end
+
+ private
+
+ def max_hops
+ @http_options[:http_max_redirects] + 1
+ end
+
+ def follow_option
+ if max_hops > 1
+ { max_hops: max_hops }
+ else
+ # i.e. Do not follow redirects as we have set http_max_redirects to 0
+ # Setting `{ max_hops: 1 }` does not work FWIW
+ false
+ end
+ end
+
+ def build_client
+ client = HTTP::Client.new(follow: follow_option)
+
+ if @http_options[:basic_auth_user] && @http_options[:basic_auth_password]
+ client = client.basic_auth(
+ user: @http_options[:basic_auth_user],
+ pass: @http_options[:basic_auth_password]
+ )
+ end
+
+ client
+ end
+
+ def using_proxy
+ proxy = @http_options[:http_proxy_uri]
+ return nil unless proxy
+ p_uri = URI.parse(proxy)
+ {
+ proxy_address: p_uri.hostname,
+ proxy_port: p_uri.port,
+ proxy_username: p_uri.user,
+ proxy_password: p_uri.password
+ }
+ end
+
+ def build_client_options
+ client_options = {
+ headers: @http_options[:headers],
+ proxy: using_proxy
+ }
+ if @http_options[:ssl]
+ client_options[:ssl] = @http_options[:ssl]
+ socket_option = :ssl_socket_class
+ else
+ socket_option = :socket_class
+ end
+ client_options[socket_option] = @http_options[socket_option] if @http_options[socket_option]
+ client_options
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml b/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml
new file mode 100644
index 00000000000..3829add6d75
--- /dev/null
+++ b/vendor/gems/kubeclient/test/cassettes/kubernetes_guestbook.yml
@@ -0,0 +1,879 @@
+---
+http_interactions:
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '253'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "namespaces \"kubeclient-ns\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "kubeclient-ns",
+ "kind": "namespaces"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '239'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "service \"guestbook\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "guestbook",
+ "kind": "service"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '245'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "service \"redis-master\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "redis-master",
+ "kind": "service"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '243'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "service \"redis-slave\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "redis-slave",
+ "kind": "service"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '269'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "replicationControllers \"guestbook\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "guestbook",
+ "kind": "replicationControllers"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '275'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "replicationControllers \"redis-master\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "redis-master",
+ "kind": "replicationControllers"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 404
+ message: Not Found
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '273'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "replicationControllers \"redis-slave\" not found",
+ "reason": "NotFound",
+ "details": {
+ "name": "redis-slave",
+ "kind": "replicationControllers"
+ },
+ "code": 404
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"name":"kubeclient-ns"},"kind":"Namespace","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '74'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '297'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"name":"guestbook"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"ports":[{"port":3000,"targetPort":"http-server"}]},"type":"LoadBalancer","kind":"Service","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '239'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '521'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '244'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '552'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"ports":[{"port":6379,"targetPort":"redis-server"}]},"kind":"Service","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '241'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '548'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"Service","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"guestbook","role":"slave"},"name":"guestbook"},"spec":{"selector":{"app":"guestbook"},"template":{"metadata":{"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000}]}]}},"replicas":3},"kind":"ReplicationController","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '395'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '815'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"547","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"master"},"name":"redis-master"},"spec":{"selector":{"app":"redis","role":"master"},"template":{"metadata":{"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":1},"kind":"ReplicationController","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '405'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '828'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"558","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: post
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
+ body:
+ encoding: UTF-8
+ string: '{"metadata":{"namespace":"kubeclient-ns","labels":{"app":"redis","role":"slave"},"name":"redis-slave"},"spec":{"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379}]}]}},"replicas":2},"kind":"ReplicationController","apiVersion":"v1"}'
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ Content-Length:
+ - '420'
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 201
+ message: Created
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '842'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"ReplicationController","apiVersion":"v1","metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: get
+ uri: http://10.35.0.23:8080/api/v1/namespaces
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '629'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"NamespaceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces","resourceVersion":"570"},"items":[{"metadata":{"name":"default","selfLink":"/api/v1/namespaces/default","uid":"37360c82-3e77-11e5-a75a-18037327aaeb","resourceVersion":"6","creationTimestamp":"2015-08-09T09:15:45Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}},{"metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"534","creationTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Active"}}]}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: get
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '1661'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"ServiceList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/services","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/guestbook","uid":"f42187e1-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"538","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"name":"guestbook"}},"spec":{"ports":[{"protocol":"TCP","port":3000,"targetPort":"http-server","nodePort":0}],"selector":{"app":"guestbook"},"clusterIP":"10.0.0.80","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-master","uid":"f423bf8b-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"542","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"master"},"clusterIP":"10.0.0.140","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/services/redis-slave","uid":"f4264678-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"545","creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"ports":[{"protocol":"TCP","port":6379,"targetPort":"redis-server","nodePort":0}],"selector":{"app":"redis","role":"slave"},"clusterIP":"10.0.0.154","type":"ClusterIP","sessionAffinity":"None"},"status":{"loadBalancer":{}}}]}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: get
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Transfer-Encoding:
+ - chunked
+ body:
+ encoding: UTF-8
+ string: '{"kind":"ReplicationControllerList","apiVersion":"v1","metadata":{"selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers","resourceVersion":"571"},"items":[{"metadata":{"name":"guestbook","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook","uid":"f4287784-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"557","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"guestbook","role":"slave"}},"spec":{"replicas":3,"selector":{"app":"guestbook"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"guestbook"}},"spec":{"containers":[{"name":"guestbook","image":"kubernetes/guestbook:v2","ports":[{"name":"http-server","containerPort":3000,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":3,"observedGeneration":1}},{"metadata":{"name":"redis-master","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master","uid":"f42a9800-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"565","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"master"}},"spec":{"replicas":1,"selector":{"app":"redis","role":"master"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"master"}},"spec":{"containers":[{"name":"redis-master","image":"redis","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0,"observedGeneration":1}},{"metadata":{"name":"redis-slave","namespace":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave","uid":"f42e1d09-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"567","generation":1,"creationTimestamp":"2015-08-09T10:03:59Z","labels":{"app":"redis","role":"slave"}},"spec":{"replicas":2,"selector":{"app":"redis","role":"slave"},"template":{"metadata":{"creationTimestamp":null,"labels":{"app":"redis","role":"slave"}},"spec":{"containers":[{"name":"redis-slave","image":"kubernetes/redis-slave:v2","ports":[{"name":"redis-server","containerPort":6379,"protocol":"TCP"}],"resources":{},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent"}],"restartPolicy":"Always","dnsPolicy":"ClusterFirst"}}},"status":{"replicas":0}}]}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/guestbook
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-master
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/services/redis-slave
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/guestbook
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-master
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns/replicationcontrollers/redis-slave
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '100'
+ body:
+ encoding: UTF-8
+ string: |-
+ {
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Success",
+ "code": 200
+ }
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: delete
+ uri: http://10.35.0.23:8080/api/v1/namespaces/kubeclient-ns
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - '*/*; q=0.5, application/xml'
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - Ruby
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Sun, 09 Aug 2015 10:03:59 GMT
+ Content-Length:
+ - '345'
+ body:
+ encoding: UTF-8
+ string: '{"kind":"Namespace","apiVersion":"v1","metadata":{"name":"kubeclient-ns","selfLink":"/api/v1/namespaces/kubeclient-ns","uid":"f41e6b27-3e7d-11e5-a75a-18037327aaeb","resourceVersion":"584","creationTimestamp":"2015-08-09T10:03:59Z","deletionTimestamp":"2015-08-09T10:03:59Z"},"spec":{"finalizers":["kubernetes"]},"status":{"phase":"Terminating"}}'
+ http_version:
+ recorded_at: Sun, 09 Aug 2015 10:00:02 GMT
+- request:
+ method: get
+ uri: http://10.35.0.23:8080/api/v1
+ body:
+ encoding: US-ASCII
+ string: ''
+ headers:
+ Accept:
+ - "*/*"
+ Accept-Encoding:
+ - gzip, deflate
+ User-Agent:
+ - rest-client/2.0.0 (linux-gnu x86_64) ruby/2.3.0p0
+ Host:
+ - localhost:8080
+ response:
+ status:
+ code: 200
+ message: OK
+ headers:
+ Content-Type:
+ - application/json
+ Date:
+ - Mon, 29 Aug 2016 15:51:30 GMT
+ Transfer-Encoding:
+ - chunked
+ body:
+ encoding: UTF-8
+ string: '{"kind":"APIResourceList","groupVersion":"v1","resources":[{"name":"bindings","namespaced":true,"kind":"Binding"},{"name":"componentstatuses","namespaced":false,"kind":"ComponentStatus"},{"name":"configmaps","namespaced":true,"kind":"ConfigMap"},{"name":"endpoints","namespaced":true,"kind":"Endpoints"},{"name":"events","namespaced":true,"kind":"Event"},{"name":"limitranges","namespaced":true,"kind":"LimitRange"},{"name":"namespaces","namespaced":false,"kind":"Namespace"},{"name":"namespaces/finalize","namespaced":false,"kind":"Namespace"},{"name":"namespaces/status","namespaced":false,"kind":"Namespace"},{"name":"nodes","namespaced":false,"kind":"Node"},{"name":"nodes/proxy","namespaced":false,"kind":"Node"},{"name":"nodes/status","namespaced":false,"kind":"Node"},{"name":"persistentvolumeclaims","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumeclaims/status","namespaced":true,"kind":"PersistentVolumeClaim"},{"name":"persistentvolumes","namespaced":false,"kind":"PersistentVolume"},{"name":"persistentvolumes/status","namespaced":false,"kind":"PersistentVolume"},{"name":"pods","namespaced":true,"kind":"Pod"},{"name":"pods/attach","namespaced":true,"kind":"Pod"},{"name":"pods/binding","namespaced":true,"kind":"Binding"},{"name":"pods/exec","namespaced":true,"kind":"Pod"},{"name":"pods/log","namespaced":true,"kind":"Pod"},{"name":"pods/portforward","namespaced":true,"kind":"Pod"},{"name":"pods/proxy","namespaced":true,"kind":"Pod"},{"name":"pods/status","namespaced":true,"kind":"Pod"},{"name":"podtemplates","namespaced":true,"kind":"PodTemplate"},{"name":"replicationcontrollers","namespaced":true,"kind":"ReplicationController"},{"name":"replicationcontrollers/scale","namespaced":true,"kind":"Scale"},{"name":"replicationcontrollers/status","namespaced":true,"kind":"ReplicationController"},{"name":"resourcequotas","namespaced":true,"kind":"ResourceQuota"},{"name":"resourcequotas/status","namespaced":true,"kind":"ResourceQuota"},{"name":"secrets","namespaced":true,"kind":"Secret"},{"name":"serviceaccounts","namespaced":true,"kind":"ServiceAccount"},{"name":"services","namespaced":true,"kind":"Service"},{"name":"services/proxy","namespaced":true,"kind":"Service"},{"name":"services/status","namespaced":true,"kind":"Service"}]}
+
+'
+ http_version:
+ recorded_at: Mon, 29 Aug 2016 15:51:30 GMT
+recorded_with: VCR 3.0.3
diff --git a/vendor/gems/kubeclient/test/config/allinone.kubeconfig b/vendor/gems/kubeclient/test/config/allinone.kubeconfig
new file mode 100644
index 00000000000..f06db6af123
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/allinone.kubeconfig
@@ -0,0 +1,21 @@
+
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:6443
+ certificate-authority-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSUMvekNDQWVlZ0F3SUJBZ0lUUGJmcHkyOWFCRzY3Q2hSZEI2bEplZ1RrbURBTkJna3Foa2lHOXcwQkFRc0YKQURBWU1SWXdGQVlEVlFRREV3MXJkV0psY201bGRHVnpMV05oTUI0WERUSXlNREl5TVRBNU1ESXdNRm9YRFRNeQpNREl4T1RBNU1ESXdNRm93R0RFV01CUUdBMVVFQXhNTmEzVmlaWEp1WlhSbGN5MWpZVENDQVNJd0RRWUpLb1pJCmh2Y05BUUVCQlFBRGdnRVBBRENDQVFvQ2dnRUJBTUxqWjJjRkJhbHpvaW1hRWNwVDlKejJKbWRnc0hNT2FnVmQKSXQ3T1FwVHdEWjNucElJQ1ZwZ3VFaDl4dG92UjhtOC9IWU0rL2E0dk1RSFQrM3A4SFBqaURhUllHZzdPWjlMKwpGcC85emhCdWlhSXZnOForQmJ5czlROVV1ajZWRXdmRkpCY05INlRtemRpRGdRVXM1L2srNi92dHVKNHlzM3NECktrQU94cVBYRGFCb0FObkxwSXhkSU1RRGNXU0xGQTB3bUZoZFpKcTNLRUFvSnBFTDBXWW8xWlJCVjNpSDc3eWYKc0RiTjFPQnUydk5uUlorRHJWMFpKNUFwbWJGWFBYOGk0S0phVzlsQ0I2MkZOMGo1WHNORG95VGVBVnBlc2ZOcwp6WXVmVnBCZHFOWkZrT0tnOWRpTXVUTWlrYTJhWWZEdWlWemRlYkRnY3A5YU1sb0t0YkVDQXdFQUFhTkNNRUF3CkRnWURWUjBQQVFIL0JBUURBZ0VHTUE4R0ExVWRFd0VCL3dRRk1BTUJBZjh3SFFZRFZSME9CQllFRkJkT2l5Z0MKTGN1SnJxOHJOYTF4QURyNVNwN0NNQTBHQ1NxR1NJYjNEUUVCQ3dVQUE0SUJBUURDeTRJbGhBU2g2QnI1WEVjSQpUcFA1VGhEMU95UnpRbnNQZTZQMXFnV1Aza0JYSy9BY3NTbCtWR3RhWnAyb0VoSm9VbnN6N2tFOHlXM2dLK1BBCjUxelk0YUhUaUY5eGt5ZDV6T0NBR0IrY2ZwOVlzK3N6V3p5dTBRUTlJQmpKNCtlRGpnN1cwL1MrQk0yUW4xaUwKalRGSWUyQmRmK1EvSjI0L3Eza3NUWEsxN1VOdW4xNHZEUnNKZ3NOY3JGdC9ydW1mSFB4MXl0d3NpcUt5RUtWNwprRnhTd2EzZDgvQXZoR2dGcFBtZlJqVTdnQUpDRmNIejUwMXpoaTJhNkw1VFlCVGVjVlJicVpvZUhpWjBZTldJCmlzNWc0Vm1WQitCeE1BTTJXRWQyOXY0bC8zb0kxUGV5OXJ2dDdOSnFTZTFpbTl1cVpnVkRlZy92UDh6S3MvZEYKWll3OAotLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tCg==
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate-data: LS0tLS1CRUdJTiBDRVJUSUZJQ0FURS0tLS0tCk1JSURXVENDQWtHZ0F3SUJBZ0lVS08xZVJtWG1DYyt2dk0rTG9CeVpFMElNR0Q4d0RRWUpLb1pJaHZjTkFRRUwKQlFBd0dERVdNQlFHQTFVRUF4TU5hM1ZpWlhKdVpYUmxjeTFqWVRBZUZ3MHlNakF5TWpFd09UQXlNREJhRncweQpNekF5TWpFd09UQXlNREJhTURReEZ6QVZCZ05WQkFvVERuTjVjM1JsYlRwdFlYTjBaWEp6TVJrd0Z3WURWUVFECkV4QnJkV0psY201bGRHVnpMV0ZrYldsdU1JSUJJakFOQmdrcWhraUc5dzBCQVFFRkFBT0NBUThBTUlJQkNnS0MKQVFFQXdodzF6SmFBWVcwa0ljbjVtV3lYTm03SVlEYStRTXpIM0hWWnJnd1l5Y0NaWlA5MGJZSmo0VEYrKyszbgpQTVoydU1mWkVYY21OcEdYQ0lxek5ZSlF6dlQrYTF6Q011VVQ5K3YxZzM0My9WYVlweFJ6R3VlQ1ZGK3B2Qi9nCmpJMFU0bDFZbUpJRWs1WGNETTl4RStob1Vrd3FWYWhNbXJ2c3E4aHluWWp6V0V0bDBtSitUTzg5LzFaandBdVEKdDRvaE5PMXBRdTNyNEhDdTNIR2JGU1RQSjZFNG94UmdkTXFIbHFzd3BHMCtaTFJYVmtvZ1VidGxJVUx0Y3RvVQpUNjdmaHNUaFJDWXUyQUFpbitMMjBncjNUY3A0VXRNV3RUY1o2NnZsTDJFcDZUa1dpdXRiMDRML0JvNDZWZnhPCnNLQkNkTjFqeXNPZVRQZ1RXS2gwODh2TTB3SURBUUFCbzM4d2ZUQU9CZ05WSFE4QkFmOEVCQU1DQmFBd0hRWUQKVlIwbEJCWXdGQVlJS3dZQkJRVUhBd0VHQ0NzR0FRVUZCd01DTUF3R0ExVWRFd0VCL3dRQ01BQXdIUVlEVlIwTwpCQllFRko2NzV6N0dDSXVKY2JHeEo3YkxJM0pBTDNCZU1COEdBMVVkSXdRWU1CYUFGQmRPaXlnQ0xjdUpycThyCk5hMXhBRHI1U3A3Q01BMEdDU3FHU0liM0RRRUJDd1VBQTRJQkFRQ1hHQ2hlbytWVXhsRlJQRVhSU3B3NDgwbGIKMm12ZHpCNE8vck9JRzJIOXZ6Z2poeGJkQ0pOVmVka0d6bUhaNzVlRUh6djFFa0luZWJTR0xGejUvUDNCUVVYdwp4eXU4NGpOSmVyOVJlMmdlbVYwdDJtd3pIV0NmUUdMS0c0QUppN00rY3haNDlYaHVtWlJWa3c3aU9SRitxWU9qCmhTbG9CLzRrZnlxM1VhcHJLQ3ZocWpFc0tKcURuZHdsT3dLTFZNaWMzbFFETExYb0thNVRpdjZpaEJpQ1ZXQUkKWFV5NWwyZG9EdlpoemdFakxlUTBDR0hiNTl2Q3Zkb3RUYzBiN0hKNFp3MjFBTHoyQ0Y3eGt3WGpQNXVVSXE1Ngo2UG1RK2dwSFhrbGJOSklPRHRrZi85STRyTWxIVXplSzVEVllZNWtkeEpUemgybng0UjBpY0Z4MWpuYzAKLS0tLS1FTkQgQ0VSVElGSUNBVEUtLS0tLQo=
+ client-key-data: LS0tLS1CRUdJTiBSU0EgUFJJVkFURSBLRVktLS0tLQpNSUlFcFFJQkFBS0NBUUVBd2h3MXpKYUFZVzBrSWNuNW1XeVhObTdJWURhK1FNekgzSFZacmd3WXljQ1paUDkwCmJZSmo0VEYrKyszblBNWjJ1TWZaRVhjbU5wR1hDSXF6TllKUXp2VCthMXpDTXVVVDkrdjFnMzQzL1ZhWXB4UnoKR3VlQ1ZGK3B2Qi9nakkwVTRsMVltSklFazVYY0RNOXhFK2hvVWt3cVZhaE1tcnZzcThoeW5ZanpXRXRsMG1KKwpUTzg5LzFaandBdVF0NG9oTk8xcFF1M3I0SEN1M0hHYkZTVFBKNkU0b3hSZ2RNcUhscXN3cEcwK1pMUlhWa29nClVidGxJVUx0Y3RvVVQ2N2Zoc1RoUkNZdTJBQWluK0wyMGdyM1RjcDRVdE1XdFRjWjY2dmxMMkVwNlRrV2l1dGIKMDRML0JvNDZWZnhPc0tCQ2ROMWp5c09lVFBnVFdLaDA4OHZNMHdJREFRQUJBb0lCQVFEQlhHQ3JRSEQ2bkVJVgo5cURSR0w4NDFmcDgvWXRmK1o1T0dnZ1B2TFVrcE5zcEpOL1NCc1dBR2xJb204QnhaakgxdC82ZnkxVWhucjRaCklER002QmVmVWFYdlJTT2VsMXZnNkFoVnlISDF4MEdoamxsclA1c3dlV3NYbjVtTDZTNFlvR3dVNzcvblZLMHoKaGFGYTkzU1VKcE0xYU1XR2poVWd1amlTZlU0TGNMRFJWS0RFUk80OFhQOEZpQ0E2UEIySUpYUDBTOUJhTVZLUQpIQVJDV05HWDV6aU5hbzFyb0l2UFFORU1EVHRuV2JiNHo0U3ZSbXBjRjYwRS9mNEpwMDZTSDAwUU5lVHY3bjU3CkR6U1hZZGNxbGZMUjlRU1RkVmt0U094UThjSGFsVGN5NXNVMnh5RndjMVM5YVpaOG56UnBiRnUxVllGQ0lWY2YKRTRRVnYxVUJBb0dCQU1XZzRuWlRIaUd0aGY2S3l6T0draDFyMmtCU21WeTlCY1lqQjhUYnpRYnJOVXk3WUFsVAppN2VPbkYrdVRLY2FWYzV2blVyVjBsN3pEM1dTV3UxQVJiOUs2WnBWTDV3allObW0venVyUittSmM4TEtsN2Q2CjU0ejFjMTExVDVpaXZNMWJZUm5VME91akhEb1g1WkQ1V0dzeE1LYUh0TGFHV1gvZ0s0OWhQYmZ6QW9HQkFQdHgKVFdRSGlPcS91VnNrMFFuWWtLWkV3ZXpmZEMyZGFWSm9BeURBVjVnY1U0TnNONjJVS2ZnVHJhRCtDaG15SjVSNwpqT1NMOGJVWDMzUVFFdm1LOVdZWE1WQnd6MjhIclp5cHVCeVFFRWM4ZTl5eTRZUStSWVoxTDJrbUdkYWVaOE16CmlEZmZMclhieTdOWnA0eGNmTVpXWW1Md2RHRVNZbzhqenVjaTFLK2hBb0dCQUpESXprQmJvbTZQM3VQZHNRTGQKcXZ4TkFJY3hQRlA1MDFvV1hlRzJHaDNnZ1pybWgzUXR0ZVZUWUhLa2tsbTE3SGtod2oyS0t1WU84aHR6anBQVQpDNFVhajh2V2J0dlgrMk5aZWhHdjZTNUoyZm95VERaS240cmdZNVZybFZYQW04dGpEOTlKejRsaVpSS1dZVVAxCnVQWkhBbHB1ZjFGZFdnSmFLKytPRVJaTEFvR0FLSmQ5K3V3TWVubEJIeW11Wlh5RXZaTFVDNzEzTC9YOWpzUWoKM1NHd0FtcHdRUU16YWQ1RmVEc1ZDS3g2VFBPcDJCcXFBQ3RuZGVqSXRoL3lNRDd5cHV5UGxZRGd1L2Z0V3lFNwpDOEZtSDFud1ZReTd3M0dhSDc3RFRLSk9BWXZKRElaQk0yUGdVcE9OS3dNS1BXcWc2aFFBQmlEemFNaGpDT0NyCkFqMXBRSUVDZ1lFQWw2THZncFl6enlUVThtRmFYazUrQXVaVHB1dlZzNXNOVEUwQmdyUWJBN0haL0hjT3hLaWQKYkxPU1diVzNaZ05aV0xXOFNhdWlURCt4L2lmVGR6UUJHQnZOaGFJaklGNnltdFlwTzNaWCs2MG15L1hUZmJGUQordUJ3UDducU1JUnNuQjUzRlc0S3VWcWljMDVEbGdvRWJ5NWM1eTlPQjlyWUQzUnJTT01EbGFzPQotLS0tLUVORCBSU0EgUFJJVkFURSBLRVktLS0tLQo=
diff --git a/vendor/gems/kubeclient/test/config/another-ca1.pem b/vendor/gems/kubeclient/test/config/another-ca1.pem
new file mode 100644
index 00000000000..50825d47519
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/another-ca1.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDADCCAeigAwIBAgIUQZjM/5qoAF78qIDyc+rKi4qBdOIwDQYJKoZIhvcNAQEL
+BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQzMDBaFw0z
+MjAzMTkxNDQzMDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGkG7g+UjpDhZ7A4Pm7Hme+RWs5IHz4I2X
+IclvtO3LuJ26yzz2S8VaXFFeUqzEPb2G1RxFGvoAVN7qrTw0n5MQJCFLAA4dI7oY
+8XLRJ7KgTBBIw1jYpgKb2zyHPIJE6VmslliKUiX+QDovdRU/dsbdup2EucrnGw4+
+QNNAc3XMbXgm6lubA6znYZlSpcQ8BKer3tq75q4KUZicIjS6gKQyZjk9a6fcOuCS
+ybtlAKp9lYzcwxZkNrx+V1PJMQ1qaJWPnMAVi7Oj5Dm3Jmf1WHBcNEh52Q/0vYlt
+4WSaeM5t/Py/m/7c4Ve97f5m2X6EhYyUbzov4qeZOnIJI3MnU1FxAgMBAAGjQjBA
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSl1qyt
+jd96WstRE8h9x5qkCvZUvjANBgkqhkiG9w0BAQsFAAOCAQEAJt55qYvBaniAwvgO
+tbO79g1FcQGrxpMX45TuoCE/K+MWDjrr6bp+FbLOqT8MwOsbGwwJIRTHGvkEkVso
+5AWI5aSNs3hWnltOdz27ZSHeX77WB4daK1tLK6ggZrp3v9iIpbBwWBFdmAqsPvEs
+H17K2BgAzdh6xRKPQd0BGTUpJBfk50R2gDMj7FKyIzBN69IOGytBfAXBhHzEGy4+
+MvtTEIMUjR//KgCrpNeyDuaWHttR5FdnuRxFO7O3BAfyNSaNmd/IEHQf7DIGgzOy
++xWLyH/HRHj5C70qAqjbnrgBODI99BsA9U7oXTuyPLdIboAcFt2zD5DIYgZET52X
+53w4jA==
+-----END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/another-ca2.pem b/vendor/gems/kubeclient/test/config/another-ca2.pem
new file mode 100644
index 00000000000..53be72e87d7
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/another-ca2.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDADCCAeigAwIBAgIUHW3OPnmuTquJ0YgbGpmm/blsY2QwDQYJKoZIhvcNAQEL
+BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQ0MDBaFw0z
+MjAzMTkxNDQ0MDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLMEJs5agS0hNQBxPTtsI6dIhIi/pY8liI
+sNukbi5KwKf80FYNyRXqE8ufDVyTFzOc+MG96jnHjDaBWjrVN9On0PgUBo4nPyd4
+DtyvYx2jMzwToSEIo/Z1aroMx1oGywCgdS4/3FWAbhlSbyXKJmhfh6gX0TxWz+dV
+zqNuqQq9EWuRhOMg9vgzjfp3mjiPE10lW8pT0j5JT3PI/eGO+C2Z7z33LJXb6GM2
+nXvhGFMGY+7XG65pqJ3L8g1mk+LjPiwyIItw8wPtrnrZ2VXMklMd5Mn+jgCTNe1B
+om0nPpPIiTblCr6gcNcVjy5WGN37OKlqrT0JTuSPHcxSUp05LFjDAgMBAAGjQjBA
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQvV/sB
+wbR3UwjkLAMN+6P3fZ/3OjANBgkqhkiG9w0BAQsFAAOCAQEACAk4EQwCkw2EBsSR
+2SKoa1SjYFkZzIr/0/TB2YcMUvHF+RpvlD5vQ8/RJjeAl1kc6/niZ9TWCemjBLqI
+hPoFe49zr49DyQjC2ZfsXVJvFCr6g7o4q4DtQ6ltyBuTJbkn1hI+aB8zgvpofG44
+mKj18Y7tPvgXtRua4SaeBq777+22AOvKxPied9p4PTrMN4RKTP6+yIbLflej7dBD
+zQDjfmmYsH0T2ZRtBpE1dYrUbU3tkizcMZRJBgreoxoff+r5coibMIm/7gh+YoSb
+BCItCaeuGSKQ8CJb8DElcPUd6nKUjmeiQL68ztsG/+CXLiL/TZb914VaaCXvPInw
+49jJ7w==
+-----END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig b/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig
new file mode 100644
index 00000000000..ed20e4dde50
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/concatenated-ca.kubeconfig
@@ -0,0 +1,20 @@
+apiVersion: v1
+clusters:
+- cluster:
+ certificate-authority: concatenated-ca.pem
+ server: https://localhost:6443
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/concatenated-ca.pem b/vendor/gems/kubeclient/test/config/concatenated-ca.pem
new file mode 100644
index 00000000000..1117298ff2d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/concatenated-ca.pem
@@ -0,0 +1,57 @@
+-----BEGIN CERTIFICATE-----
+MIIDADCCAeigAwIBAgIUQZjM/5qoAF78qIDyc+rKi4qBdOIwDQYJKoZIhvcNAQEL
+BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQzMDBaFw0z
+MjAzMTkxNDQzMDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDGkG7g+UjpDhZ7A4Pm7Hme+RWs5IHz4I2X
+IclvtO3LuJ26yzz2S8VaXFFeUqzEPb2G1RxFGvoAVN7qrTw0n5MQJCFLAA4dI7oY
+8XLRJ7KgTBBIw1jYpgKb2zyHPIJE6VmslliKUiX+QDovdRU/dsbdup2EucrnGw4+
+QNNAc3XMbXgm6lubA6znYZlSpcQ8BKer3tq75q4KUZicIjS6gKQyZjk9a6fcOuCS
+ybtlAKp9lYzcwxZkNrx+V1PJMQ1qaJWPnMAVi7Oj5Dm3Jmf1WHBcNEh52Q/0vYlt
+4WSaeM5t/Py/m/7c4Ve97f5m2X6EhYyUbzov4qeZOnIJI3MnU1FxAgMBAAGjQjBA
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSl1qyt
+jd96WstRE8h9x5qkCvZUvjANBgkqhkiG9w0BAQsFAAOCAQEAJt55qYvBaniAwvgO
+tbO79g1FcQGrxpMX45TuoCE/K+MWDjrr6bp+FbLOqT8MwOsbGwwJIRTHGvkEkVso
+5AWI5aSNs3hWnltOdz27ZSHeX77WB4daK1tLK6ggZrp3v9iIpbBwWBFdmAqsPvEs
+H17K2BgAzdh6xRKPQd0BGTUpJBfk50R2gDMj7FKyIzBN69IOGytBfAXBhHzEGy4+
+MvtTEIMUjR//KgCrpNeyDuaWHttR5FdnuRxFO7O3BAfyNSaNmd/IEHQf7DIGgzOy
++xWLyH/HRHj5C70qAqjbnrgBODI99BsA9U7oXTuyPLdIboAcFt2zD5DIYgZET52X
+53w4jA==
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgITPbfpy29aBG67ChRdB6lJegTkmDANBgkqhkiG9w0BAQsF
+ADAYMRYwFAYDVQQDEw1rdWJlcm5ldGVzLWNhMB4XDTIyMDIyMTA5MDIwMFoXDTMy
+MDIxOTA5MDIwMFowGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMLjZ2cFBalzoimaEcpT9Jz2JmdgsHMOagVd
+It7OQpTwDZ3npIICVpguEh9xtovR8m8/HYM+/a4vMQHT+3p8HPjiDaRYGg7OZ9L+
+Fp/9zhBuiaIvg8Z+Bbys9Q9Uuj6VEwfFJBcNH6TmzdiDgQUs5/k+6/vtuJ4ys3sD
+KkAOxqPXDaBoANnLpIxdIMQDcWSLFA0wmFhdZJq3KEAoJpEL0WYo1ZRBV3iH77yf
+sDbN1OBu2vNnRZ+DrV0ZJ5ApmbFXPX8i4KJaW9lCB62FN0j5XsNDoyTeAVpesfNs
+zYufVpBdqNZFkOKg9diMuTMika2aYfDuiVzdebDgcp9aMloKtbECAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBdOiygC
+LcuJrq8rNa1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQDCy4IlhASh6Br5XEcI
+TpP5ThD1OyRzQnsPe6P1qgWP3kBXK/AcsSl+VGtaZp2oEhJoUnsz7kE8yW3gK+PA
+51zY4aHTiF9xkyd5zOCAGB+cfp9Ys+szWzyu0QQ9IBjJ4+eDjg7W0/S+BM2Qn1iL
+jTFIe2Bdf+Q/J24/q3ksTXK17UNun14vDRsJgsNcrFt/rumfHPx1ytwsiqKyEKV7
+kFxSwa3d8/AvhGgFpPmfRjU7gAJCFcHz501zhi2a6L5TYBTecVRbqZoeHiZ0YNWI
+is5g4VmVB+BxMAM2WEd29v4l/3oI1Pey9rvt7NJqSe1im9uqZgVDeg/vP8zKs/dF
+ZYw8
+-----END CERTIFICATE-----
+-----BEGIN CERTIFICATE-----
+MIIDADCCAeigAwIBAgIUHW3OPnmuTquJ0YgbGpmm/blsY2QwDQYJKoZIhvcNAQEL
+BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAzMjIxNDQ0MDBaFw0z
+MjAzMTkxNDQ0MDBaMBgxFjAUBgNVBAMTDWt1YmVybmV0ZXMtY2EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDLMEJs5agS0hNQBxPTtsI6dIhIi/pY8liI
+sNukbi5KwKf80FYNyRXqE8ufDVyTFzOc+MG96jnHjDaBWjrVN9On0PgUBo4nPyd4
+DtyvYx2jMzwToSEIo/Z1aroMx1oGywCgdS4/3FWAbhlSbyXKJmhfh6gX0TxWz+dV
+zqNuqQq9EWuRhOMg9vgzjfp3mjiPE10lW8pT0j5JT3PI/eGO+C2Z7z33LJXb6GM2
+nXvhGFMGY+7XG65pqJ3L8g1mk+LjPiwyIItw8wPtrnrZ2VXMklMd5Mn+jgCTNe1B
+om0nPpPIiTblCr6gcNcVjy5WGN37OKlqrT0JTuSPHcxSUp05LFjDAgMBAAGjQjBA
+MA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBQvV/sB
+wbR3UwjkLAMN+6P3fZ/3OjANBgkqhkiG9w0BAQsFAAOCAQEACAk4EQwCkw2EBsSR
+2SKoa1SjYFkZzIr/0/TB2YcMUvHF+RpvlD5vQ8/RJjeAl1kc6/niZ9TWCemjBLqI
+hPoFe49zr49DyQjC2ZfsXVJvFCr6g7o4q4DtQ6ltyBuTJbkn1hI+aB8zgvpofG44
+mKj18Y7tPvgXtRua4SaeBq777+22AOvKxPied9p4PTrMN4RKTP6+yIbLflej7dBD
+zQDjfmmYsH0T2ZRtBpE1dYrUbU3tkizcMZRJBgreoxoff+r5coibMIm/7gh+YoSb
+BCItCaeuGSKQ8CJb8DElcPUd6nKUjmeiQL68ztsG/+CXLiL/TZb914VaaCXvPInw
+49jJ7w==
+-----END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/execauth.kubeconfig b/vendor/gems/kubeclient/test/config/execauth.kubeconfig
new file mode 100644
index 00000000000..c9a9773fe5e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/execauth.kubeconfig
@@ -0,0 +1,61 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:6443
+ name: localhost:6443
+contexts:
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: system:admin:exec-search-path
+ name: localhost/system:admin:exec-search-path
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: system:admin:exec-relative-path
+ name: localhost/system:admin:exec-relative-path
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: system:admin:exec-absolute-path
+ name: localhost/system:admin:exec-absolute-path
+kind: Config
+preferences: {}
+users:
+- name: system:admin:exec-search-path
+ user:
+ exec:
+ # Command to execute. Required.
+ command: "example-exec-plugin"
+
+ # API version to use when decoding the ExecCredentials resource. Required.
+ #
+ # The API version returned by the plugin MUST match the version listed here.
+ #
+ # To integrate with tools that support multiple versions (such as client.authentication.k8s.io/v1alpha1),
+ # set an environment variable or pass an argument to the tool that indicates which version the exec plugin expects.
+ apiVersion: "client.authentication.k8s.io/v1beta1"
+
+ # Environment variables to set when executing the plugin. Optional.
+ env:
+ - name: "FOO"
+ value: "bar"
+
+ # Arguments to pass when executing the plugin. Optional.
+ args:
+ - "arg1"
+ - "arg2"
+
+- name: system:admin:exec-relative-path
+ user:
+ exec:
+ # Command to execute. Required.
+ command: "dir/example-exec-plugin"
+ apiVersion: "client.authentication.k8s.io/v1beta1"
+
+- name: system:admin:exec-absolute-path
+ user:
+ exec:
+ # Command to execute. Required.
+ command: "/abs/path/example-exec-plugin"
+ apiVersion: "client.authentication.k8s.io/v1beta1"
diff --git a/vendor/gems/kubeclient/test/config/external-ca.pem b/vendor/gems/kubeclient/test/config/external-ca.pem
new file mode 100644
index 00000000000..f1c8a8b615d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/external-ca.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIC/zCCAeegAwIBAgITPbfpy29aBG67ChRdB6lJegTkmDANBgkqhkiG9w0BAQsF
+ADAYMRYwFAYDVQQDEw1rdWJlcm5ldGVzLWNhMB4XDTIyMDIyMTA5MDIwMFoXDTMy
+MDIxOTA5MDIwMFowGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAMLjZ2cFBalzoimaEcpT9Jz2JmdgsHMOagVd
+It7OQpTwDZ3npIICVpguEh9xtovR8m8/HYM+/a4vMQHT+3p8HPjiDaRYGg7OZ9L+
+Fp/9zhBuiaIvg8Z+Bbys9Q9Uuj6VEwfFJBcNH6TmzdiDgQUs5/k+6/vtuJ4ys3sD
+KkAOxqPXDaBoANnLpIxdIMQDcWSLFA0wmFhdZJq3KEAoJpEL0WYo1ZRBV3iH77yf
+sDbN1OBu2vNnRZ+DrV0ZJ5ApmbFXPX8i4KJaW9lCB62FN0j5XsNDoyTeAVpesfNs
+zYufVpBdqNZFkOKg9diMuTMika2aYfDuiVzdebDgcp9aMloKtbECAwEAAaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFBdOiygC
+LcuJrq8rNa1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQDCy4IlhASh6Br5XEcI
+TpP5ThD1OyRzQnsPe6P1qgWP3kBXK/AcsSl+VGtaZp2oEhJoUnsz7kE8yW3gK+PA
+51zY4aHTiF9xkyd5zOCAGB+cfp9Ys+szWzyu0QQ9IBjJ4+eDjg7W0/S+BM2Qn1iL
+jTFIe2Bdf+Q/J24/q3ksTXK17UNun14vDRsJgsNcrFt/rumfHPx1ytwsiqKyEKV7
+kFxSwa3d8/AvhGgFpPmfRjU7gAJCFcHz501zhi2a6L5TYBTecVRbqZoeHiZ0YNWI
+is5g4VmVB+BxMAM2WEd29v4l/3oI1Pey9rvt7NJqSe1im9uqZgVDeg/vP8zKs/dF
+ZYw8
+-----END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/external-cert.pem b/vendor/gems/kubeclient/test/config/external-cert.pem
new file mode 100644
index 00000000000..6c8b5232d7a
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/external-cert.pem
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDWTCCAkGgAwIBAgIUKO1eRmXmCc+vvM+LoByZE0IMGD8wDQYJKoZIhvcNAQEL
+BQAwGDEWMBQGA1UEAxMNa3ViZXJuZXRlcy1jYTAeFw0yMjAyMjEwOTAyMDBaFw0y
+MzAyMjEwOTAyMDBaMDQxFzAVBgNVBAoTDnN5c3RlbTptYXN0ZXJzMRkwFwYDVQQD
+ExBrdWJlcm5ldGVzLWFkbWluMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAwhw1zJaAYW0kIcn5mWyXNm7IYDa+QMzH3HVZrgwYycCZZP90bYJj4TF+++3n
+PMZ2uMfZEXcmNpGXCIqzNYJQzvT+a1zCMuUT9+v1g343/VaYpxRzGueCVF+pvB/g
+jI0U4l1YmJIEk5XcDM9xE+hoUkwqVahMmrvsq8hynYjzWEtl0mJ+TO89/1ZjwAuQ
+t4ohNO1pQu3r4HCu3HGbFSTPJ6E4oxRgdMqHlqswpG0+ZLRXVkogUbtlIULtctoU
+T67fhsThRCYu2AAin+L20gr3Tcp4UtMWtTcZ66vlL2Ep6TkWiutb04L/Bo46VfxO
+sKBCdN1jysOeTPgTWKh088vM0wIDAQABo38wfTAOBgNVHQ8BAf8EBAMCBaAwHQYD
+VR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0O
+BBYEFJ675z7GCIuJcbGxJ7bLI3JAL3BeMB8GA1UdIwQYMBaAFBdOiygCLcuJrq8r
+Na1xADr5Sp7CMA0GCSqGSIb3DQEBCwUAA4IBAQCXGCheo+VUxlFRPEXRSpw480lb
+2mvdzB4O/rOIG2H9vzgjhxbdCJNVedkGzmHZ75eEHzv1EkInebSGLFz5/P3BQUXw
+xyu84jNJer9Re2gemV0t2mwzHWCfQGLKG4AJi7M+cxZ49XhumZRVkw7iORF+qYOj
+hSloB/4kfyq3UaprKCvhqjEsKJqDndwlOwKLVMic3lQDLLXoKa5Tiv6ihBiCVWAI
+XUy5l2doDvZhzgEjLeQ0CGHb59vCvdotTc0b7HJ4Zw21ALz2CF7xkwXjP5uUIq56
+6PmQ+gpHXklbNJIODtkf/9I4rMlHUzeK5DVYY5kdxJTzh2nx4R0icFx1jnc0
+-----END CERTIFICATE-----
diff --git a/vendor/gems/kubeclient/test/config/external-key.rsa b/vendor/gems/kubeclient/test/config/external-key.rsa
new file mode 100644
index 00000000000..c79c1f2c310
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/external-key.rsa
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAwhw1zJaAYW0kIcn5mWyXNm7IYDa+QMzH3HVZrgwYycCZZP90
+bYJj4TF+++3nPMZ2uMfZEXcmNpGXCIqzNYJQzvT+a1zCMuUT9+v1g343/VaYpxRz
+GueCVF+pvB/gjI0U4l1YmJIEk5XcDM9xE+hoUkwqVahMmrvsq8hynYjzWEtl0mJ+
+TO89/1ZjwAuQt4ohNO1pQu3r4HCu3HGbFSTPJ6E4oxRgdMqHlqswpG0+ZLRXVkog
+UbtlIULtctoUT67fhsThRCYu2AAin+L20gr3Tcp4UtMWtTcZ66vlL2Ep6TkWiutb
+04L/Bo46VfxOsKBCdN1jysOeTPgTWKh088vM0wIDAQABAoIBAQDBXGCrQHD6nEIV
+9qDRGL841fp8/Ytf+Z5OGggPvLUkpNspJN/SBsWAGlIom8BxZjH1t/6fy1Uhnr4Z
+IDGM6BefUaXvRSOel1vg6AhVyHH1x0GhjllrP5sweWsXn5mL6S4YoGwU77/nVK0z
+haFa93SUJpM1aMWGjhUgujiSfU4LcLDRVKDERO48XP8FiCA6PB2IJXP0S9BaMVKQ
+HARCWNGX5ziNao1roIvPQNEMDTtnWbb4z4SvRmpcF60E/f4Jp06SH00QNeTv7n57
+DzSXYdcqlfLR9QSTdVktSOxQ8cHalTcy5sU2xyFwc1S9aZZ8nzRpbFu1VYFCIVcf
+E4QVv1UBAoGBAMWg4nZTHiGthf6KyzOGkh1r2kBSmVy9BcYjB8TbzQbrNUy7YAlT
+i7eOnF+uTKcaVc5vnUrV0l7zD3WSWu1ARb9K6ZpVL5wjYNmm/zurR+mJc8LKl7d6
+54z1c111T5iivM1bYRnU0OujHDoX5ZD5WGsxMKaHtLaGWX/gK49hPbfzAoGBAPtx
+TWQHiOq/uVsk0QnYkKZEwezfdC2daVJoAyDAV5gcU4NsN62UKfgTraD+ChmyJ5R7
+jOSL8bUX33QQEvmK9WYXMVBwz28HrZypuByQEEc8e9yy4YQ+RYZ1L2kmGdaeZ8Mz
+iDffLrXby7NZp4xcfMZWYmLwdGESYo8jzuci1K+hAoGBAJDIzkBbom6P3uPdsQLd
+qvxNAIcxPFP501oWXeG2Gh3ggZrmh3QtteVTYHKkklm17Hkhwj2KKuYO8htzjpPU
+C4Uaj8vWbtvX+2NZehGv6S5J2foyTDZKn4rgY5VrlVXAm8tjD99Jz4liZRKWYUP1
+uPZHAlpuf1FdWgJaK++OERZLAoGAKJd9+uwMenlBHymuZXyEvZLUC713L/X9jsQj
+3SGwAmpwQQMzad5FeDsVCKx6TPOp2BqqACtndejIth/yMD7ypuyPlYDgu/ftWyE7
+C8FmH1nwVQy7w3GaH77DTKJOAYvJDIZBM2PgUpONKwMKPWqg6hQABiDzaMhjCOCr
+Aj1pQIECgYEAl6LvgpYzzyTU8mFaXk5+AuZTpuvVs5sNTE0BgrQbA7HZ/HcOxKid
+bLOSWbW3ZgNZWLW8SauiTD+x/ifTdzQBGBvNhaIjIF6ymtYpO3ZX+60my/XTfbFQ
++uBwP7nqMIRsnB53FW4KuVqic05DlgoEby5c5y9OB9rYD3RrSOMDlas=
+-----END RSA PRIVATE KEY-----
diff --git a/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig b/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig
new file mode 100644
index 00000000000..1f3d617a40d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/external-without-ca.kubeconfig
@@ -0,0 +1,21 @@
+apiVersion: v1
+clusters:
+- cluster:
+ # Not defining custom `certificate-authority`.
+ # Without it, the localhost cert should be rejected.
+ server: https://localhost:6443
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/external.kubeconfig b/vendor/gems/kubeclient/test/config/external.kubeconfig
new file mode 100644
index 00000000000..ef2dca61348
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/external.kubeconfig
@@ -0,0 +1,20 @@
+apiVersion: v1
+clusters:
+- cluster:
+ certificate-authority: external-ca.pem
+ server: https://localhost:6443
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig b/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig
new file mode 100644
index 00000000000..0ee387ebb16
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/gcpauth.kubeconfig
@@ -0,0 +1,21 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:8443
+ name: localhost:8443
+contexts:
+- context:
+ cluster: localhost:8443
+ namespace: default
+ user: application-default-credentials
+ name: localhost/application-default-credentials
+kind: Config
+preferences: {}
+users:
+- name: application-default-credentials
+ user:
+ auth-provider:
+ config:
+ access-token: <fake_token>
+ expiry: 2019-02-19T11:07:29.827352-05:00
+ name: gcp
diff --git a/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig b/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig
new file mode 100644
index 00000000000..2e2db395834
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/gcpcmdauth.kubeconfig
@@ -0,0 +1,25 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:8443
+ name: localhost:8443
+contexts:
+- context:
+ cluster: localhost:8443
+ namespace: default
+ user: application-default-credentials
+ name: localhost/application-default-credentials
+kind: Config
+preferences: {}
+users:
+- name: application-default-credentials
+ user:
+ auth-provider:
+ config:
+ access-token: <fake_token>
+ cmd-args: config config-helper --format=json
+ cmd-path: /path/to/gcloud
+ expiry: 2019-04-09T19:26:18Z
+ expiry-key: '{.credential.token_expiry}'
+ token-key: '{.credential.access_token}'
+ name: gcp
diff --git a/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig b/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig
new file mode 100644
index 00000000000..06c803c16bf
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/insecure-custom-ca.kubeconfig
@@ -0,0 +1,22 @@
+apiVersion: v1
+clusters:
+- cluster:
+ # This is a silly configuration, skip-tls-verify makes CA data useless, but testing for completeness.
+ certificate-authority: external-ca.pem
+ server: https://localhost:6443
+ insecure-skip-tls-verify: true
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/insecure.kubeconfig b/vendor/gems/kubeclient/test/config/insecure.kubeconfig
new file mode 100644
index 00000000000..d7c28087a92
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/insecure.kubeconfig
@@ -0,0 +1,25 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:6443
+ insecure-skip-tls-verify: true
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ # Providing ANY credentials in `insecure-skip-tls-verify` mode is unwise due to MITM risk.
+ # At least client certs are not as catastrophic as bearer tokens.
+ #
+ # This combination of insecure + client certs was once broken in kubernetes but
+ # is meaningful since 2015 (https://github.com/kubernetes/kubernetes/pull/15430).
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/nouser.kubeconfig b/vendor/gems/kubeclient/test/config/nouser.kubeconfig
new file mode 100644
index 00000000000..9289895cc81
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/nouser.kubeconfig
@@ -0,0 +1,15 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:6443
+ name: localhost:6443
+contexts:
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: ""
+ name: default/localhost:6443/nouser
+current-context: default/localhost:6443/nouser
+kind: Config
+preferences: {}
+users: []
diff --git a/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig b/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig
new file mode 100644
index 00000000000..e1f389da46f
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/oidcauth.kubeconfig
@@ -0,0 +1,24 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:8443
+ name: localhost:8443
+contexts:
+- context:
+ cluster: localhost:8443
+ namespace: default
+ user: oidc-auth-provider
+ name: localhost/oidc-auth-provider
+kind: Config
+preferences: {}
+users:
+- name: oidc-auth-provider
+ user:
+ auth-provider:
+ config:
+ client-id: fake-client-id
+ client-secret: fake-client-secret
+ id-token: fake-id-token
+ idp-issuer-url: https://accounts.google.com
+ refresh-token: fake-refresh-token
+ name: oidc
diff --git a/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig b/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig
new file mode 100644
index 00000000000..1b1acefe905
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/secure-without-ca.kubeconfig
@@ -0,0 +1,22 @@
+apiVersion: v1
+clusters:
+- cluster:
+ # Not defining custom `certificate-authority`.
+ # Without it, the localhost cert should be rejected.
+ server: https://localhost:6443
+ insecure-skip-tls-verify: false # Same as external-without-ca.kubeconfig but with explicit false here.
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/secure.kubeconfig b/vendor/gems/kubeclient/test/config/secure.kubeconfig
new file mode 100644
index 00000000000..b0a00bb8d0d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/secure.kubeconfig
@@ -0,0 +1,21 @@
+apiVersion: v1
+clusters:
+- cluster:
+ certificate-authority: external-ca.pem
+ server: https://localhost:6443
+ insecure-skip-tls-verify: false # Same as external.kubeconfig but with explicit false here.
+ name: local
+contexts:
+- context:
+ cluster: local
+ namespace: default
+ user: user
+ name: Default
+current-context: Default
+kind: Config
+preferences: {}
+users:
+- name: user
+ user:
+ client-certificate: external-cert.pem
+ client-key: external-key.rsa
diff --git a/vendor/gems/kubeclient/test/config/timestamps.kubeconfig b/vendor/gems/kubeclient/test/config/timestamps.kubeconfig
new file mode 100644
index 00000000000..7b718da21e9
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/timestamps.kubeconfig
@@ -0,0 +1,25 @@
+apiVersion: v1
+users:
+- name: gke_username
+ user:
+ auth-provider:
+ config:
+ access-token: REDACTED
+ cmd-args: config config-helper --format=json
+ cmd-path: /Users/tannerbruce/opt/google-cloud-sdk/bin/gcloud
+ expiry: 2018-07-07T18:25:36Z
+ expiry-key: '{.credential.token_expiry}'
+ token-key: '{.credential.access_token}'
+ name: gcp
+
+# More syntaxes from go-yaml tests, hopefully covering all types possible in kubeconfig
+IPv4: 1.2.3.4
+Duration: 3s
+date_only: 2015-01-01
+rfc3339: 2015-02-24T18:19:39Z
+longer: 2015-02-24T18:19:39.123456789-03:00
+shorter: 2015-2-3T3:4:5Z
+iso_lower_t: 2015-02-24t18:19:39Z
+space_no_tz: 2015-02-24 18:19:39
+space_tz: 2001-12-14 21:59:43.10 -5
+timestamp_like_string: "2015-02-24T18:19:39Z"
diff --git a/vendor/gems/kubeclient/test/config/update_certs_k0s.rb b/vendor/gems/kubeclient/test/config/update_certs_k0s.rb
new file mode 100755
index 00000000000..2632d72685c
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/update_certs_k0s.rb
@@ -0,0 +1,53 @@
+#!/usr/bin/env ruby
+# https://docs.k0sproject.io/latest/k0s-in-docker/
+# Runs in --prividged mode, only run this if you trust the k0s distribution.
+
+require 'English'
+
+# Like Kernel#system, returns true iff exit status == 0
+def sh?(*cmd)
+ puts("+ #{cmd.join(' ')}")
+ system(*cmd)
+end
+
+# Raises if exit status != 0
+def sh!(*cmd)
+ sh?(*cmd) || raise("returned #{$CHILD_STATUS}")
+end
+
+# allow DOCKER='sudo docker', DOCKER=podman etc.
+DOCKER = ENV['DOCKER'] || 'docker'
+
+CONTAINER = 'k0s'.freeze
+
+sh! "#{DOCKER} container inspect #{CONTAINER} --format='exists' ||
+ #{DOCKER} run -d --name #{CONTAINER} --hostname k0s --privileged -v /var/lib/k0s -p 6443:6443 \
+ ghcr.io/k0sproject/k0s/k0s:v1.23.3-k0s.1"
+
+# sh! "#{DOCKER} exec #{CONTAINER} kubectl config view --raw"
+# is another way to dump kubeconfig but succeeds with dummy output even before admin.conf exists;
+# so accessing the file is better way as it lets us poll until ready:
+sleep(1) until sh?("#{DOCKER} exec #{CONTAINER} ls -l /var/lib/k0s/pki/admin.conf")
+
+sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.conf > test/config/allinone.kubeconfig"
+# The rest could easily be extracted from allinone.kubeconfig, but the test is more robust
+# if we don't reuse YAML and/or Kubeclient::Config parsing to construct test data.
+sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/ca.crt > test/config/external-ca.pem"
+sh! 'cat test/config/another-ca1.pem test/config/external-ca.pem '\
+ ' test/config/another-ca2.pem > test/config/concatenated-ca.pem'
+sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.crt > test/config/external-cert.pem"
+sh! "#{DOCKER} exec #{CONTAINER} cat /var/lib/k0s/pki/admin.key > test/config/external-key.rsa"
+
+# Wait for apiserver to be up. To speed startup, this only retries connection errors;
+# without `--fail-with-body` curl still returns 0 for well-formed 4xx or 5xx responses.
+sleep(1) until sh?(
+ 'curl --cacert test/config/external-ca.pem ' \
+ '--key test/config/external-key.rsa ' \
+ '--cert test/config/external-cert.pem https://127.0.0.1:6443/healthz'
+)
+
+sh! 'env KUBECLIENT_TEST_REAL_CLUSTER=true bundle exec rake test'
+
+sh! "#{DOCKER} rm -f #{CONTAINER}"
+
+puts 'If you run this only for tests, cleanup by running: git restore test/config/'
diff --git a/vendor/gems/kubeclient/test/config/userauth.kubeconfig b/vendor/gems/kubeclient/test/config/userauth.kubeconfig
new file mode 100644
index 00000000000..604e3bda920
--- /dev/null
+++ b/vendor/gems/kubeclient/test/config/userauth.kubeconfig
@@ -0,0 +1,27 @@
+apiVersion: v1
+clusters:
+- cluster:
+ server: https://localhost:6443
+ name: localhost:6443
+contexts:
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: system:admin:token
+ name: localhost/system:admin:token
+- context:
+ cluster: localhost:6443
+ namespace: default
+ user: system:admin:userpass
+ name: localhost/system:admin:userpass
+current-context: localhost/system:admin:token
+kind: Config
+preferences: {}
+users:
+- name: system:admin:token
+ user:
+ token: 0123456789ABCDEF0123456789ABCDEF
+- name: system:admin:userpass
+ user:
+ username: admin
+ password: pAssw0rd123
diff --git a/vendor/gems/kubeclient/test/json/bindings_list.json b/vendor/gems/kubeclient/test/json/bindings_list.json
new file mode 100644
index 00000000000..260748c3aa4
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/bindings_list.json
@@ -0,0 +1,10 @@
+{
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "the server could not find the requested resource",
+ "reason": "NotFound",
+ "details": {},
+ "code": 404
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/component_status.json b/vendor/gems/kubeclient/test/json/component_status.json
new file mode 100644
index 00000000000..109936d3dac
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/component_status.json
@@ -0,0 +1,17 @@
+{
+ "kind": "ComponentStatus",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "etcd-0",
+ "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0",
+ "creationTimestamp": null
+ },
+ "conditions": [
+ {
+ "type": "Healthy",
+ "status": "True",
+ "message": "{\"health\": \"true\"}",
+ "error": "nil"
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/component_status_list.json b/vendor/gems/kubeclient/test/json/component_status_list.json
new file mode 100644
index 00000000000..1849f489eb2
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/component_status_list.json
@@ -0,0 +1,52 @@
+{
+ "kind": "ComponentStatusList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/componentstatuses"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "controller-manager",
+ "selfLink": "/api/v1/namespaces/componentstatuses/controller-manager",
+ "creationTimestamp": null
+ },
+ "conditions": [
+ {
+ "type": "Healthy",
+ "status": "Unknown",
+ "error": "Get http://127.0.0.1:10252/healthz: dial tcp 127.0.0.1:10252: connection refused"
+ }
+ ]
+ },
+ {
+ "metadata": {
+ "name": "scheduler",
+ "selfLink": "/api/v1/namespaces/componentstatuses/scheduler",
+ "creationTimestamp": null
+ },
+ "conditions": [
+ {
+ "type": "Healthy",
+ "status": "Unknown",
+ "error": "Get http://127.0.0.1:10251/healthz: dial tcp 127.0.0.1:10251: connection refused"
+ }
+ ]
+ },
+ {
+ "metadata": {
+ "name": "etcd-0",
+ "selfLink": "/api/v1/namespaces/componentstatuses/etcd-0",
+ "creationTimestamp": null
+ },
+ "conditions": [
+ {
+ "type": "Healthy",
+ "status": "True",
+ "message": "{\"health\": \"true\"}",
+ "error": "nil"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json
new file mode 100644
index 00000000000..5317e865b63
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/config.istio.io_api_resource_list.json
@@ -0,0 +1,679 @@
+{
+ "kind": "APIResourceList",
+ "apiVersion": "v1",
+ "groupVersion": "config.istio.io/v1alpha2",
+ "resources": [
+ {
+ "name": "metrics",
+ "singularName": "metric",
+ "namespaced": true,
+ "kind": "metric",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "servicecontrolreports",
+ "singularName": "servicecontrolreport",
+ "namespaced": true,
+ "kind": "servicecontrolreport",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "opas",
+ "singularName": "opa",
+ "namespaced": true,
+ "kind": "opa",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "redisquotas",
+ "singularName": "redisquota",
+ "namespaced": true,
+ "kind": "redisquota",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "authorizations",
+ "singularName": "authorization",
+ "namespaced": true,
+ "kind": "authorization",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "listentries",
+ "singularName": "listentry",
+ "namespaced": true,
+ "kind": "listentry",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "logentries",
+ "singularName": "logentry",
+ "namespaced": true,
+ "kind": "logentry",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "tracespans",
+ "singularName": "tracespan",
+ "namespaced": true,
+ "kind": "tracespan",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "quotaspecs",
+ "singularName": "quotaspec",
+ "namespaced": true,
+ "kind": "QuotaSpec",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "fluentds",
+ "singularName": "fluentd",
+ "namespaced": true,
+ "kind": "fluentd",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "rbacs",
+ "singularName": "rbac",
+ "namespaced": true,
+ "kind": "rbac",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "checknothings",
+ "singularName": "checknothing",
+ "namespaced": true,
+ "kind": "checknothing",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "edges",
+ "singularName": "edge",
+ "namespaced": true,
+ "kind": "edge",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "apikeys",
+ "singularName": "apikey",
+ "namespaced": true,
+ "kind": "apikey",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "kuberneteses",
+ "singularName": "kubernetes",
+ "namespaced": true,
+ "kind": "kubernetes",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "httpapispecs",
+ "singularName": "httpapispec",
+ "namespaced": true,
+ "kind": "HTTPAPISpec",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "attributemanifests",
+ "singularName": "attributemanifest",
+ "namespaced": true,
+ "kind": "attributemanifest",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "kubernetesenvs",
+ "singularName": "kubernetesenv",
+ "namespaced": true,
+ "kind": "kubernetesenv",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "listcheckers",
+ "singularName": "listchecker",
+ "namespaced": true,
+ "kind": "listchecker",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "quotas",
+ "singularName": "quota",
+ "namespaced": true,
+ "kind": "quota",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "instances",
+ "singularName": "instance",
+ "namespaced": true,
+ "kind": "instance",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "memquotas",
+ "singularName": "memquota",
+ "namespaced": true,
+ "kind": "memquota",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "noops",
+ "singularName": "noop",
+ "namespaced": true,
+ "kind": "noop",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "prometheuses",
+ "singularName": "prometheus",
+ "namespaced": true,
+ "kind": "prometheus",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "solarwindses",
+ "singularName": "solarwinds",
+ "namespaced": true,
+ "kind": "solarwinds",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "cloudwatches",
+ "singularName": "cloudwatch",
+ "namespaced": true,
+ "kind": "cloudwatch",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "reportnothings",
+ "singularName": "reportnothing",
+ "namespaced": true,
+ "kind": "reportnothing",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "stackdrivers",
+ "singularName": "stackdriver",
+ "namespaced": true,
+ "kind": "stackdriver",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "statsds",
+ "singularName": "statsd",
+ "namespaced": true,
+ "kind": "statsd",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "httpapispecbindings",
+ "singularName": "httpapispecbinding",
+ "namespaced": true,
+ "kind": "HTTPAPISpecBinding",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "quotaspecbindings",
+ "singularName": "quotaspecbinding",
+ "namespaced": true,
+ "kind": "QuotaSpecBinding",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "bypasses",
+ "singularName": "bypass",
+ "namespaced": true,
+ "kind": "bypass",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "circonuses",
+ "singularName": "circonus",
+ "namespaced": true,
+ "kind": "circonus",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "deniers",
+ "singularName": "denier",
+ "namespaced": true,
+ "kind": "denier",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "signalfxs",
+ "singularName": "signalfx",
+ "namespaced": true,
+ "kind": "signalfx",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "adapters",
+ "singularName": "adapter",
+ "namespaced": true,
+ "kind": "adapter",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "servicecontrols",
+ "singularName": "servicecontrol",
+ "namespaced": true,
+ "kind": "servicecontrol",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "templates",
+ "singularName": "template",
+ "namespaced": true,
+ "kind": "template",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "handlers",
+ "singularName": "handler",
+ "namespaced": true,
+ "kind": "handler",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "rules",
+ "singularName": "rule",
+ "namespaced": true,
+ "kind": "rule",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "dogstatsds",
+ "singularName": "dogstatsd",
+ "namespaced": true,
+ "kind": "dogstatsd",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "stdios",
+ "singularName": "stdio",
+ "namespaced": true,
+ "kind": "stdio",
+ "verbs": [
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "create",
+ "update",
+ "watch"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/config_map_list.json b/vendor/gems/kubeclient/test/json/config_map_list.json
new file mode 100644
index 00000000000..85e0e30d7fe
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/config_map_list.json
@@ -0,0 +1,9 @@
+{
+ "kind": "ConfigMapList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/configmaps",
+ "resourceVersion": "665"
+ },
+ "items": []
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/core_api_resource_list.json b/vendor/gems/kubeclient/test/json/core_api_resource_list.json
new file mode 100644
index 00000000000..395acb249df
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/core_api_resource_list.json
@@ -0,0 +1,181 @@
+{
+ "kind": "APIResourceList",
+ "groupVersion": "v1",
+ "resources": [
+ {
+ "name": "bindings",
+ "namespaced": true,
+ "kind": "Binding"
+ },
+ {
+ "name": "componentstatuses",
+ "namespaced": false,
+ "kind": "ComponentStatus"
+ },
+ {
+ "name": "configmaps",
+ "namespaced": true,
+ "kind": "ConfigMap"
+ },
+ {
+ "name": "endpoints",
+ "namespaced": true,
+ "kind": "Endpoints"
+ },
+ {
+ "name": "events",
+ "namespaced": true,
+ "kind": "Event"
+ },
+ {
+ "name": "limitranges",
+ "namespaced": true,
+ "kind": "LimitRange"
+ },
+ {
+ "name": "namespaces",
+ "namespaced": false,
+ "kind": "Namespace"
+ },
+ {
+ "name": "namespaces/finalize",
+ "namespaced": false,
+ "kind": "Namespace"
+ },
+ {
+ "name": "namespaces/status",
+ "namespaced": false,
+ "kind": "Namespace"
+ },
+ {
+ "name": "nodes",
+ "namespaced": false,
+ "kind": "Node"
+ },
+ {
+ "name": "nodes/proxy",
+ "namespaced": false,
+ "kind": "Node"
+ },
+ {
+ "name": "nodes/status",
+ "namespaced": false,
+ "kind": "Node"
+ },
+ {
+ "name": "persistentvolumeclaims",
+ "namespaced": true,
+ "kind": "PersistentVolumeClaim"
+ },
+ {
+ "name": "persistentvolumeclaims/status",
+ "namespaced": true,
+ "kind": "PersistentVolumeClaim"
+ },
+ {
+ "name": "persistentvolumes",
+ "namespaced": false,
+ "kind": "PersistentVolume"
+ },
+ {
+ "name": "persistentvolumes/status",
+ "namespaced": false,
+ "kind": "PersistentVolume"
+ },
+ {
+ "name": "pods",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/attach",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/binding",
+ "namespaced": true,
+ "kind": "Binding"
+ },
+ {
+ "name": "pods/exec",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/log",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/portforward",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/proxy",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "pods/status",
+ "namespaced": true,
+ "kind": "Pod"
+ },
+ {
+ "name": "podtemplates",
+ "namespaced": true,
+ "kind": "PodTemplate"
+ },
+ {
+ "name": "replicationcontrollers",
+ "namespaced": true,
+ "kind": "ReplicationController"
+ },
+ {
+ "name": "replicationcontrollers/scale",
+ "namespaced": true,
+ "kind": "Scale"
+ },
+ {
+ "name": "replicationcontrollers/status",
+ "namespaced": true,
+ "kind": "ReplicationController"
+ },
+ {
+ "name": "resourcequotas",
+ "namespaced": true,
+ "kind": "ResourceQuota"
+ },
+ {
+ "name": "resourcequotas/status",
+ "namespaced": true,
+ "kind": "ResourceQuota"
+ },
+ {
+ "name": "secrets",
+ "namespaced": true,
+ "kind": "Secret"
+ },
+ {
+ "name": "serviceaccounts",
+ "namespaced": true,
+ "kind": "ServiceAccount"
+ },
+ {
+ "name": "services",
+ "namespaced": true,
+ "kind": "Service"
+ },
+ {
+ "name": "services/proxy",
+ "namespaced": true,
+ "kind": "Service"
+ },
+ {
+ "name": "services/status",
+ "namespaced": true,
+ "kind": "Service"
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json b/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json
new file mode 100644
index 00000000000..f60e113d6e5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/core_api_resource_list_without_kind.json
@@ -0,0 +1,129 @@
+{
+ "groupVersion": "v1",
+ "resources": [
+ {
+ "name": "bindings",
+ "namespaced": true
+ },
+ {
+ "name": "componentstatuses",
+ "namespaced": true
+ },
+ {
+ "name": "endpoints",
+ "namespaced": true
+ },
+ {
+ "name": "events",
+ "namespaced": true
+ },
+ {
+ "name": "limitranges",
+ "namespaced": true
+ },
+ {
+ "name": "namespaces",
+ "namespaced": false
+ },
+ {
+ "name": "namespaces/finalize",
+ "namespaced": false
+ },
+ {
+ "name": "namespaces/status",
+ "namespaced": false
+ },
+ {
+ "name": "nodes",
+ "namespaced": false
+ },
+ {
+ "name": "nodes/status",
+ "namespaced": false
+ },
+ {
+ "name": "persistentvolumeclaims",
+ "namespaced": true
+ },
+ {
+ "name": "persistentvolumeclaims/status",
+ "namespaced": true
+ },
+ {
+ "name": "persistentvolumes",
+ "namespaced": false
+ },
+ {
+ "name": "persistentvolumes/status",
+ "namespaced": false
+ },
+ {
+ "name": "pods",
+ "namespaced": true
+ },
+ {
+ "name": "pods/attach",
+ "namespaced": true
+ },
+ {
+ "name": "pods/binding",
+ "namespaced": true
+ },
+ {
+ "name": "pods/exec",
+ "namespaced": true
+ },
+ {
+ "name": "pods/log",
+ "namespaced": true
+ },
+ {
+ "name": "pods/portforward",
+ "namespaced": true
+ },
+ {
+ "name": "pods/proxy",
+ "namespaced": true
+ },
+ {
+ "name": "pods/status",
+ "namespaced": true
+ },
+ {
+ "name": "podtemplates",
+ "namespaced": true
+ },
+ {
+ "name": "replicationcontrollers",
+ "namespaced": true
+ },
+ {
+ "name": "replicationcontrollers/status",
+ "namespaced": true
+ },
+ {
+ "name": "resourcequotas",
+ "namespaced": true
+ },
+ {
+ "name": "resourcequotas/status",
+ "namespaced": true
+ },
+ {
+ "name": "secrets",
+ "namespaced": true
+ },
+ {
+ "name": "securitycontextconstraints",
+ "namespaced": false
+ },
+ {
+ "name": "serviceaccounts",
+ "namespaced": true
+ },
+ {
+ "name": "services",
+ "namespaced": true
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json b/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json
new file mode 100644
index 00000000000..a902a6a7fd1
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/core_oapi_resource_list_without_kind.json
@@ -0,0 +1,197 @@
+{
+ "groupVersion": "v1",
+ "resources": [
+ {
+ "name": "buildconfigs",
+ "namespaced": true
+ },
+ {
+ "name": "buildconfigs/instantiate",
+ "namespaced": true
+ },
+ {
+ "name": "buildconfigs/instantiatebinary",
+ "namespaced": true
+ },
+ {
+ "name": "buildconfigs/webhooks",
+ "namespaced": true
+ },
+ {
+ "name": "builds",
+ "namespaced": true
+ },
+ {
+ "name": "builds/clone",
+ "namespaced": true
+ },
+ {
+ "name": "builds/details",
+ "namespaced": true
+ },
+ {
+ "name": "builds/log",
+ "namespaced": true
+ },
+ {
+ "name": "clusternetworks",
+ "namespaced": false
+ },
+ {
+ "name": "clusterpolicies",
+ "namespaced": false
+ },
+ {
+ "name": "clusterpolicybindings",
+ "namespaced": false
+ },
+ {
+ "name": "clusterrolebindings",
+ "namespaced": false
+ },
+ {
+ "name": "clusterroles",
+ "namespaced": false
+ },
+ {
+ "name": "deploymentconfigrollbacks",
+ "namespaced": true
+ },
+ {
+ "name": "deploymentconfigs",
+ "namespaced": true
+ },
+ {
+ "name": "deploymentconfigs/log",
+ "namespaced": true
+ },
+ {
+ "name": "deploymentconfigs/scale",
+ "namespaced": true
+ },
+ {
+ "name": "generatedeploymentconfigs",
+ "namespaced": true
+ },
+ {
+ "name": "groups",
+ "namespaced": false
+ },
+ {
+ "name": "hostsubnets",
+ "namespaced": false
+ },
+ {
+ "name": "identities",
+ "namespaced": false
+ },
+ {
+ "name": "images",
+ "namespaced": false
+ },
+ {
+ "name": "imagestreamimages",
+ "namespaced": true
+ },
+ {
+ "name": "imagestreammappings",
+ "namespaced": true
+ },
+ {
+ "name": "imagestreams",
+ "namespaced": true
+ },
+ {
+ "name": "imagestreams/status",
+ "namespaced": true
+ },
+ {
+ "name": "imagestreamtags",
+ "namespaced": true
+ },
+ {
+ "name": "localresourceaccessreviews",
+ "namespaced": true
+ },
+ {
+ "name": "localsubjectaccessreviews",
+ "namespaced": true
+ },
+ {
+ "name": "netnamespaces",
+ "namespaced": false
+ },
+ {
+ "name": "oauthaccesstokens",
+ "namespaced": false
+ },
+ {
+ "name": "oauthauthorizetokens",
+ "namespaced": false
+ },
+ {
+ "name": "oauthclientauthorizations",
+ "namespaced": false
+ },
+ {
+ "name": "oauthclients",
+ "namespaced": false
+ },
+ {
+ "name": "policies",
+ "namespaced": true
+ },
+ {
+ "name": "policybindings",
+ "namespaced": true
+ },
+ {
+ "name": "processedtemplates",
+ "namespaced": true
+ },
+ {
+ "name": "projectrequests",
+ "namespaced": false
+ },
+ {
+ "name": "projects",
+ "namespaced": false
+ },
+ {
+ "name": "resourceaccessreviews",
+ "namespaced": true
+ },
+ {
+ "name": "rolebindings",
+ "namespaced": true
+ },
+ {
+ "name": "roles",
+ "namespaced": true
+ },
+ {
+ "name": "routes",
+ "namespaced": true
+ },
+ {
+ "name": "routes/status",
+ "namespaced": true
+ },
+ {
+ "name": "subjectaccessreviews",
+ "namespaced": true
+ },
+ {
+ "name": "templates",
+ "namespaced": true
+ },
+ {
+ "name": "useridentitymappings",
+ "namespaced": false
+ },
+ {
+ "name": "users",
+ "namespaced": false
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/created_endpoint.json b/vendor/gems/kubeclient/test/json/created_endpoint.json
new file mode 100644
index 00000000000..1e0fd7dc41d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/created_endpoint.json
@@ -0,0 +1,28 @@
+{
+ "kind": "Endpoints",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "myendpoint",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/endpoints/myendpoint",
+ "uid": "59d05b48-dadb-11e5-937e-18037327aaeb",
+ "resourceVersion": "393",
+ "creationTimestamp": "2016-02-24T09:45:34Z"
+ },
+ "subsets": [
+ {
+ "addresses": [
+ {
+ "ip": "172.17.0.25"
+ }
+ ],
+ "ports": [
+ {
+ "name": "https",
+ "port": 6443,
+ "protocol": "TCP"
+ }
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/created_namespace.json b/vendor/gems/kubeclient/test/json/created_namespace.json
new file mode 100644
index 00000000000..218bc000aa8
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/created_namespace.json
@@ -0,0 +1,20 @@
+{
+"kind": "Namespace",
+"apiVersion": "v1",
+"metadata": {
+"name": "development",
+"selfLink": "/api/v1/namespaces/development",
+"uid": "13d820d6-df5b-11e4-bd42-f8b156af4ae1",
+"resourceVersion": "2533",
+"creationTimestamp": "2015-04-10T08:24:59Z"
+},
+"spec": {
+"finalizers": [
+"kubernetes"
+]
+},
+"status": {
+"phase": "Active"
+}
+}
+
diff --git a/vendor/gems/kubeclient/test/json/created_secret.json b/vendor/gems/kubeclient/test/json/created_secret.json
new file mode 100644
index 00000000000..bcea8848335
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/created_secret.json
@@ -0,0 +1,16 @@
+{
+ "kind": "Secret",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "test-secret",
+ "namespace": "dev",
+ "selfLink": "/api/v1/namespaces/dev/secrets/test-secret",
+ "uid": "4e38a198-2bcb-11e5-a483-0e840567604d",
+ "resourceVersion": "245569",
+ "creationTimestamp": "2015-07-16T14:59:49Z"
+ },
+ "data": {
+ "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK"
+ },
+ "type": "Opaque"
+}
diff --git a/vendor/gems/kubeclient/test/json/created_security_context_constraint.json b/vendor/gems/kubeclient/test/json/created_security_context_constraint.json
new file mode 100644
index 00000000000..c2981712cb5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/created_security_context_constraint.json
@@ -0,0 +1,65 @@
+{
+ "allowHostDirVolumePlugin": false,
+ "allowHostIPC": false,
+ "allowHostNetwork": false,
+ "allowHostPID": false,
+ "allowHostPorts": false,
+ "allowPrivilegedContainer": false,
+ "allowedCapabilities": null,
+ "allowedFlexVolumes": null,
+ "apiVersion": "security.openshift.io/v1",
+ "defaultAddCapabilities": null,
+ "fsGroup": {
+ "type": "RunAsAny"
+ },
+ "groups": [],
+ "kind": "SecurityContextConstraints",
+ "metadata": {
+ "creationTimestamp": "2018-11-23T10:01:42Z",
+ "name": "teleportation",
+ "resourceVersion": "5274",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/teleportation",
+ "uid": "c6e8e2ec-ef06-11e8-b4c0-68f728fac3ab"
+ },
+ "priority": null,
+ "readOnlyRootFilesystem": false,
+ "requiredDropCapabilities": null,
+ "runAsUser": {
+ "type": "MustRunAs"
+ },
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "users": [],
+ "volumes": [
+ "awsElasticBlockStore",
+ "azureDisk",
+ "azureFile",
+ "cephFS",
+ "cinder",
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "fc",
+ "flexVolume",
+ "flocker",
+ "gcePersistentDisk",
+ "gitRepo",
+ "glusterfs",
+ "iscsi",
+ "nfs",
+ "persistentVolumeClaim",
+ "photonPersistentDisk",
+ "portworxVolume",
+ "projected",
+ "quobyte",
+ "rbd",
+ "scaleIO",
+ "secret",
+ "storageOS",
+ "vsphere"
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/created_service.json b/vendor/gems/kubeclient/test/json/created_service.json
new file mode 100644
index 00000000000..4c2bc7d7196
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/created_service.json
@@ -0,0 +1,31 @@
+{
+ "kind": "Service",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "guestbook",
+ "namespace": "staging",
+ "selfLink": "/api/v1/namespaces/staging/services/guestbook",
+ "uid": "29885239-df58-11e4-bd42-f8b156af4ae1",
+ "resourceVersion": "1908",
+ "creationTimestamp": "2015-04-10T08:04:07Z",
+ "labels": {
+ "name": "guestbook"
+ }
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "",
+ "protocol": "TCP",
+ "port": 3000,
+ "targetPort": "http-server"
+ }
+ ],
+ "selector": {
+ "name": "guestbook"
+ },
+ "clusterIP": "10.0.0.99",
+ "sessionAffinity": "None"
+ },
+ "status": {}
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/empty_pod_list.json b/vendor/gems/kubeclient/test/json/empty_pod_list.json
new file mode 100644
index 00000000000..a82cba1148f
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/empty_pod_list.json
@@ -0,0 +1,9 @@
+{
+ "kind": "PodList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/pods",
+ "resourceVersion": "565"
+ },
+ "items": []
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/endpoint_list.json b/vendor/gems/kubeclient/test/json/endpoint_list.json
new file mode 100644
index 00000000000..bd6c00ab678
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/endpoint_list.json
@@ -0,0 +1,48 @@
+{
+ "kind": "EndpointsList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/namespaces/endpoints",
+ "resourceVersion": "39"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "example",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/endpoints/example",
+ "uid": "db467530-b6aa-11e4-974a-525400c903c1",
+ "resourceVersion": "38",
+ "creationTimestamp": "2015-02-17T08:42:46-05:00"
+ },
+ "endpoints": [
+ "172.17.0.63:80",
+ "172.17.0.64:80"
+ ]
+ },
+ {
+ "metadata": {
+ "name": "kubernetes",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes",
+ "resourceVersion": "8",
+ "creationTimestamp": null
+ },
+ "endpoints": [
+ "192.168.122.4:6443"
+ ]
+ },
+ {
+ "metadata": {
+ "name": "kubernetes-ro",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/endpoints/kubernetes-ro",
+ "resourceVersion": "7",
+ "creationTimestamp": null
+ },
+ "endpoints": [
+ "192.168.122.4:7080"
+ ]
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/entity_list.json b/vendor/gems/kubeclient/test/json/entity_list.json
new file mode 100644
index 00000000000..3dd140d38c8
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/entity_list.json
@@ -0,0 +1,56 @@
+{
+ "kind": "ServiceList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/services",
+ "resourceVersion": "59"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "kubernetes",
+ "namespace": "default",
+ "selfLink": "/api/v1/services/kubernetes?namespace=default",
+ "uid": "016e9dcd-ce39-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "6",
+ "creationTimestamp": "2015-03-19T15:08:16+02:00",
+ "labels": {
+ "component": "apiserver",
+ "provider": "kubernetes"
+ }
+ },
+ "spec": {
+ "port": 443,
+ "protocol": "TCP",
+ "selector": null,
+ "clusterIP": "10.0.0.2",
+ "containerPort": 0,
+ "sessionAffinity": "None"
+ },
+ "status": {}
+ },
+ {
+ "metadata": {
+ "name": "kubernetes-ro",
+ "namespace": "default",
+ "selfLink": "/api/v1/services/kubernetes-ro?namespace=default",
+ "uid": "015b78bf-ce39-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "5",
+ "creationTimestamp": "2015-03-19T15:08:15+02:00",
+ "labels": {
+ "component": "apiserver",
+ "provider": "kubernetes"
+ }
+ },
+ "spec": {
+ "port": 80,
+ "protocol": "TCP",
+ "selector": null,
+ "clusterIP": "10.0.0.1",
+ "containerPort": 0,
+ "sessionAffinity": "None"
+ },
+ "status": {}
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/event_list.json b/vendor/gems/kubeclient/test/json/event_list.json
new file mode 100644
index 00000000000..45abfccc278
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/event_list.json
@@ -0,0 +1,35 @@
+{
+ "kind": "EventList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/events",
+ "resourceVersion": "152"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "php.13c130f78da4641e",
+ "namespace": "default",
+ "selfLink": "/api/v1/events/php.13c130f78da4641e?namespace=default",
+ "uid": "f3a454d2-b03a-11e4-89e4-525400c903c1",
+ "resourceVersion": "178",
+ "creationTimestamp": "2015-02-09T04:06:37-05:00"
+ },
+ "involvedObject": {
+ "kind": "BoundPod",
+ "namespace": "default",
+ "name": "php",
+ "uid": "64273d20-b03a-11e4-89e4-525400c903c1",
+ "apiVersion": "v1beta1",
+ "fieldPath": "spec.containers{nginx}"
+ },
+ "reason": "created",
+ "message": "Created with docker id 9ba2a714411d2d0dd1e826b2fe5c3222b5cbfd9dd9133c841585cbb96b8c2c0f",
+ "source": {
+ "component": "kubelet",
+ "host": "127.0.0.1"
+ },
+ "timestamp": "2015-02-09T04:06:37-05:00"
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json b/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json
new file mode 100644
index 00000000000..16fc80cf4d7
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/extensions_v1beta1_api_resource_list.json
@@ -0,0 +1,217 @@
+{
+ "kind": "APIResourceList",
+ "groupVersion": "extensions/v1beta1",
+ "resources": [
+ {
+ "name": "daemonsets",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "DaemonSet",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "ds"
+ ]
+ },
+ {
+ "name": "daemonsets/status",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "DaemonSet",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "deployments",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Deployment",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "deploy"
+ ]
+ },
+ {
+ "name": "deployments/rollback",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "DeploymentRollback",
+ "verbs": [
+ "create"
+ ]
+ },
+ {
+ "name": "deployments/scale",
+ "singularName": "",
+ "namespaced": true,
+ "group": "extensions",
+ "version": "v1beta1",
+ "kind": "Scale",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "deployments/status",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Deployment",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "ingresses",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Ingress",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "ing"
+ ]
+ },
+ {
+ "name": "ingresses/status",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Ingress",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "networkpolicies",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "NetworkPolicy",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "netpol"
+ ]
+ },
+ {
+ "name": "podsecuritypolicies",
+ "singularName": "",
+ "namespaced": false,
+ "kind": "PodSecurityPolicy",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "psp"
+ ]
+ },
+ {
+ "name": "replicasets",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "ReplicaSet",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "rs"
+ ]
+ },
+ {
+ "name": "replicasets/scale",
+ "singularName": "",
+ "namespaced": true,
+ "group": "extensions",
+ "version": "v1beta1",
+ "kind": "Scale",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "replicasets/status",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "ReplicaSet",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "replicationcontrollers",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "ReplicationControllerDummy",
+ "verbs": []
+ },
+ {
+ "name": "replicationcontrollers/scale",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Scale",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/limit_range.json b/vendor/gems/kubeclient/test/json/limit_range.json
new file mode 100644
index 00000000000..ac2e21aa744
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/limit_range.json
@@ -0,0 +1,23 @@
+{
+ "kind": "LimitRange",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "limits",
+ "namespace": "quota-example",
+ "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits",
+ "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e",
+ "resourceVersion": "103384",
+ "creationTimestamp": "2015-08-09T13:49:39Z"
+ },
+ "spec": {
+ "limits": [
+ {
+ "type": "Container",
+ "default": {
+ "cpu": "100m",
+ "memory": "512Mi"
+ }
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/limit_range_list.json b/vendor/gems/kubeclient/test/json/limit_range_list.json
new file mode 100644
index 00000000000..7986ec861d8
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/limit_range_list.json
@@ -0,0 +1,31 @@
+{
+ "kind": "LimitRangeList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/namespaces/quota-example/limitranges/",
+ "resourceVersion": "103421"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "limits",
+ "namespace": "quota-example",
+ "selfLink": "/api/v1/namespaces/quota-example/limitranges/limits",
+ "uid": "7a76a44c-3e9d-11e5-8214-0aaeec44370e",
+ "resourceVersion": "103384",
+ "creationTimestamp": "2015-08-09T13:49:39Z"
+ },
+ "spec": {
+ "limits": [
+ {
+ "type": "Container",
+ "default": {
+ "cpu": "100m",
+ "memory": "512Mi"
+ }
+ }
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace.json b/vendor/gems/kubeclient/test/json/namespace.json
new file mode 100644
index 00000000000..5a856730188
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/namespace.json
@@ -0,0 +1,13 @@
+{
+ "kind": "Namespace",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "staging",
+ "selfLink": "/api/v1/namespaces/staging",
+ "uid": "e388bc10-c021-11e4-a514-3c970e4a436a",
+ "resourceVersion": "1168",
+ "creationTimestamp": "2015-03-01T16:47:31+02:00"
+ },
+ "spec": {},
+ "status": {}
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace_exception.json b/vendor/gems/kubeclient/test/json/namespace_exception.json
new file mode 100644
index 00000000000..555ef24cabb
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/namespace_exception.json
@@ -0,0 +1,8 @@
+{
+ "kind": "Status",
+ "apiVersion": "v1",
+ "metadata": {},
+ "status": "Failure",
+ "message": "converting to : type names don't match (Pod, Namespace)",
+ "code": 500
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/namespace_list.json b/vendor/gems/kubeclient/test/json/namespace_list.json
new file mode 100644
index 00000000000..af6feb7485c
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/namespace_list.json
@@ -0,0 +1,32 @@
+{
+ "kind": "NamespaceList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/namespaces",
+ "resourceVersion": "1707"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "default",
+ "selfLink": "/api/v1/namespaces/default",
+ "uid": "56c3eb7c-c009-11e4-a514-3c970e4a436a",
+ "resourceVersion": "4",
+ "creationTimestamp": "2015-03-01T13:51:47+02:00"
+ },
+ "spec": {},
+ "status": {}
+ },
+ {
+ "metadata": {
+ "name": "staging",
+ "selfLink": "/api/v1/namespaces/staging",
+ "uid": "e388bc10-c021-11e4-a514-3c970e4a436a",
+ "resourceVersion": "1168",
+ "creationTimestamp": "2015-03-01T16:47:31+02:00"
+ },
+ "spec": {},
+ "status": {}
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node.json b/vendor/gems/kubeclient/test/json/node.json
new file mode 100644
index 00000000000..bb4772c3f20
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/node.json
@@ -0,0 +1,29 @@
+{
+ "kind": "Node",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "127.0.0.1",
+ "selfLink": "/api/v1/nodes/127.0.0.1",
+ "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "1724",
+ "creationTimestamp": "2015-03-19T15:08:20+02:00"
+ },
+ "spec": {
+ "capacity": {
+ "cpu": "1",
+ "memory": "3Gi"
+ }
+ },
+ "status": {
+ "hostIP": "127.0.0.1",
+ "conditions": [
+ {
+ "kind": "Ready",
+ "status": "None",
+ "lastProbeTime": "2015-03-20T14:16:52+02:00",
+ "lastTransitionTime": "2015-03-19T15:08:20+02:00",
+ "reason": "Node health check failed: kubelet /healthz endpoint returns not ok"
+ }
+ ]
+ }
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node_list.json b/vendor/gems/kubeclient/test/json/node_list.json
new file mode 100644
index 00000000000..a5c7cbb77a3
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/node_list.json
@@ -0,0 +1,37 @@
+{
+ "kind": "NodeList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/nodes",
+ "resourceVersion": "137"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "127.0.0.1",
+ "selfLink": "/api/v1/nodes/127.0.0.1",
+ "uid": "041143c5-ce39-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "137",
+ "creationTimestamp": "2015-03-19T15:08:20+02:00"
+ },
+ "spec": {
+ "capacity": {
+ "cpu": "1",
+ "memory": "3Gi"
+ }
+ },
+ "status": {
+ "hostIP": "127.0.0.1",
+ "conditions": [
+ {
+ "kind": "Ready",
+ "status": "None",
+ "lastProbeTime": "2015-03-19T15:29:33+02:00",
+ "lastTransitionTime": "2015-03-19T15:08:20+02:00",
+ "reason": "Node health check failed: kubelet /healthz endpoint returns not ok"
+ }
+ ]
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/node_notice.json b/vendor/gems/kubeclient/test/json/node_notice.json
new file mode 100644
index 00000000000..69ee438ecc2
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/node_notice.json
@@ -0,0 +1,160 @@
+{
+ "type": "ADDED",
+ "object": {
+ "apiVersion": "v1",
+ "kind": "Node",
+ "metadata": {
+ "annotations": {
+ "volumes.kubernetes.io/controller-managed-attach-detach": "true"
+ },
+ "creationTimestamp": "2017-12-11T12:00:13Z",
+ "labels": {
+ "beta.kubernetes.io/arch": "amd64",
+ "beta.kubernetes.io/os": "linux",
+ "kubernetes.io/hostname": "openshift.local",
+ "openshift-infra": "apiserver"
+ },
+ "name": "openshift.local",
+ "resourceVersion": "367410",
+ "selfLink": "/api/v1/nodes/openshift.local",
+ "uid": "d88c7af6-de6a-11e7-8725-52540080f1d2"
+ },
+ "spec": {
+ "externalID": "openshift.local"
+ },
+ "status": {
+ "addresses": [
+ {
+ "address": "192.168.122.40",
+ "type": "InternalIP"
+ },
+ {
+ "address": "openshift.local",
+ "type": "Hostname"
+ }
+ ],
+ "allocatable": {
+ "cpu": "2",
+ "memory": "8072896Ki",
+ "pods": "20"
+ },
+ "capacity": {
+ "cpu": "2",
+ "memory": "8175296Ki",
+ "pods": "20"
+ },
+ "conditions": [
+ {
+ "lastHeartbeatTime": "2017-12-15T00:36:13Z",
+ "lastTransitionTime": "2017-12-11T12:00:13Z",
+ "message": "kubelet has sufficient disk space available",
+ "reason": "KubeletHasSufficientDisk",
+ "status": "False",
+ "type": "OutOfDisk"
+ },
+ {
+ "lastHeartbeatTime": "2017-12-15T00:36:13Z",
+ "lastTransitionTime": "2017-12-11T12:00:13Z",
+ "message": "kubelet has sufficient memory available",
+ "reason": "KubeletHasSufficientMemory",
+ "status": "False",
+ "type": "MemoryPressure"
+ },
+ {
+ "lastHeartbeatTime": "2017-12-15T00:36:13Z",
+ "lastTransitionTime": "2017-12-11T12:00:13Z",
+ "message": "kubelet has no disk pressure",
+ "reason": "KubeletHasNoDiskPressure",
+ "status": "False",
+ "type": "DiskPressure"
+ },
+ {
+ "lastHeartbeatTime": "2017-12-15T00:36:13Z",
+ "lastTransitionTime": "2017-12-14T15:43:39Z",
+ "message": "kubelet is posting ready status",
+ "reason": "KubeletReady",
+ "status": "True",
+ "type": "Ready"
+ }
+ ],
+ "daemonEndpoints": {
+ "kubeletEndpoint": {
+ "Port": 10250
+ }
+ },
+ "images": [
+ {
+ "names": [
+ "docker.io/openshift/origin@sha256:908c6c9ccf0e0feefe2658899656c6e73d2854777fa340738fb903f0a40c328d",
+ "docker.io/openshift/origin:latest"
+ ],
+ "sizeBytes": 1222636603
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-deployer@sha256:3d324bce1870047edc418041cefdec88e0a5bbb5b3b9f6fd35b43f14919a656c",
+ "docker.io/openshift/origin-deployer:v3.7.0"
+ ],
+ "sizeBytes": 1098951248
+ },
+ {
+ "names": [
+ "docker.io/cockpit/kubernetes@sha256:a8e58cd5e6f5a4d12d1e2dfd339686b74f3c22586952ca7aa184dc254ab49714",
+ "docker.io/cockpit/kubernetes:latest"
+ ],
+ "sizeBytes": 375926556
+ },
+ {
+ "names": [
+ "docker.io/cockpit/kubernetes@sha256:0745b3823efc57e03a5ef378614dfcb6c2b1e3964220bbf908fb3046a91cef70"
+ ],
+ "sizeBytes": 350062743
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-service-catalog@sha256:ef851e06276af96838a93320d0e4be51cc8de6e5afb2fb0efd4e56cec114b937"
+ ],
+ "sizeBytes": 284732029
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-service-catalog@sha256:8addfd742d92d8da819b091d6bda40edc45e88d1446ffd1ad658b6d21b3c36fd"
+ ],
+ "sizeBytes": 284731998
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-service-catalog@sha256:b3a737cc346b3cae85ef2f5d020b607781a1cac38fe70678cb78fee2c2a3bf8a"
+ ],
+ "sizeBytes": 284731943
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-service-catalog@sha256:957934537721da33362693d4f1590dc79dc5da7438799bf14d645165768e53ef",
+ "docker.io/openshift/origin-service-catalog:latest"
+ ],
+ "sizeBytes": 283929631
+ },
+ {
+ "names": [
+ "docker.io/openshift/origin-pod@sha256:2c257d83a01607b229ef5e3dca09f52c3a2a2788c09dc33f0444ec4e572a9e1d",
+ "docker.io/openshift/origin-pod:v3.7.0"
+ ],
+ "sizeBytes": 218423400
+ }
+ ],
+ "nodeInfo": {
+ "architecture": "amd64",
+ "bootID": "75be791d-88a2-4f56-a588-c071a80bf7cf",
+ "containerRuntimeVersion": "docker://1.12.6",
+ "kernelVersion": "3.10.0-693.11.1.el7.x86_64",
+ "kubeProxyVersion": "v1.7.6+a08f5eeb62",
+ "kubeletVersion": "v1.7.6+a08f5eeb62",
+ "machineID": "adf09ffc2de2624aa5ed335727c7400d",
+ "operatingSystem": "linux",
+ "osImage": "CentOS Linux 7 (Core)",
+ "systemUUID": "FC9FF0AD-E22D-4A62-A5ED-335727C7400D"
+ }
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume.json b/vendor/gems/kubeclient/test/json/persistent_volume.json
new file mode 100644
index 00000000000..612d9df1564
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/persistent_volume.json
@@ -0,0 +1,37 @@
+{
+ "kind": "PersistentVolume",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "pv0001",
+ "selfLink": "/api/v1/persistentvolumes/pv0001",
+ "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe",
+ "resourceVersion": "1585",
+ "creationTimestamp": "2015-08-25T14:51:35Z",
+ "labels": {
+ "type": "local"
+ }
+ },
+ "spec": {
+ "capacity": {
+ "storage": "10Gi"
+ },
+ "hostPath": {
+ "path": "/tmp/data01"
+ },
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "claimRef": {
+ "kind": "PersistentVolumeClaim",
+ "namespace": "default",
+ "name": "myclaim-1",
+ "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
+ "apiVersion": "v1",
+ "resourceVersion": "1582"
+ },
+ "persistentVolumeReclaimPolicy": "Retain"
+ },
+ "status": {
+ "phase": "Bound"
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claim.json b/vendor/gems/kubeclient/test/json/persistent_volume_claim.json
new file mode 100644
index 00000000000..65154685348
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/persistent_volume_claim.json
@@ -0,0 +1,32 @@
+{
+ "kind": "PersistentVolumeClaim",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "myclaim-1",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1",
+ "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
+ "resourceVersion": "1584",
+ "creationTimestamp": "2015-08-25T14:51:55Z"
+ },
+ "spec": {
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "resources": {
+ "requests": {
+ "storage": "3Gi"
+ }
+ },
+ "volumeName": "pv0001"
+ },
+ "status": {
+ "phase": "Bound",
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "capacity": {
+ "storage": "10Gi"
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json b/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json
new file mode 100644
index 00000000000..9533d75603b
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/persistent_volume_claim_list.json
@@ -0,0 +1,40 @@
+{
+ "kind": "PersistentVolumeClaimList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/persistentvolumeclaims",
+ "resourceVersion": "3188"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "myclaim-1",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1",
+ "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
+ "resourceVersion": "1584",
+ "creationTimestamp": "2015-08-25T14:51:55Z"
+ },
+ "spec": {
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "resources": {
+ "requests": {
+ "storage": "3Gi"
+ }
+ },
+ "volumeName": "pv0001"
+ },
+ "status": {
+ "phase": "Bound",
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "capacity": {
+ "storage": "10Gi"
+ }
+ }
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json b/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json
new file mode 100644
index 00000000000..b23ff4dcffd
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/persistent_volume_claims_nil_items.json
@@ -0,0 +1,8 @@
+{
+ "kind": "PersistentVolumeClaimList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/persistentvolumeclaims",
+ "resourceVersion": "1089012"
+ }
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/persistent_volume_list.json b/vendor/gems/kubeclient/test/json/persistent_volume_list.json
new file mode 100644
index 00000000000..fa7e53cb914
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/persistent_volume_list.json
@@ -0,0 +1,45 @@
+{
+ "kind": "PersistentVolumeList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/persistentvolumes",
+ "resourceVersion": "2999"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "pv0001",
+ "selfLink": "/api/v1/persistentvolumes/pv0001",
+ "uid": "c83eece1-4b38-11e5-8d27-28d2447dcefe",
+ "resourceVersion": "1585",
+ "creationTimestamp": "2015-08-25T14:51:35Z",
+ "labels": {
+ "type": "local"
+ }
+ },
+ "spec": {
+ "capacity": {
+ "storage": "10Gi"
+ },
+ "hostPath": {
+ "path": "/tmp/data01"
+ },
+ "accessModes": [
+ "ReadWriteOnce"
+ ],
+ "claimRef": {
+ "kind": "PersistentVolumeClaim",
+ "namespace": "default",
+ "name": "myclaim-1",
+ "uid": "d47384a3-4b38-11e5-8d27-28d2447dcefe",
+ "apiVersion": "v1",
+ "resourceVersion": "1582"
+ },
+ "persistentVolumeReclaimPolicy": "Retain"
+ },
+ "status": {
+ "phase": "Bound"
+ }
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/pod.json b/vendor/gems/kubeclient/test/json/pod.json
new file mode 100644
index 00000000000..913c2146f6a
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pod.json
@@ -0,0 +1,92 @@
+{
+ "kind": "Pod",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "redis-master3",
+ "namespace": "default",
+ "selfLink": "/api/v1/pods/redis-master3?namespace=default",
+ "uid": "a344023f-a23c-11e4-a36b-3c970e4a436a",
+ "resourceVersion": "9",
+ "creationTimestamp": "2015-01-22T15:43:24+02:00",
+ "labels": {
+ "name": "redis-master"
+ }
+ },
+ "spec": {
+ "volumes": null,
+ "containers": [
+ {
+ "name": "master",
+ "image": "dockerfile/redis",
+ "ports": [
+ {
+ "hostPort": 6379,
+ "containerPort": 6379,
+ "protocol": "TCP"
+ }
+ ],
+ "memory": "0",
+ "cpu": "100m",
+ "imagePullPolicy": ""
+ },
+ {
+ "name": "php-redis",
+ "image": "kubernetes/example-guestbook-php-redis",
+ "ports": [
+ {
+ "hostPort": 8000,
+ "containerPort": 80,
+ "protocol": "TCP"
+ }
+ ],
+ "memory": "50000000",
+ "cpu": "100m",
+ "imagePullPolicy": ""
+ }
+ ],
+ "restartPolicy": {
+ "always": {
+
+ }
+ },
+ "dnsPolicy": "ClusterFirst"
+ },
+ "status": {
+ "phase": "Running",
+ "host": "127.0.0.1",
+ "podIP": "172.17.0.2",
+ "info": {
+ "master": {
+ "state": {
+ "running": {
+ "startedAt": "2015-01-22T13:43:29Z"
+ }
+ },
+ "restartCount": 0,
+ "containerID": "docker://87458d9a12f9dc9a01b52c1eee5f09cf48939380271c0eaf31af298ce67b125e",
+ "image": "dockerfile/redis"
+ },
+ "net": {
+ "state": {
+ "running": {
+ "startedAt": "2015-01-22T13:43:27Z"
+ }
+ },
+ "restartCount": 0,
+ "containerID": "docker://3bb5ced1f831322d370f70b58137e1dd41216c2960b7a99394542b5230cbd259",
+ "podIP": "172.17.0.2",
+ "image": "kubernetes/pause:latest"
+ },
+ "php-redis": {
+ "state": {
+ "running": {
+ "startedAt": "2015-01-22T13:43:31Z"
+ }
+ },
+ "restartCount": 0,
+ "containerID": "docker://5f08685c0a7a5c974d438a52c6560d72bb0aae7e805d2a34302b9b460f1297c7",
+ "image": "kubernetes/example-guestbook-php-redis"
+ }
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/pod_list.json b/vendor/gems/kubeclient/test/json/pod_list.json
new file mode 100644
index 00000000000..d08bbdce0c0
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pod_list.json
@@ -0,0 +1,79 @@
+{
+ "kind": "PodList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/pods",
+ "resourceVersion": "1315"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "redis-master3",
+ "namespace": "default",
+ "selfLink": "/api/v1/pods/redis-master3?namespace=default",
+ "uid": "1da148b4-cef5-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "1301",
+ "creationTimestamp": "2015-03-20T13:34:48+02:00",
+ "labels": {
+ "mylabel": "mylabelvalue",
+ "role": "pod"
+ }
+ },
+ "spec": {
+ "volumes": null,
+ "containers": [
+ {
+ "name": "master",
+ "image": "dockerfile/redis",
+ "ports": [
+ {
+ "hostPort": 6379,
+ "containerPort": 6379,
+ "protocol": "TCP"
+ }
+ ],
+ "resources": {
+ "limits": {
+ "cpu": "100m"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "imagePullPolicy": "IfNotPresent",
+ "securityContext": {
+ "capabilities": {}
+ }
+ },
+ {
+ "name": "php-redis",
+ "image": "kubernetes/example-guestbook-php-redis",
+ "ports": [
+ {
+ "hostPort": 8000,
+ "containerPort": 80,
+ "protocol": "TCP"
+ }
+ ],
+ "resources": {
+ "limits": {
+ "cpu": "100m",
+ "memory": "50000000"
+ }
+ },
+ "terminationMessagePath": "/dev/termination-log",
+ "imagePullPolicy": "IfNotPresent",
+ "securityContext": {
+ "capabilities": {}
+ }
+ }
+ ],
+ "restartPolicy": {
+ "always": {}
+ },
+ "dnsPolicy": "ClusterFirst"
+ },
+ "status": {
+ "phase": "Pending"
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/pod_template_list.json b/vendor/gems/kubeclient/test/json/pod_template_list.json
new file mode 100644
index 00000000000..5acb2c2f83a
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pod_template_list.json
@@ -0,0 +1,9 @@
+{
+ "kind": "PodTemplateList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/podtemplates",
+ "resourceVersion": "672"
+ },
+ "items": []
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/pods_1.json b/vendor/gems/kubeclient/test/json/pods_1.json
new file mode 100644
index 00000000000..ec00bd3b5cc
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pods_1.json
@@ -0,0 +1,265 @@
+{
+ "kind":"PodList",
+ "apiVersion":"v1",
+ "metadata":{
+ "selfLink":"/api/v1/pods",
+ "resourceVersion":"53225946",
+ "continue":"eyJ2IjoibWV0YS5rOHMua"
+ },
+ "items":[
+ {
+ "metadata":{
+ "name":"my-ruby-project-2-build",
+ "namespace":"my-project",
+ "selfLink":"/api/v1/namespaces/my-project/pods/my-ruby-project-2-build",
+ "uid":"0c478b50-babb-11e8-ba7e-d094660d31fb",
+ "resourceVersion":"42398462",
+ "creationTimestamp":"2018-09-17T20:48:36Z",
+ "deletionTimestamp":"2018-09-19T13:22:50Z",
+ "deletionGracePeriodSeconds":0,
+ "labels":{
+ "openshift.io/build.name":"my-ruby-project-2"
+ },
+ "annotations":{
+ "openshift.io/build.name":"my-ruby-project-2",
+ "openshift.io/scc":"privileged"
+ },
+ "ownerReferences":[
+ {
+ "apiVersion":"build.openshift.io/v1",
+ "kind":"Build",
+ "name":"my-ruby-project-2",
+ "uid":"0c450e6d-babb-11e8-ba7e-d094660d31fb",
+ "controller":true
+ }
+ ],
+ "finalizers":[
+ "foregroundDeletion"
+ ]
+ },
+ "spec":{
+ "volumes":[
+ {
+ "name":"buildworkdir",
+ "emptyDir":{
+
+ }
+ },
+ {
+ "name":"docker-socket",
+ "hostPath":{
+ "path":"/var/run/docker.sock",
+ "type":""
+ }
+ },
+ {
+ "name":"crio-socket",
+ "hostPath":{
+ "path":"/var/run/crio/crio.sock",
+ "type":""
+ }
+ },
+ {
+ "name":"builder-dockercfg-rjgnm-push",
+ "secret":{
+ "secretName":"builder-dockercfg-rjgnm",
+ "defaultMode":384
+ }
+ },
+ {
+ "name":"builder-token-zkpb6",
+ "secret":{
+ "secretName":"builder-token-zkpb6",
+ "defaultMode":420
+ }
+ }
+ ],
+ "containers":[
+ {
+ "name":"sti-build",
+ "image":"openshift3/ose-sti-builder:v3.9.25",
+ "command":[
+ "openshift-sti-build"
+ ]
+ }
+ ],
+ "restartPolicy":"Never",
+ "terminationGracePeriodSeconds":30,
+ "dnsPolicy":"ClusterFirst",
+ "nodeSelector":{
+ "node-role.kubernetes.io/compute":"true"
+ },
+ "serviceAccountName":"builder",
+ "serviceAccount":"builder",
+ "nodeName":"dell-r430-20.example.com",
+ "securityContext":{
+
+ },
+ "imagePullSecrets":[
+ {
+ "name":"builder-dockercfg-rjgnm"
+ }
+ ],
+ "schedulerName":"default-scheduler"
+ },
+ "status":{
+ "phase":"Failed",
+ "conditions":[
+ {
+ "type":"Initialized",
+ "status":"True",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-09-17T20:48:49Z"
+ },
+ {
+ "type":"Ready",
+ "status":"False",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-09-17T20:49:08Z",
+ "reason":"ContainersNotReady",
+ "message":"containers with unready status: [sti-build]"
+ },
+ {
+ "type":"PodScheduled",
+ "status":"True",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-09-17T20:48:36Z"
+ }
+ ],
+ "hostIP":"10.8.96.55",
+ "podIP":"10.129.0.207",
+ "startTime":"2018-09-17T20:48:36Z",
+ "qosClass":"BestEffort"
+ }
+ },
+ {
+ "metadata":{
+ "name":"redis-1-94zxb",
+ "generateName":"redis-1-",
+ "namespace":"customer-logging",
+ "selfLink":"/api/v1/namespaces/customer-logging/pods/redis-1-94zxb",
+ "uid":"a8aea5f4-5f91-11e8-ba7e-d094660d31fb",
+ "resourceVersion":"47622190",
+ "creationTimestamp":"2018-05-24T20:33:03Z",
+ "labels":{
+ "app":"elastic-log-ripper",
+ "deployment":"redis-1",
+ "deploymentconfig":"redis",
+ "name":"redis"
+ },
+ "annotations":{
+ "openshift.io/deployment-config.latest-version":"1",
+ "openshift.io/deployment-config.name":"redis",
+ "openshift.io/deployment.name":"redis-1",
+ "openshift.io/generated-by":"OpenShiftNewApp",
+ "openshift.io/scc":"restricted"
+ },
+ "ownerReferences":[
+ {
+ "apiVersion":"v1",
+ "kind":"ReplicationController",
+ "name":"redis-1",
+ "uid":"9e2e46b3-5f91-11e8-ba7e-d094660d31fb",
+ "controller":true,
+ "blockOwnerDeletion":true
+ }
+ ]
+ },
+ "spec":{
+ "volumes":[
+ {
+ "name":"default-token-n2wzs",
+ "secret":{
+ "secretName":"default-token-n2wzs",
+ "defaultMode":420
+ }
+ }
+ ],
+ "containers":[
+ {
+ "name":"redis",
+ "image":"manageiq/redis:latest",
+ "ports":[
+ {
+ "containerPort":6379,
+ "protocol":"TCP"
+ }
+ ],
+ "resources":{
+
+ },
+ "volumeMounts":[
+ {
+ "name":"default-token-n2wzs",
+ "readOnly":true,
+ "mountPath":"/var/run/secrets/kubernetes.io/serviceaccount"
+ }
+ ],
+ "terminationMessagePath":"/dev/termination-log",
+ "terminationMessagePolicy":"File",
+ "imagePullPolicy":"Always",
+ "securityContext":{
+ "capabilities":{
+ "drop":[
+ "KILL",
+ "MKNOD",
+ "SETGID",
+ "SETUID"
+ ]
+ },
+ "runAsUser":1000260000
+ }
+ }
+ ],
+ "restartPolicy":"Always",
+ "terminationGracePeriodSeconds":30,
+ "dnsPolicy":"ClusterFirst",
+ "nodeSelector":{
+ "node-role.kubernetes.io/compute":"true"
+ },
+ "serviceAccountName":"default",
+ "serviceAccount":"default",
+ "nodeName":"dell-r430-20.example.com",
+ "securityContext":{
+ "seLinuxOptions":{
+ "level":"s0:c16,c10"
+ },
+ "fsGroup":1000260000
+ },
+ "imagePullSecrets":[
+ {
+ "name":"default-dockercfg-ck286"
+ }
+ ],
+ "schedulerName":"default-scheduler"
+ },
+ "status":{
+ "phase":"Running",
+ "conditions":[
+ {
+ "type":"Initialized",
+ "status":"True",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-05-24T20:33:04Z"
+ },
+ {
+ "type":"Ready",
+ "status":"True",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-09-18T12:06:18Z"
+ },
+ {
+ "type":"PodScheduled",
+ "status":"True",
+ "lastProbeTime":null,
+ "lastTransitionTime":"2018-05-24T20:33:03Z"
+ }
+ ],
+ "hostIP":"10.8.96.55",
+ "podIP":"10.129.0.222",
+ "startTime":"2018-05-24T20:33:04Z",
+ "qosClass":"BestEffort"
+ }
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/pods_2.json b/vendor/gems/kubeclient/test/json/pods_2.json
new file mode 100644
index 00000000000..fd6085bc5de
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pods_2.json
@@ -0,0 +1,102 @@
+{
+ "kind":"PodList",
+ "apiVersion":"v1",
+ "metadata":{
+ "selfLink":"/api/v1/pods",
+ "resourceVersion":"53226147"
+ },
+ "items":[
+ {
+ "metadata":{
+ "name":"topological-inventory-persister-9-hznds",
+ "generateName":"topological-inventory-persister-9-",
+ "namespace":"topological-inventory-ci",
+ "selfLink":"/api/v1/namespaces/topological-inventory-ci/pods/topological-inventory-persister-9-hznds",
+ "uid":"0c114dde-d865-11e8-ba7e-d094660d31fb",
+ "resourceVersion":"51987342",
+ "creationTimestamp":"2018-10-25T14:48:34Z",
+ "labels":{
+ "name":"topological-inventory-persister"
+ }
+ },
+ "spec":{
+ "volumes":[
+ {
+ "name":"default-token-5pdjl",
+ "secret":{
+ "secretName":"default-token-5pdjl",
+ "defaultMode":420
+ }
+ }
+ ],
+ "containers":[
+ {
+ "name":"topological-inventory-persister",
+ "image":"docker-registry.default.svc:5000/topological-inventory-ci/topological-inventory-persister@sha256:0f654ea09e749019cf3bcc4b8ee43b8dd813fcbf487843b917cf190213741927",
+ "resources":{
+ }
+ }
+ ],
+ "restartPolicy":"Always",
+ "terminationGracePeriodSeconds":30,
+ "dnsPolicy":"ClusterFirst",
+ "nodeSelector":{
+ "node-role.kubernetes.io/compute":"true"
+ },
+ "serviceAccountName":"default",
+ "serviceAccount":"default",
+ "nodeName":"dell-r430-20.example.com",
+ "schedulerName":"default-scheduler"
+ },
+ "status":{
+ "phase":"Running",
+ "hostIP":"10.8.96.55",
+ "podIP":"10.129.1.108",
+ "startTime":"2018-10-25T14:48:34Z",
+ "qosClass":"BestEffort"
+ }
+ },
+ {
+ "metadata":{
+ "name":"topological-inventory-persister-9-vzr6h",
+ "generateName":"topological-inventory-persister-9-",
+ "namespace":"topological-inventory-ci",
+ "selfLink":"/api/v1/namespaces/topological-inventory-ci/pods/topological-inventory-persister-9-vzr6h",
+ "uid":"3065d8ce-d86a-11e8-ba7e-d094660d31fb",
+ "resourceVersion":"51996115",
+ "creationTimestamp":"2018-10-25T15:25:22Z",
+ "labels":{
+ "name":"topological-inventory-persister"
+ }
+ },
+ "spec":{
+ "volumes":null,
+ "containers":[
+ {
+ "name":"topological-inventory-persister",
+ "image":"docker-registry.default.svc:5000/topological-inventory-ci/topological-inventory-persister@sha256:0f654ea09e749019cf3bcc4b8ee43b8dd813fcbf487843b917cf190213741927",
+ "resources":{
+ }
+ }
+ ],
+ "restartPolicy":"Always",
+ "terminationGracePeriodSeconds":30,
+ "dnsPolicy":"ClusterFirst",
+ "nodeSelector":{
+ "node-role.kubernetes.io/compute":"true"
+ },
+ "serviceAccountName":"default",
+ "serviceAccount":"default",
+ "nodeName":"dell-r430-20.example.com",
+ "schedulerName":"default-scheduler"
+ },
+ "status":{
+ "phase":"Running",
+ "hostIP":"10.8.96.55",
+ "podIP":"10.129.1.168",
+ "startTime":"2018-10-25T15:25:22Z",
+ "qosClass":"BestEffort"
+ }
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/pods_410.json b/vendor/gems/kubeclient/test/json/pods_410.json
new file mode 100644
index 00000000000..eb1a31937b7
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/pods_410.json
@@ -0,0 +1,9 @@
+{
+ "kind":"Status",
+ "apiVersion":"v1",
+ "metadata":{},
+ "status":"Failure",
+ "message":"The provided from parameter is too old to display a consistent list result. You must start a new list without the from.",
+ "reason":"Expired",
+ "code":410
+}
diff --git a/vendor/gems/kubeclient/test/json/processed_template.json b/vendor/gems/kubeclient/test/json/processed_template.json
new file mode 100644
index 00000000000..66c6e32ea70
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/processed_template.json
@@ -0,0 +1,27 @@
+{
+ "kind": "Template",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "my-templtae",
+ "namespace": "default",
+ "selfLink": "/oapi/v1/namespaces/default/processedtemplates/my-templtae",
+ "uid": "2240c61c-8f70-11e5-a806-001a4a231290",
+ "resourceVersion": "1399",
+ "creationTimestamp": "2015-11-20T10:19:07Z"
+ },
+ "objects": [
+ {
+ "apiVersion": "v1",
+ "kind": "Service",
+ "metadata": {
+ "name": "test/my-service"
+ }
+ }
+ ],
+ "parameters": [
+ {
+ "name": "NAME_PREFIX",
+ "value": "test/"
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/replication_controller.json b/vendor/gems/kubeclient/test/json/replication_controller.json
new file mode 100644
index 00000000000..26ac7a9a39e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/replication_controller.json
@@ -0,0 +1,57 @@
+{
+ "kind": "ReplicationController",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "guestbook-controller",
+ "namespace": "default",
+ "selfLink": "/api/v1/replicationcontrollers/guestbook-controller?namespace=default",
+ "uid": "c71aa4c0-a240-11e4-a265-3c970e4a436a",
+ "resourceVersion": "8",
+ "creationTimestamp": "2015-01-22T16:13:02+02:00",
+ "labels": {
+ "name": "guestbook"
+ }
+ },
+ "spec": {
+ "replicas": 3,
+ "selector": {
+ "name": "guestbook"
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "name": "guestbook"
+ }
+ },
+ "spec": {
+ "volumes": null,
+ "containers": [
+ {
+ "name": "guestbook",
+ "image": "kubernetes/guestbook",
+ "ports": [
+ {
+ "name": "http-server",
+ "containerPort": 3000,
+ "protocol": "TCP"
+ }
+ ],
+ "memory": "0",
+ "cpu": "0m",
+ "imagePullPolicy": ""
+ }
+ ],
+ "restartPolicy": {
+ "always": {
+
+ }
+ },
+ "dnsPolicy": "ClusterFirst"
+ }
+ }
+ },
+ "status": {
+ "replicas": 3
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/replication_controller_list.json b/vendor/gems/kubeclient/test/json/replication_controller_list.json
new file mode 100644
index 00000000000..b7f2f7bd521
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/replication_controller_list.json
@@ -0,0 +1,66 @@
+{
+ "kind": "ReplicationControllerList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/namespaces/default/replicationcontrollers",
+ "resourceVersion": "1636"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "redis-master-controller",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/replicationcontrollers/redis-master-controller?namespace=default",
+ "uid": "108eb547-cefa-11e4-ac24-3c970e4a436a",
+ "resourceVersion": "1631",
+ "creationTimestamp": "2015-03-20T14:10:14+02:00",
+ "labels": {
+ "name": "redis-master"
+ }
+ },
+ "spec": {
+ "replicas": 1,
+ "selector": {
+ "name": "redis-master"
+ },
+ "template": {
+ "metadata": {
+ "creationTimestamp": null,
+ "labels": {
+ "app": "redis",
+ "name": "redis-master"
+ }
+ },
+ "spec": {
+ "volumes": null,
+ "containers": [
+ {
+ "name": "redis-master",
+ "image": "dockerfile/redis",
+ "ports": [
+ {
+ "containerPort": 6379,
+ "protocol": "TCP"
+ }
+ ],
+ "resources": {},
+ "terminationMessagePath": "/dev/termination-log",
+ "imagePullPolicy": "IfNotPresent",
+ "securityContext": {
+ "capabilities": {}
+ }
+ }
+ ],
+ "restartPolicy": {
+ "always": {}
+ },
+ "dnsPolicy": "ClusterFirst"
+ }
+ }
+ },
+ "status": {
+ "replicas": 1
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/resource_quota.json b/vendor/gems/kubeclient/test/json/resource_quota.json
new file mode 100644
index 00000000000..75b40391d68
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/resource_quota.json
@@ -0,0 +1,46 @@
+{
+ "kind": "ResourceQuota",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "quota",
+ "namespace": "quota-example",
+ "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota",
+ "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e",
+ "resourceVersion": "12919",
+ "creationTimestamp": "2015-08-06T14:01:44Z"
+ },
+ "spec": {
+ "hard": {
+ "cpu": "20",
+ "memory": "1Gi",
+ "persistentvolumeclaims": "10",
+ "pods": "10",
+ "replicationcontrollers": "20",
+ "resourcequotas": "1",
+ "secrets": "10",
+ "services": "5"
+ }
+ },
+ "status": {
+ "hard": {
+ "cpu": "20",
+ "memory": "1Gi",
+ "persistentvolumeclaims": "10",
+ "pods": "10",
+ "replicationcontrollers": "20",
+ "resourcequotas": "1",
+ "secrets": "10",
+ "services": "5"
+ },
+ "used": {
+ "cpu": "0",
+ "memory": "0",
+ "persistentvolumeclaims": "0",
+ "pods": "0",
+ "replicationcontrollers": "1",
+ "resourcequotas": "1",
+ "secrets": "9",
+ "services": "0"
+ }
+ }
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/resource_quota_list.json b/vendor/gems/kubeclient/test/json/resource_quota_list.json
new file mode 100644
index 00000000000..371f3feb649
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/resource_quota_list.json
@@ -0,0 +1,54 @@
+{
+ "kind": "ResourceQuotaList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/",
+ "resourceVersion": "102452"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "quota",
+ "namespace": "quota-example",
+ "selfLink": "/api/v1/namespaces/quota-example/resourcequotas/quota",
+ "uid": "ab9f24a4-3c43-11e5-8214-0aaeec44370e",
+ "resourceVersion": "12919",
+ "creationTimestamp": "2015-08-06T14:01:44Z"
+ },
+ "spec": {
+ "hard": {
+ "cpu": "20",
+ "memory": "1Gi",
+ "persistentvolumeclaims": "10",
+ "pods": "10",
+ "replicationcontrollers": "20",
+ "resourcequotas": "1",
+ "secrets": "10",
+ "services": "5"
+ }
+ },
+ "status": {
+ "hard": {
+ "cpu": "20",
+ "memory": "1Gi",
+ "persistentvolumeclaims": "10",
+ "pods": "10",
+ "replicationcontrollers": "20",
+ "resourcequotas": "1",
+ "secrets": "10",
+ "services": "5"
+ },
+ "used": {
+ "cpu": "0",
+ "memory": "0",
+ "persistentvolumeclaims": "0",
+ "pods": "0",
+ "replicationcontrollers": "1",
+ "resourcequotas": "1",
+ "secrets": "9",
+ "services": "0"
+ }
+ }
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/secret_list.json b/vendor/gems/kubeclient/test/json/secret_list.json
new file mode 100644
index 00000000000..bfd7661b390
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/secret_list.json
@@ -0,0 +1,44 @@
+{
+ "kind": "SecretList",
+ "apiVersion":"v1",
+ "metadata":{
+ "selfLink":"/api/v1/secrets",
+ "resourceVersion":"256788"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name":"default-token-my2pi",
+ "namespace":"default",
+ "selfLink":"/api/v1/namespaces/default/secrets/default-token-my2pi",
+ "uid":"07b60654-2a65-11e5-a483-0e840567604d",
+ "resourceVersion":"11",
+ "creationTimestamp":"2015-07-14T20:15:11Z",
+ "annotations": {
+ "kubernetes.io/service-account.name":"default",
+ "kubernetes.io/service-account.uid":"07b350a0-2a65-11e5-a483-0e840567604d"
+ }
+ },
+ "data":{
+ "ca.crt":"Y2F0J3MgYXJlIGF3ZXNvbWUK",
+ "token":"Y2F0J3MgYXJlIGF3ZXNvbWUK"
+ },
+ "type":"kubernetes.io/service-account-token"
+ },
+ {
+ "metadata": {
+ "name": "test-secret",
+ "namespace": "dev",
+ "selfLink": "/api/v1/namespaces/dev/secrets/test-secret",
+ "uid": "4e38a198-2bcb-11e5-a483-0e840567604d",
+ "resourceVersion": "245569",
+ "creationTimestamp": "2015-07-16T14:59:49Z"
+ },
+ "data": {
+ "super-secret": "Y2F0J3MgYXJlIGF3ZXNvbWUK"
+ },
+ "type": "Opaque"
+ }
+ ]
+}
+
diff --git a/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json
new file mode 100644
index 00000000000..18e2021cff5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/security.openshift.io_api_resource_list.json
@@ -0,0 +1,69 @@
+{
+ "kind": "APIResourceList",
+ "apiVersion": "v1",
+ "groupVersion": "security.openshift.io/v1",
+ "resources": [
+ {
+ "name": "podsecuritypolicyreviews",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "PodSecurityPolicyReview",
+ "verbs": [
+ "create"
+ ]
+ },
+ {
+ "name": "podsecuritypolicyselfsubjectreviews",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "PodSecurityPolicySelfSubjectReview",
+ "verbs": [
+ "create"
+ ]
+ },
+ {
+ "name": "podsecuritypolicysubjectreviews",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "PodSecurityPolicySubjectReview",
+ "verbs": [
+ "create"
+ ]
+ },
+ {
+ "name": "rangeallocations",
+ "singularName": "",
+ "namespaced": false,
+ "kind": "RangeAllocation",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "securitycontextconstraints",
+ "singularName": "",
+ "namespaced": false,
+ "kind": "SecurityContextConstraints",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ],
+ "shortNames": [
+ "scc"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/security_context_constraint_list.json b/vendor/gems/kubeclient/test/json/security_context_constraint_list.json
new file mode 100644
index 00000000000..1e9d4c474a7
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/security_context_constraint_list.json
@@ -0,0 +1,375 @@
+{
+ "kind": "SecurityContextConstraintsList",
+ "apiVersion": "security.openshift.io/v1",
+ "metadata": {
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints",
+ "resourceVersion": "5751"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "anyuid",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/anyuid",
+ "uid": "12ba8540-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "71",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "anyuid provides all features of the restricted SCC but allows users to run with any UID and any GID."
+ }
+ },
+ "priority": 10,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "MKNOD"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": false,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": false,
+ "allowHostPorts": false,
+ "allowHostPID": false,
+ "allowHostIPC": false,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "RunAsAny"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "RunAsAny"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [],
+ "groups": [
+ "system:cluster-admins"
+ ]
+ },
+ {
+ "metadata": {
+ "name": "hostaccess",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostaccess",
+ "uid": "12b5b3a2-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "69",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "hostaccess allows access to all host namespaces but still requires pods to be run with a UID and SELinux context that are allocated to the namespace. WARNING: this SCC allows host access to namespaces, file systems, and PIDS. It should only be used by trusted pods. Grant with caution."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "KILL",
+ "MKNOD",
+ "SETUID",
+ "SETGID"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": true,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "hostPath",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": true,
+ "allowHostPorts": true,
+ "allowHostPID": true,
+ "allowHostIPC": true,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "MustRunAsRange"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "MustRunAs"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [],
+ "groups": []
+ },
+ {
+ "metadata": {
+ "name": "hostmount-anyuid",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostmount-anyuid",
+ "uid": "12b512c0-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "68",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "hostmount-anyuid provides all the features of the restricted SCC but allows host mounts and any UID by a pod. This is primarily used by the persistent volume recycler. WARNING: this SCC allows host file system access as any UID, including UID 0. Grant with caution."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "MKNOD"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": true,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "hostPath",
+ "nfs",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": false,
+ "allowHostPorts": false,
+ "allowHostPID": false,
+ "allowHostIPC": false,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "RunAsAny"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "RunAsAny"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [
+ "system:serviceaccount:openshift-infra:pv-recycler-controller"
+ ],
+ "groups": []
+ },
+ {
+ "metadata": {
+ "name": "hostnetwork",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/hostnetwork",
+ "uid": "12bb0984-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "72",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "hostnetwork allows using host networking and host ports but still requires pods to be run with a UID and SELinux context that are allocated to the namespace."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "KILL",
+ "MKNOD",
+ "SETUID",
+ "SETGID"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": false,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": true,
+ "allowHostPorts": true,
+ "allowHostPID": false,
+ "allowHostIPC": false,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "MustRunAsRange"
+ },
+ "supplementalGroups": {
+ "type": "MustRunAs"
+ },
+ "fsGroup": {
+ "type": "MustRunAs"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [],
+ "groups": []
+ },
+ {
+ "metadata": {
+ "name": "nonroot",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/nonroot",
+ "uid": "12b37c59-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "67",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "nonroot provides all features of the restricted SCC but allows users to run with any non-root UID. The user must specify the UID or it must be specified on the by the manifest of the container runtime."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "KILL",
+ "MKNOD",
+ "SETUID",
+ "SETGID"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": false,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": false,
+ "allowHostPorts": false,
+ "allowHostPID": false,
+ "allowHostIPC": false,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "MustRunAsNonRoot"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "RunAsAny"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [],
+ "groups": []
+ },
+ {
+ "metadata": {
+ "name": "privileged",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/privileged",
+ "uid": "12b18f4a-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "300",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "privileged allows access to all privileged and host features and the ability to run as any user, any group, any fsGroup, and with any SELinux context. WARNING: this is the most relaxed SCC and should be used only for cluster administration. Grant with caution."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": true,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": null,
+ "allowedCapabilities": [
+ "*"
+ ],
+ "allowHostDirVolumePlugin": true,
+ "volumes": [
+ "*"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": true,
+ "allowHostPorts": true,
+ "allowHostPID": true,
+ "allowHostIPC": true,
+ "seLinuxContext": {
+ "type": "RunAsAny"
+ },
+ "runAsUser": {
+ "type": "RunAsAny"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "RunAsAny"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [
+ "system:admin",
+ "system:serviceaccount:openshift-infra:build-controller",
+ "system:serviceaccount:default:pvinstaller",
+ "system:serviceaccount:default:registry",
+ "system:serviceaccount:default:router"
+ ],
+ "groups": [
+ "system:cluster-admins",
+ "system:nodes",
+ "system:masters"
+ ],
+ "seccompProfiles": [
+ "*"
+ ]
+ },
+ {
+ "metadata": {
+ "name": "restricted",
+ "selfLink": "/apis/security.openshift.io/v1/securitycontextconstraints/restricted",
+ "uid": "12b9a842-ef00-11e8-b4c0-68f728fac3ab",
+ "resourceVersion": "70",
+ "creationTimestamp": "2018-11-23T09:13:42Z",
+ "annotations": {
+ "kubernetes.io/description": "restricted denies access to all host features and requires pods to be run with a UID, and SELinux context that are allocated to the namespace. This is the most restrictive SCC and it is used by default for authenticated users."
+ }
+ },
+ "priority": null,
+ "allowPrivilegedContainer": false,
+ "defaultAddCapabilities": null,
+ "requiredDropCapabilities": [
+ "KILL",
+ "MKNOD",
+ "SETUID",
+ "SETGID"
+ ],
+ "allowedCapabilities": null,
+ "allowHostDirVolumePlugin": false,
+ "volumes": [
+ "configMap",
+ "downwardAPI",
+ "emptyDir",
+ "persistentVolumeClaim",
+ "projected",
+ "secret"
+ ],
+ "allowedFlexVolumes": null,
+ "allowHostNetwork": false,
+ "allowHostPorts": false,
+ "allowHostPID": false,
+ "allowHostIPC": false,
+ "seLinuxContext": {
+ "type": "MustRunAs"
+ },
+ "runAsUser": {
+ "type": "MustRunAsRange"
+ },
+ "supplementalGroups": {
+ "type": "RunAsAny"
+ },
+ "fsGroup": {
+ "type": "MustRunAs"
+ },
+ "readOnlyRootFilesystem": false,
+ "users": [],
+ "groups": [
+ "system:authenticated"
+ ]
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/service.json b/vendor/gems/kubeclient/test/json/service.json
new file mode 100644
index 00000000000..6e2e5c79ce1
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service.json
@@ -0,0 +1,33 @@
+{
+ "kind": "Service",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "redis-slave",
+ "namespace": "development",
+ "selfLink": "/api/v1/namespaces/development/services/redis-slave",
+ "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1",
+ "resourceVersion": "2815",
+ "creationTimestamp": "2015-04-05T13:00:31Z",
+ "labels": {
+ "name": "redis",
+ "role": "slave"
+ }
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "",
+ "protocol": "TCP",
+ "port": 6379,
+ "targetPort": "redis-server"
+ }
+ ],
+ "selector": {
+ "name": "redis",
+ "role": "slave"
+ },
+ "clusterIP": "10.0.0.140",
+ "sessionAffinity": "None"
+ },
+ "status": {}
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_account.json b/vendor/gems/kubeclient/test/json/service_account.json
new file mode 100644
index 00000000000..632d429260d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_account.json
@@ -0,0 +1,25 @@
+{
+ "kind": "ServiceAccount",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "default",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/serviceaccounts/default",
+ "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e",
+ "resourceVersion": "94",
+ "creationTimestamp": "2015-10-06T06:09:39Z"
+ },
+ "secrets": [
+ {
+ "name": "default-token-6s23q"
+ },
+ {
+ "name": "default-dockercfg-62tf3"
+ }
+ ],
+ "imagePullSecrets": [
+ {
+ "name": "default-dockercfg-62tf3"
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/service_account_list.json b/vendor/gems/kubeclient/test/json/service_account_list.json
new file mode 100644
index 00000000000..934e729ed08
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_account_list.json
@@ -0,0 +1,82 @@
+{
+ "kind": "List",
+ "apiVersion": "v1",
+ "metadata": {},
+ "items": [
+ {
+ "kind": "ServiceAccount",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "builder",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/serviceaccounts/builder",
+ "uid": "d40655f6-6bf0-11e5-843a-525400f8b93e",
+ "resourceVersion": "133",
+ "creationTimestamp": "2015-10-06T06:09:39Z"
+ },
+ "secrets": [
+ {
+ "name": "builder-token-5v6z2"
+ },
+ {
+ "name": "builder-dockercfg-qe2re"
+ }
+ ],
+ "imagePullSecrets": [
+ {
+ "name": "builder-dockercfg-qe2re"
+ }
+ ]
+ },
+ {
+ "kind": "ServiceAccount",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "default",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/serviceaccounts/default",
+ "uid": "d3d773f4-6bf0-11e5-843a-525400f8b93e",
+ "resourceVersion": "94",
+ "creationTimestamp": "2015-10-06T06:09:39Z"
+ },
+ "secrets": [
+ {
+ "name": "default-token-6s23q"
+ },
+ {
+ "name": "default-dockercfg-62tf3"
+ }
+ ],
+ "imagePullSecrets": [
+ {
+ "name": "default-dockercfg-62tf3"
+ }
+ ]
+ },
+ {
+ "kind": "ServiceAccount",
+ "apiVersion": "v1",
+ "metadata": {
+ "name": "deployer",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/serviceaccounts/deployer",
+ "uid": "d41d385e-6bf0-11e5-843a-525400f8b93e",
+ "resourceVersion": "137",
+ "creationTimestamp": "2015-10-06T06:09:39Z"
+ },
+ "secrets": [
+ {
+ "name": "deployer-token-h3i57"
+ },
+ {
+ "name": "deployer-dockercfg-qgjjj"
+ }
+ ],
+ "imagePullSecrets": [
+ {
+ "name": "deployer-dockercfg-qgjjj"
+ }
+ ]
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/service_illegal_json_404.json b/vendor/gems/kubeclient/test/json/service_illegal_json_404.json
new file mode 100644
index 00000000000..faa82b3aa87
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_illegal_json_404.json
@@ -0,0 +1 @@
+404: Page Not Found \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_json_patch.json b/vendor/gems/kubeclient/test/json/service_json_patch.json
new file mode 100644
index 00000000000..f960242ba4d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_json_patch.json
@@ -0,0 +1,26 @@
+{
+ "status" : {},
+ "kind" : "Service",
+ "apiVersion" : "v1",
+ "spec" : {
+ "ports" : [
+ {
+ "targetPort" : 80,
+ "nodePort" : 0,
+ "port" : 80,
+ "protocol" : "TCP"
+ }
+ ],
+ "clusterIP" : "1.2.3.4",
+ "type": "LoadBalancer"
+ },
+ "metadata" : {
+ "name" : "my-service",
+ "creationTimestamp" : null,
+ "namespace" : "development",
+ "resourceVersion" : "2",
+ "annotations" : {
+ "key" : "value"
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/service_list.json b/vendor/gems/kubeclient/test/json/service_list.json
new file mode 100644
index 00000000000..f0f97a12c4e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_list.json
@@ -0,0 +1,97 @@
+{
+ "kind": "ServiceList",
+ "apiVersion": "v1",
+ "metadata": {
+ "selfLink": "/api/v1/services",
+ "resourceVersion": "36727"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "kubernetes",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/services/kubernetes",
+ "uid": "b6606490-db86-11e4-b293-f8b156af4ae1",
+ "resourceVersion": "6",
+ "creationTimestamp": "2015-04-05T11:27:15Z",
+ "labels": {
+ "component": "apiserver",
+ "provider": "kubernetes"
+ }
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "",
+ "protocol": "TCP",
+ "port": 443,
+ "targetPort": 443
+ }
+ ],
+ "selector": null,
+ "clusterIP": "10.0.0.2",
+ "sessionAffinity": "None"
+ },
+ "status": {}
+ },
+ {
+ "metadata": {
+ "name": "kubernetes-ro",
+ "namespace": "default",
+ "selfLink": "/api/v1/namespaces/default/services/kubernetes-ro",
+ "uid": "b6606694-db86-11e4-b293-f8b156af4ae1",
+ "resourceVersion": "5",
+ "creationTimestamp": "2015-04-05T11:27:15Z",
+ "labels": {
+ "component": "apiserver",
+ "provider": "kubernetes"
+ }
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "",
+ "protocol": "TCP",
+ "port": 80,
+ "targetPort": 80
+ }
+ ],
+ "selector": null,
+ "clusterIP": "10.0.0.1",
+ "sessionAffinity": "None"
+ },
+ "status": {}
+ },
+ {
+ "metadata": {
+ "name": "redis-slave",
+ "namespace": "development",
+ "selfLink": "/api/v1/namespaces/development/services/redis-slave",
+ "uid": "bdb80a8f-db93-11e4-b293-f8b156af4ae1",
+ "resourceVersion": "2815",
+ "creationTimestamp": "2015-04-05T13:00:31Z",
+ "labels": {
+ "name": "redis",
+ "role": "slave"
+ }
+ },
+ "spec": {
+ "ports": [
+ {
+ "name": "",
+ "protocol": "TCP",
+ "port": 6379,
+ "targetPort": "redis-server"
+ }
+ ],
+ "selector": {
+ "name": "redis",
+ "role": "slave"
+ },
+ "clusterIP": "10.0.0.140",
+ "sessionAffinity": "None"
+ },
+ "status": {}
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/service_merge_patch.json b/vendor/gems/kubeclient/test/json/service_merge_patch.json
new file mode 100644
index 00000000000..5a9cf7dd384
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_merge_patch.json
@@ -0,0 +1,26 @@
+{
+ "status" : {},
+ "kind" : "Service",
+ "apiVersion" : "v1",
+ "spec" : {
+ "ports" : [
+ {
+ "targetPort" : 80,
+ "nodePort" : 0,
+ "port" : 80,
+ "protocol" : "TCP"
+ }
+ ],
+ "clusterIP" : "1.2.3.4",
+ "type": "NodePort"
+ },
+ "metadata" : {
+ "name" : "my-service",
+ "creationTimestamp" : null,
+ "namespace" : "development",
+ "resourceVersion" : "2",
+ "annotations" : {
+ "key" : "value"
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/service_patch.json b/vendor/gems/kubeclient/test/json/service_patch.json
new file mode 100644
index 00000000000..d6c9c29e691
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_patch.json
@@ -0,0 +1,25 @@
+{
+ "status" : {},
+ "kind" : "Service",
+ "apiVersion" : "v1",
+ "spec" : {
+ "ports" : [
+ {
+ "targetPort" : 80,
+ "nodePort" : 0,
+ "port" : 80,
+ "protocol" : "TCP"
+ }
+ ],
+ "clusterIP" : "1.2.3.4"
+ },
+ "metadata" : {
+ "name" : "my_service",
+ "creationTimestamp" : null,
+ "namespace" : "development",
+ "resourceVersion" : "2",
+ "annotations" : {
+ "key" : "value"
+ }
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/service_update.json b/vendor/gems/kubeclient/test/json/service_update.json
new file mode 100644
index 00000000000..1053d750e60
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/service_update.json
@@ -0,0 +1,22 @@
+{
+ "status" : {},
+ "kind" : "Service",
+ "apiVersion" : "v1",
+ "spec" : {
+ "ports" : [
+ {
+ "targetPort" : 80,
+ "nodePort" : 0,
+ "port" : 80,
+ "protocol" : "TCP"
+ }
+ ],
+ "clusterIP" : "1.2.3.4"
+ },
+ "metadata" : {
+ "name" : "my_service",
+ "creationTimestamp" : null,
+ "namespace" : "default",
+ "resourceVersion" : "2"
+ }
+}
diff --git a/vendor/gems/kubeclient/test/json/template.json b/vendor/gems/kubeclient/test/json/template.json
new file mode 100644
index 00000000000..85d8bad748e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/template.json
@@ -0,0 +1,27 @@
+{
+ "apiVersion": "template.openshift.io/v1",
+ "kind": "Template",
+ "metadata": {
+ "creationTimestamp": "2018-12-17T16:11:36Z",
+ "name": "my-template",
+ "namespace": "default",
+ "resourceVersion": "21954",
+ "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates/my-template",
+ "uid": "6e03e3e6-0216-11e9-b1e0-68f728fac3ab"
+ },
+ "objects": [
+ {
+ "apiVersion": "v1",
+ "kind": "Service",
+ "metadata": {
+ "name": "${NAME_PREFIX}my-service"
+ }
+ }
+ ],
+ "parameters": [
+ {
+ "description": "Prefix for names",
+ "name": "NAME_PREFIX"
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json b/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json
new file mode 100644
index 00000000000..1ba147f795d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/template.openshift.io_api_resource_list.json
@@ -0,0 +1,75 @@
+{
+ "kind": "APIResourceList",
+ "apiVersion": "v1",
+ "groupVersion": "template.openshift.io/v1",
+ "resources": [
+ {
+ "name": "brokertemplateinstances",
+ "singularName": "",
+ "namespaced": false,
+ "kind": "BrokerTemplateInstance",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "processedtemplates",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Template",
+ "verbs": [
+ "create"
+ ]
+ },
+ {
+ "name": "templateinstances",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "TemplateInstance",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ]
+ },
+ {
+ "name": "templateinstances/status",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "TemplateInstance",
+ "verbs": [
+ "get",
+ "patch",
+ "update"
+ ]
+ },
+ {
+ "name": "templates",
+ "singularName": "",
+ "namespaced": true,
+ "kind": "Template",
+ "verbs": [
+ "create",
+ "delete",
+ "deletecollection",
+ "get",
+ "list",
+ "patch",
+ "update",
+ "watch"
+ ]
+ }
+ ]
+} \ No newline at end of file
diff --git a/vendor/gems/kubeclient/test/json/template_list.json b/vendor/gems/kubeclient/test/json/template_list.json
new file mode 100644
index 00000000000..a0f84ad3e01
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/template_list.json
@@ -0,0 +1,35 @@
+{
+ "kind": "TemplateList",
+ "apiVersion": "template.openshift.io/v1",
+ "metadata": {
+ "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates",
+ "resourceVersion": "22758"
+ },
+ "items": [
+ {
+ "metadata": {
+ "name": "my-template",
+ "namespace": "default",
+ "selfLink": "/apis/template.openshift.io/v1/namespaces/default/templates/my-template",
+ "uid": "6e03e3e6-0216-11e9-b1e0-68f728fac3ab",
+ "resourceVersion": "21954",
+ "creationTimestamp": "2018-12-17T16:11:36Z"
+ },
+ "objects": [
+ {
+ "apiVersion": "v1",
+ "kind": "Service",
+ "metadata": {
+ "name": "${NAME_PREFIX}my-service"
+ }
+ }
+ ],
+ "parameters": [
+ {
+ "name": "NAME_PREFIX",
+ "description": "Prefix for names"
+ }
+ ]
+ }
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/versions_list.json b/vendor/gems/kubeclient/test/json/versions_list.json
new file mode 100644
index 00000000000..372e101b6ab
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/versions_list.json
@@ -0,0 +1,6 @@
+{
+ "versions": [
+ "v1beta3",
+ "v1"
+ ]
+}
diff --git a/vendor/gems/kubeclient/test/json/watch_stream.json b/vendor/gems/kubeclient/test/json/watch_stream.json
new file mode 100644
index 00000000000..aa8f03dd078
--- /dev/null
+++ b/vendor/gems/kubeclient/test/json/watch_stream.json
@@ -0,0 +1,3 @@
+{"type":"ADDED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1389","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending"}}}
+{"type":"MODIFIED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1390","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}}
+{"type":"DELETED","object":{"kind":"Pod","apiVersion":"v1","metadata":{"name":"php","namespace":"default","selfLink":"/api/v1/pods/php","uid":"e75f2c07-b047-11e4-89e4-525400c903c1","resourceVersion":"1398","creationTimestamp":"2015-02-09T05:39:19-05:00","labels":{"name":"foo"}},"spec":{"volumes":null,"containers":[{"name":"nginx","image":"dockerfile/nginx","ports":[{"hostPort":9090,"containerPort":80,"protocol":"TCP"}],"resources":{},"livenessProbe":{"httpGet":{"path":"/index.html","port":"9090"},"initialDelaySeconds":30},"terminationMessagePath":"/dev/termination-log","imagePullPolicy":"IfNotPresent","securityContext":{"capabilities":{}}}],"restartPolicy":{"always":{}},"dnsPolicy":"ClusterFirst"},"status":{"phase":"Pending","host":"127.0.0.1"}}}
diff --git a/vendor/gems/kubeclient/test/test_common.rb b/vendor/gems/kubeclient/test/test_common.rb
new file mode 100644
index 00000000000..32bf826085d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_common.rb
@@ -0,0 +1,95 @@
+
+require_relative 'test_helper'
+
+# Unit tests for the common module
+class CommonTest < MiniTest::Test
+ class ClientStub
+ include Kubeclient::ClientMixin
+ end
+
+ def client
+ @client ||= ClientStub.new
+ end
+
+ def test_underscore_entity
+ %w[
+ Pod pod
+ Service service
+ ReplicationController replication_controller
+ Node node
+ Event event
+ Endpoint endpoint
+ Namespace namespace
+ Secret secret
+ ResourceQuota resource_quota
+ LimitRange limit_range
+ PersistentVolume persistent_volume
+ PersistentVolumeClaim persistent_volume_claim
+ ComponentStatus component_status
+ ServiceAccount service_account
+ Project project
+ Route route
+ ClusterRoleBinding cluster_role_binding
+ Build build
+ BuildConfig build_config
+ Image image
+ ImageStream image_stream
+ dogstatsd dogstatsd
+ lowerCamelUPPERCase lower_camel_uppercase
+ HTTPAPISpecBinding httpapispec_binding
+ APIGroup apigroup
+ APIGroupList apigroup_list
+ APIResourceList apiresource_list
+ APIService apiservice
+ APIServiceList apiservice_list
+ APIVersions apiversions
+ OAuthAccessToken oauth_access_token
+ OAuthAccessTokenList oauth_access_token_list
+ OAuthAuthorizeToken oauth_authorize_token
+ OAuthAuthorizeTokenList oauth_authorize_token_list
+ OAuthClient oauth_client
+ OAuthClientAuthorization oauth_client_authorization
+ OAuthClientAuthorizationList oauth_client_authorization_list
+ OAuthClientList oauth_client_list
+ ].each_slice(2) do |kind, expected_underscore|
+ underscore = Kubeclient::ClientMixin.underscore_entity(kind)
+ assert_equal(underscore, expected_underscore)
+ end
+ end
+
+ def test_format_datetime_with_string
+ value = '2018-04-27T18:30:17.480321984Z'
+ formatted = client.send(:format_datetime, value)
+ assert_equal(formatted, value)
+ end
+
+ def test_format_datetime_with_datetime
+ value = DateTime.new(2018, 4, 30, 19, 20, 33)
+ formatted = client.send(:format_datetime, value)
+ assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
+ end
+
+ def test_format_datetime_with_time
+ value = Time.new(2018, 4, 30, 19, 20, 33, 0)
+ formatted = client.send(:format_datetime, value)
+ assert_equal(formatted, '2018-04-30T19:20:33.000000000+00:00')
+ end
+
+ def test_parse_definition_with_unconventional_names
+ %w[
+ PluralPolicy pluralpolicies plural_policy plural_policies
+ LatinDatum latindata latin_datum latin_data
+ Noseparator noseparators noseparator noseparators
+ lowercase lowercases lowercase lowercases
+ TestWithDash test-with-dashes test_with_dash test_with_dashes
+ TestUnderscore test_underscores test_underscore test_underscores
+ TestMismatch other-odd-name testmismatch otheroddname
+ MixedDashMinus mixed-dash_minuses mixed_dash_minus mixed_dash_minuses
+ SameUptoWordboundary sameup-toword-boundarys sameuptowordboundary sameuptowordboundarys
+ ].each_slice(4) do |kind, plural, expected_single, expected_plural|
+ method_names = Kubeclient::ClientMixin.parse_definition(kind, plural).method_names
+ assert_equal(method_names[0], expected_single)
+ assert_equal(method_names[1], expected_plural)
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_common_url_handling.rb b/vendor/gems/kubeclient/test/test_common_url_handling.rb
new file mode 100644
index 00000000000..e7798c2f489
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_common_url_handling.rb
@@ -0,0 +1,160 @@
+require_relative 'test_helper'
+
+# URLHandling tests
+class TestCommonUrlHandling < MiniTest::Test
+ def test_no_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_with_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/api', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_with_api_path_in_uri_other_version
+ client = Kubeclient::Client.new('http://localhost:8080/api', 'v2')
+ rest_client = client.rest_client
+ assert_equal('v2', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/api/v2', rest_client.url.to_s)
+ end
+
+ def test_with_api_group_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/apis/this_is_the_group', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/apis/this_is_the_group/v1', rest_client.url.to_s)
+ end
+
+ def test_with_api_group_path_in_uri_other_version
+ client = Kubeclient::Client.new('http://localhost:8080/apis/this_is_the_group', 'v2')
+ rest_client = client.rest_client
+ assert_equal('v2', client.instance_variable_get(:@api_version))
+ assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/apis/this_is_the_group/v2', rest_client.url.to_s)
+ end
+
+ def test_with_api_path_in_uri_trailing_slash
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_with_api_path_in_api
+ client = Kubeclient::Client.new('http://localhost:8080/api/but/I/want/a/hidden/k8s/api', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/api/but/I/want/a/hidden/k8s/api/v1', rest_client.url.to_s)
+ end
+
+ def test_with_api_group_path_in_api
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/but/I/want/a/hidden/k8s/apis/this_is_the_group',
+ 'v1'
+ )
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
+ assert_equal(
+ 'http://localhost:8080/api/but/I/want/a/hidden/k8s/apis/this_is_the_group/v1',
+ rest_client.url.to_s
+ )
+ end
+
+ def test_rancher_with_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/api', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
+ end
+
+ def test_rancher_no_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
+ end
+
+ def test_rancher_no_api_path_in_uri_trailing_slash
+ client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
+ end
+
+ def test_rancher_with_api_path_in_uri_trailing_slash
+ client = Kubeclient::Client.new('http://localhost:8080/k8s/clusters/c-somerancherID/api/', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/k8s/clusters/c-somerancherID/api/v1', rest_client.url.to_s)
+ end
+
+ def test_rancher_with_api_group_in_uri_trailing_slash
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/k8s/clusters/c-somerancherID/apis/this_is_the_group',
+ 'v1'
+ )
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('this_is_the_group/', client.instance_variable_get(:@api_group))
+ assert_equal(
+ 'http://localhost:8080/k8s/clusters/c-somerancherID/apis/this_is_the_group/v1',
+ rest_client.url.to_s
+ )
+ end
+
+ def test_with_openshift_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/oapi', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/oapi/v1', rest_client.url.to_s)
+ end
+
+ def test_arbitrary_path_with_openshift_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/foobarbaz/oapi', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/foobarbaz/oapi/v1', rest_client.url.to_s)
+ end
+
+ def test_with_openshift_api_path_in_uri_trailing_slash
+ client = Kubeclient::Client.new('http://localhost:8080/oapi/', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/oapi/v1', rest_client.url.to_s)
+ end
+
+ def test_with_arbitrary_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/foobarbaz', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/foobarbaz/api/v1', rest_client.url.to_s)
+ end
+
+ def test_with_arbitrary_and_api_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080/foobarbaz/api', 'v1')
+ rest_client = client.rest_client
+ assert_equal('v1', client.instance_variable_get(:@api_version))
+ assert_equal('', client.instance_variable_get(:@api_group))
+ assert_equal('http://localhost:8080/foobarbaz/api/v1', rest_client.url.to_s)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_component_status.rb b/vendor/gems/kubeclient/test/test_component_status.rb
new file mode 100644
index 00000000000..7bb4ca1ad51
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_component_status.rb
@@ -0,0 +1,29 @@
+require_relative 'test_helper'
+
+# ComponentStatus tests
+class TestComponentStatus < MiniTest::Test
+ def test_get_from_json_v3
+ stub_core_api_list
+ stub_request(:get, %r{/componentstatuses})
+ .to_return(body: open_test_file('component_status.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ component_status = client.get_component_status('etcd-0', 'default')
+
+ assert_instance_of(Kubeclient::Resource, component_status)
+ assert_equal('etcd-0', component_status.metadata.name)
+ assert_equal('Healthy', component_status.conditions[0].type)
+ assert_equal('True', component_status.conditions[0].status)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/namespaces/default/componentstatuses/etcd-0',
+ times: 1
+ )
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_config.rb b/vendor/gems/kubeclient/test/test_config.rb
new file mode 100644
index 00000000000..d47827e0393
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_config.rb
@@ -0,0 +1,271 @@
+require_relative 'test_helper'
+require 'yaml'
+require 'open3'
+
+# Testing Kubernetes client configuration
+class KubeclientConfigTest < MiniTest::Test
+ def test_allinone
+ config = Kubeclient::Config.read(config_file('allinone.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
+ end
+
+ def test_external
+ config = Kubeclient::Config.read(config_file('external.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
+ end
+
+ def test_explicit_secure
+ config = Kubeclient::Config.read(config_file('secure.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ # Same as external.kubeconfig, but with explicit `insecure-skip-tls-verify: false`
+ check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
+ end
+
+ def test_external_public_ca
+ config = Kubeclient::Config.read(config_file('external-without-ca.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ # Same as external.kubeconfig, no custom CA data (cluster has a publicly trusted cert)
+ check_context(config.context, ssl: true, custom_ca: false, client_cert: true)
+ end
+
+ def test_secure_public_ca
+ config = Kubeclient::Config.read(config_file('secure-without-ca.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ # no custom CA data + explicit `insecure-skip-tls-verify: false`
+ check_context(config.context, ssl: true, custom_ca: false, client_cert: true)
+ end
+
+ def test_insecure
+ config = Kubeclient::Config.read(config_file('insecure.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ # Has explicit `insecure-skip-tls-verify: false`
+ check_context(config.context, ssl: false, custom_ca: false, client_cert: true)
+ end
+
+ def test_insecure_custom_ca
+ config = Kubeclient::Config.read(config_file('insecure-custom-ca.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ # Has explicit `insecure-skip-tls-verify: false`
+ check_context(config.context, ssl: false, custom_ca: true, client_cert: true)
+ end
+
+ def test_allinone_nopath
+ yaml = File.read(config_file('allinone.kubeconfig'))
+ # A self-contained config shouldn't depend on kcfg_path.
+ config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
+ assert_equal(['Default'], config.contexts)
+ check_context(config.context, ssl: true, custom_ca: true, client_cert: true)
+ end
+
+ def test_external_nopath
+ yaml = File.read(config_file('external.kubeconfig'))
+ # kcfg_path = nil should prevent file access
+ config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
+ assert_raises(StandardError) do
+ config.context
+ end
+ end
+
+ def test_external_nopath_absolute
+ yaml = File.read(config_file('external.kubeconfig'))
+ # kcfg_path = nil should prevent file access, even if absolute path specified
+ ca_absolute_path = File.absolute_path(config_file('external-'))
+ yaml = yaml.gsub('external-', ca_absolute_path)
+ config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
+ assert_raises(StandardError) do
+ config.context
+ end
+ end
+
+ def test_concatenated_ca
+ config = Kubeclient::Config.read(config_file('concatenated-ca.kubeconfig'))
+ assert_equal(['Default'], config.contexts)
+ check_context(config.context, ssl: true)
+ end
+
+ def test_nouser
+ config = Kubeclient::Config.read(config_file('nouser.kubeconfig'))
+ assert_equal(['default/localhost:6443/nouser'], config.contexts)
+ check_context(config.context, ssl: true, custom_ca: false, client_cert: false)
+ end
+
+ def test_user_token
+ config = Kubeclient::Config.read(config_file('userauth.kubeconfig'))
+ assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'],
+ config.contexts)
+ context = config.context('localhost/system:admin:token')
+ check_context(context, ssl: true, custom_ca: false, client_cert: false)
+ assert_equal('0123456789ABCDEF0123456789ABCDEF', context.auth_options[:bearer_token])
+ end
+
+ def test_user_password
+ config = Kubeclient::Config.read(config_file('userauth.kubeconfig'))
+ assert_equal(['localhost/system:admin:token', 'localhost/system:admin:userpass'],
+ config.contexts)
+ context = config.context('localhost/system:admin:userpass')
+ check_context(context, ssl: true, custom_ca: false, client_cert: false)
+ assert_equal('admin', context.auth_options[:username])
+ assert_equal('pAssw0rd123', context.auth_options[:password])
+ end
+
+ def test_timestamps
+ # Test YAML parsing doesn't crash on YAML timestamp syntax.
+ Kubeclient::Config.read(config_file('timestamps.kubeconfig'))
+ end
+
+ def test_user_exec
+ token = '0123456789ABCDEF0123456789ABCDEF'
+ creds = {
+ 'apiVersion': 'client.authentication.k8s.io/v1beta1',
+ 'status': {
+ 'token': token
+ }
+ }
+
+ config = Kubeclient::Config.read(config_file('execauth.kubeconfig'))
+ assert_equal(['localhost/system:admin:exec-search-path',
+ 'localhost/system:admin:exec-relative-path',
+ 'localhost/system:admin:exec-absolute-path'],
+ config.contexts)
+
+ # A bare command name in config means search PATH, so it's executed as bare command.
+ stub_exec(%r{^example-exec-plugin$}, creds) do
+ context = config.context('localhost/system:admin:exec-search-path')
+ check_context(context, ssl: true, custom_ca: false, client_cert: false)
+ assert_equal(token, context.auth_options[:bearer_token])
+ end
+
+ # A relative path is taken relative to the dir of the kubeconfig.
+ stub_exec(%r{.*config/dir/example-exec-plugin$}, creds) do
+ context = config.context('localhost/system:admin:exec-relative-path')
+ check_context(context, ssl: true, custom_ca: false, client_cert: false)
+ assert_equal(token, context.auth_options[:bearer_token])
+ end
+
+ # An absolute path is taken as-is.
+ stub_exec(%r{^/abs/path/example-exec-plugin$}, creds) do
+ context = config.context('localhost/system:admin:exec-absolute-path')
+ check_context(context, ssl: true, custom_ca: false, client_cert: false)
+ assert_equal(token, context.auth_options[:bearer_token])
+ end
+ end
+
+ def test_user_exec_nopath
+ yaml = File.read(config_file('execauth.kubeconfig'))
+ config = Kubeclient::Config.new(YAML.safe_load(yaml), nil)
+ config.contexts.each do |context_name|
+ Open3.stub(:capture3, proc { flunk 'should not execute command' }) do
+ assert_raises(StandardError) do
+ config.context(context_name)
+ end
+ end
+ end
+ end
+
+ def test_gcp_default_auth
+ Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token1').once
+ parsed = load_yaml(config_file('gcpauth.kubeconfig'))
+ config = Kubeclient::Config.new(parsed, nil)
+ config.context(config.contexts.first)
+ end
+
+ # Each call to .context() obtains a new token, calling .auth_options doesn't change anything.
+ # NOTE: this is not a guarantee, may change, just testing current behavior.
+ def test_gcp_default_auth_renew
+ Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token1').once
+ parsed = load_yaml(config_file('gcpauth.kubeconfig'))
+ config = Kubeclient::Config.new(parsed, nil)
+ context = config.context(config.contexts.first)
+ assert_equal({ bearer_token: 'token1' }, context.auth_options)
+ assert_equal({ bearer_token: 'token1' }, context.auth_options)
+
+ Kubeclient::GoogleApplicationDefaultCredentials.expects(:token).returns('token2').once
+ context2 = config.context(config.contexts.first)
+ assert_equal({ bearer_token: 'token2' }, context2.auth_options)
+ assert_equal({ bearer_token: 'token1' }, context.auth_options)
+ end
+
+ def test_gcp_command_auth
+ Kubeclient::GCPCommandCredentials.expects(:token)
+ .with('access-token' => '<fake_token>',
+ 'cmd-args' => 'config config-helper --format=json',
+ 'cmd-path' => '/path/to/gcloud',
+ 'expiry' => '2019-04-09 19:26:18 UTC',
+ 'expiry-key' => '{.credential.token_expiry}',
+ 'token-key' => '{.credential.access_token}')
+ .returns('token1')
+ .once
+ config = Kubeclient::Config.read(config_file('gcpcmdauth.kubeconfig'))
+ config.context(config.contexts.first)
+ end
+
+ def test_oidc_auth_provider
+ Kubeclient::OIDCAuthProvider.expects(:token)
+ .with('client-id' => 'fake-client-id',
+ 'client-secret' => 'fake-client-secret',
+ 'id-token' => 'fake-id-token',
+ 'idp-issuer-url' => 'https://accounts.google.com',
+ 'refresh-token' => 'fake-refresh-token')
+ .returns('token1')
+ .once
+ parsed = YAML.safe_load(File.read(config_file('oidcauth.kubeconfig')))
+ config = Kubeclient::Config.new(parsed, nil)
+ config.context(config.contexts.first)
+ end
+
+ private
+
+ def check_context(context, ssl: true, custom_ca: true, client_cert: true)
+ assert_equal('https://localhost:6443', context.api_endpoint)
+ assert_equal('v1', context.api_version)
+ assert_equal('default', context.namespace)
+ if custom_ca
+ assert_kind_of(OpenSSL::X509::Store, context.ssl_options[:cert_store])
+ else
+ assert_nil(context.ssl_options[:cert_store])
+ end
+ if client_cert
+ assert_kind_of(OpenSSL::X509::Certificate, context.ssl_options[:client_cert])
+ assert_kind_of(OpenSSL::PKey::RSA, context.ssl_options[:client_key])
+ if custom_ca
+ # When certificates expire one way to recreate them is using a k0s single-node cluster:
+ # test/config/update_certs_k0s.rb
+ assert(context.ssl_options[:cert_store].verify(context.ssl_options[:client_cert]))
+ end
+ else
+ assert_nil(context.ssl_options[:client_cert])
+ assert_nil(context.ssl_options[:client_key])
+ end
+ if ssl
+ assert_equal(OpenSSL::SSL::VERIFY_PEER, context.ssl_options[:verify_ssl],
+ 'expected VERIFY_PEER')
+ else
+ assert_equal(OpenSSL::SSL::VERIFY_NONE, context.ssl_options[:verify_ssl],
+ 'expected VERIFY_NONE')
+ end
+ end
+
+ def stub_exec(command_regexp, creds)
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ capture3_stub = lambda do |_env, command, *_args|
+ assert_match command_regexp, command
+ [JSON.dump(creds), nil, st]
+ end
+
+ Open3.stub(:capture3, capture3_stub) do
+ yield
+ end
+ end
+
+ def load_yaml(file_name)
+ if RUBY_VERSION >= '2.6'
+ YAML.safe_load(File.read(file_name), permitted_classes: [Date, Time])
+ else
+ YAML.safe_load(File.read(file_name), [Date, Time])
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_endpoint.rb b/vendor/gems/kubeclient/test/test_endpoint.rb
new file mode 100644
index 00000000000..ec2cd9306d4
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_endpoint.rb
@@ -0,0 +1,54 @@
+require_relative 'test_helper'
+
+# kind: 'Endpoints' entity tests.
+# This is one of the unusual `kind`s that are already plural (https://github.com/kubernetes/kubernetes/issues/8115).
+# We force singular in method names like 'create_endpoint',
+# but `kind` should remain plural as in kubernetes.
+class TestEndpoint < MiniTest::Test
+ def test_create_endpoint
+ stub_core_api_list
+ testing_ep = Kubeclient::Resource.new
+ testing_ep.metadata = {}
+ testing_ep.metadata.name = 'myendpoint'
+ testing_ep.metadata.namespace = 'default'
+ testing_ep.subsets = [
+ {
+ 'addresses' => [{ 'ip' => '172.17.0.25' }],
+ 'ports' => [{ 'name' => 'https', 'port' => 6443, 'protocol' => 'TCP' }]
+ }
+ ]
+
+ req_body = '{"metadata":{"name":"myendpoint","namespace":"default"},' \
+ '"subsets":[{"addresses":[{"ip":"172.17.0.25"}],"ports":[{"name":"https",' \
+ '"port":6443,"protocol":"TCP"}]}],"kind":"Endpoints","apiVersion":"v1"}'
+
+ stub_request(:post, 'http://localhost:8080/api/v1/namespaces/default/endpoints')
+ .with(body: req_body)
+ .to_return(body: open_test_file('created_endpoint.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ created_ep = client.create_endpoint(testing_ep)
+ assert_equal('Endpoints', created_ep.kind)
+ assert_equal('v1', created_ep.apiVersion)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', as: :parsed_symbolized)
+ created_ep = client.create_endpoint(testing_ep)
+ assert_equal('Endpoints', created_ep[:kind])
+ assert_equal('v1', created_ep[:apiVersion])
+ end
+
+ def test_get_endpoints
+ stub_core_api_list
+ stub_request(:get, %r{/endpoints})
+ .to_return(body: open_test_file('endpoint_list.json'), status: 200)
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ collection = client.get_endpoints(as: :parsed_symbolized)
+ assert_equal('EndpointsList', collection[:kind])
+ assert_equal('v1', collection[:apiVersion])
+
+ # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
+ collection = client.get_endpoints
+ assert_equal('Endpoints', collection.kind)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_exec_credentials.rb b/vendor/gems/kubeclient/test/test_exec_credentials.rb
new file mode 100644
index 00000000000..f0e51827f55
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_exec_credentials.rb
@@ -0,0 +1,225 @@
+require_relative 'test_helper'
+require 'open3'
+
+# Unit tests for the ExecCredentials provider
+class ExecCredentialsTest < MiniTest::Test
+ def test_exec_opts_missing
+ expected_msg =
+ 'exec options are required'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::ExecCredentials.run(nil)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_exec_command_missing
+ expected_msg =
+ 'exec command is required'
+ exception = assert_raises(KeyError) do
+ Kubeclient::ExecCredentials.run({})
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_exec_command_failure
+ err = 'Error'
+ expected_msg =
+ "exec command failed: #{err}"
+
+ st = Minitest::Mock.new
+ st.expect(:success?, false)
+
+ opts = { 'command' => 'dummy' }
+
+ Open3.stub(:capture3, [nil, err, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_run_with_token_credentials
+ opts = { 'command' => 'dummy' }
+
+ credentials = {
+ 'token' => '0123456789ABCDEF0123456789ABCDEF'
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => credentials
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ assert_equal(credentials, Kubeclient::ExecCredentials.run(opts))
+ end
+ end
+
+ def test_run_with_client_credentials
+ opts = { 'command' => 'dummy' }
+
+ credentials = {
+ 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF',
+ 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF'
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => credentials
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ assert_equal(credentials, Kubeclient::ExecCredentials.run(opts))
+ end
+ end
+
+ def test_run_with_missing_client_certificate_data
+ opts = { 'command' => 'dummy' }
+
+ credentials = {
+ 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF'
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => credentials
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = 'exec plugin didn\'t return client certificate data'
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_run_with_missing_client_key_data
+ opts = { 'command' => 'dummy' }
+
+ credentials = {
+ 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF'
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => credentials
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = 'exec plugin didn\'t return client key data'
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_run_with_client_data_and_token
+ opts = { 'command' => 'dummy' }
+
+ credentials = {
+ 'clientCertificateData' => '0123456789ABCDEF0123456789ABCDEF',
+ 'clientKeyData' => '0123456789ABCDEF0123456789ABCDEF',
+ 'token' => '0123456789ABCDEF0123456789ABCDEF'
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => credentials
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = 'exec plugin returned both token and client data'
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_status_missing
+ opts = { 'command' => 'dummy' }
+
+ creds = JSON.dump('apiVersion' => 'client.authentication.k8s.io/v1alpha1')
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = 'exec plugin didn\'t return a status field'
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_credentials_missing
+ opts = { 'command' => 'dummy' }
+
+ creds = JSON.dump(
+ 'apiVersion' => 'client.authentication.k8s.io/v1alpha1',
+ 'status' => {}
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = 'exec plugin didn\'t return a token or client data'
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+
+ def test_api_version_mismatch
+ api_version = 'client.authentication.k8s.io/v1alpha1'
+ expected_version = 'client.authentication.k8s.io/v1beta1'
+
+ opts = {
+ 'command' => 'dummy',
+ 'apiVersion' => expected_version
+ }
+
+ creds = JSON.dump(
+ 'apiVersion' => api_version
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ expected_msg = "exec plugin is configured to use API version #{expected_version}," \
+ " plugin returned version #{api_version}"
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ exception = assert_raises(RuntimeError) do
+ Kubeclient::ExecCredentials.run(opts)
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb b/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb
new file mode 100644
index 00000000000..f95b8fd045e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_gcp_command_credentials.rb
@@ -0,0 +1,27 @@
+require_relative 'test_helper'
+require 'open3'
+
+# Unit tests for the GCPCommandCredentials token provider
+class GCPCommandCredentialsTest < MiniTest::Test
+ def test_token
+ opts = { 'cmd-args' => 'config config-helper --format=json',
+ 'cmd-path' => '/path/to/gcloud',
+ 'expiry-key' => '{.credential.token_expiry}',
+ 'token-key' => '{.credential.access_token}' }
+
+ creds = JSON.dump(
+ 'credential' => {
+ 'access_token' => '9A3A941836F2458175BE18AA1971EBBF47949B07',
+ 'token_expiry' => '2019-04-12T15:02:51Z'
+ }
+ )
+
+ st = Minitest::Mock.new
+ st.expect(:success?, true)
+
+ Open3.stub(:capture3, [creds, nil, st]) do
+ assert_equal('9A3A941836F2458175BE18AA1971EBBF47949B07',
+ Kubeclient::GCPCommandCredentials.token(opts))
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb b/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb
new file mode 100644
index 00000000000..238ae729c16
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_google_application_default_credentials.rb
@@ -0,0 +1,15 @@
+require_relative 'test_helper'
+require 'googleauth'
+
+# Unit tests for the ApplicationDefaultCredentials token provider
+class GoogleApplicationDefaultCredentialsTest < MiniTest::Test
+ def test_token
+ auth = Minitest::Mock.new
+ auth.expect(:apply, nil, [{}])
+ auth.expect(:access_token, 'valid_token')
+
+ Google::Auth.stub(:get_application_default, auth) do
+ assert_equal('valid_token', Kubeclient::GoogleApplicationDefaultCredentials.token)
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_guestbook_go.rb b/vendor/gems/kubeclient/test/test_guestbook_go.rb
new file mode 100644
index 00000000000..a50e192a0c5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_guestbook_go.rb
@@ -0,0 +1,237 @@
+require_relative 'test_helper'
+require 'vcr'
+
+# creation of google's example of guest book
+class CreateGuestbookGo < MiniTest::Test
+ def test_create_guestbook_entities
+ VCR.configure do |c|
+ c.cassette_library_dir = 'test/cassettes'
+ c.hook_into(:webmock)
+ end
+
+ # WebMock.allow_net_connect!
+ VCR.use_cassette('kubernetes_guestbook') do # , record: :new_episodes) do
+ client = Kubeclient::Client.new('http://10.35.0.23:8080/api/', 'v1')
+
+ testing_ns = Kubeclient::Resource.new
+ testing_ns.metadata = {}
+ testing_ns.metadata.name = 'kubeclient-ns'
+
+ # delete in case they existed before so creation can be tested
+ delete_namespace(client, testing_ns.metadata.name)
+ delete_services(
+ client, testing_ns.metadata.name,
+ ['guestbook', 'redis-master', 'redis-slave']
+ )
+ delete_replication_controllers(
+ client, testing_ns.metadata.name,
+ ['guestbook', 'redis-master', 'redis-slave']
+ )
+
+ client.create_namespace(testing_ns)
+ services = create_services(client, testing_ns.metadata.name)
+ replicators = create_replication_controllers(client, testing_ns.metadata.name)
+
+ get_namespaces(client)
+ get_services(client, testing_ns.metadata.name)
+ get_replication_controllers(client, testing_ns.metadata.name)
+
+ delete_services(client, testing_ns.metadata.name, services)
+ delete_replication_controllers(client, testing_ns.metadata.name, replicators)
+
+ client.delete_namespace(testing_ns.metadata.name)
+ end
+ ensure
+ VCR.turn_off!
+ end
+
+ def delete_namespace(client, namespace_name)
+ client.delete_namespace(namespace_name)
+ rescue Kubeclient::ResourceNotFoundError => exception
+ assert_equal(404, exception.error_code)
+ end
+
+ def get_namespaces(client)
+ namespaces = client.get_namespaces
+ assert(true, namespaces.size > 2)
+ end
+
+ def get_services(client, ns)
+ retrieved_services = client.get_services(namespace: ns)
+ assert_equal(3, retrieved_services.size)
+ end
+
+ def get_replication_controllers(client, ns)
+ retrieved_replicators = client.get_replication_controllers(namespace: ns)
+ assert_equal(3, retrieved_replicators.size)
+ end
+
+ def create_services(client, ns)
+ guestbook_service = client.create_service(guestbook_service(ns))
+ redis_service = client.create_service(redis_service(ns))
+ redis_slave_service = client.create_service(redis_slave_service(ns))
+ [guestbook_service, redis_service, redis_slave_service]
+ end
+
+ def create_replication_controllers(client, namespace)
+ rc = client.create_replication_controller(guestbook_rc(namespace))
+ rc2 = client.create_replication_controller(redis_master_rc(namespace))
+ rc3 = client.create_replication_controller(redis_slave_rc(namespace))
+ [rc, rc2, rc3]
+ end
+
+ def delete_services(client, namespace, services)
+ # if the entity is not found, no need to fail the test
+ services.each do |service|
+ begin
+ if service.instance_of?(Kubeclient::Resource)
+ client.delete_service(service.metadata.name, namespace)
+ else
+ # it's just a string - service name
+ client.delete_service(service, namespace)
+ end
+ rescue Kubeclient::ResourceNotFoundError => exception
+ assert_equal(404, exception.error_code)
+ end
+ end
+ end
+
+ def delete_replication_controllers(client, namespace, replication_controllers)
+ # if the entity is not found, no need to fail the test
+ replication_controllers.each do |rc|
+ begin
+ if rc.instance_of?(Kubeclient::Resource)
+ client.delete_replication_controller(rc.metadata.name, namespace)
+ else
+ # it's just a string - rc name
+ client.delete_replication_controller(rc, namespace)
+ end
+ rescue Kubeclient::ResourceNotFoundError => exception
+ assert_equal(404, exception.error_code)
+ end
+ end
+ end
+
+ private
+
+ def construct_base_rc(namespace)
+ rc = Kubeclient::Resource.new
+ rc.metadata = {}
+ rc.metadata.namespace = namespace
+ rc.metadata.labels = {}
+ rc.spec = {}
+ rc.spec.selector = {}
+ rc.spec.template = {}
+ rc.spec.template.metadata = {}
+ rc.spec.template.spec = {}
+ rc.spec.template.metadata.labels = {}
+ rc
+ end
+
+ def redis_master_rc(namespace)
+ rc = construct_base_rc(namespace)
+ rc.metadata.name = 'redis-master'
+ rc.metadata.labels.app = 'redis'
+ rc.metadata.labels.role = 'master'
+ rc.spec.replicas = 1
+ rc.spec.selector.app = 'redis'
+ rc.spec.selector.role = 'master'
+ rc.spec.template.metadata.labels.app = 'redis'
+ rc.spec.template.metadata.labels.role = 'master'
+ rc.spec.template.spec.containers = [{
+ 'name' => 'redis-master',
+ 'image' => 'redis',
+ 'ports' => [{
+ 'name' => 'redis-server',
+ 'containerPort' => 6379
+ }]
+ }]
+ rc
+ end
+
+ def redis_slave_rc(namespace)
+ rc = construct_base_rc(namespace)
+ rc.metadata.name = 'redis-slave'
+ rc.metadata.labels.app = 'redis'
+ rc.metadata.labels.role = 'slave'
+ rc.spec.replicas = 2
+ rc.spec.selector.app = 'redis'
+ rc.spec.selector.role = 'slave'
+ rc.spec.template.metadata.labels.app = 'redis'
+ rc.spec.template.metadata.labels.role = 'slave'
+ rc.spec.template.spec.containers = [{
+ 'name' => 'redis-slave',
+ 'image' => 'kubernetes/redis-slave:v2',
+ 'ports' => [{
+ 'name' => 'redis-server',
+ 'containerPort' => 6379
+ }]
+ }]
+ rc
+ end
+
+ def guestbook_rc(namespace)
+ rc = construct_base_rc(namespace)
+ rc.metadata.name = 'guestbook'
+ rc.metadata.labels.app = 'guestbook'
+ rc.metadata.labels.role = 'slave'
+ rc.spec.replicas = 3
+ rc.spec.selector.app = 'guestbook'
+ rc.spec.template.metadata.labels.app = 'guestbook'
+ rc.spec.template.spec.containers = [
+ {
+ 'name' => 'guestbook',
+ 'image' => 'kubernetes/guestbook:v2',
+ 'ports' => [
+ {
+ 'name' => 'http-server',
+ 'containerPort' => 3000
+ }
+ ]
+ }
+ ]
+ rc
+ end
+
+ def base_service(namespace)
+ our_service = Kubeclient::Resource.new
+ our_service.metadata = {}
+ our_service.metadata.namespace = namespace
+ our_service.metadata.labels = {}
+ our_service.spec = {}
+ our_service.spec.selector = {}
+ our_service
+ end
+
+ def redis_slave_service(namespace)
+ our_service = base_service(namespace)
+ our_service.metadata.name = 'redis-slave'
+ our_service.metadata.labels.app = 'redis'
+ our_service.metadata.labels.role = 'slave'
+ our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }]
+ our_service.spec.selector.app = 'redis'
+ our_service.spec.selector.role = 'slave'
+ our_service
+ end
+
+ def redis_service(namespace)
+ our_service = base_service(namespace)
+ our_service.metadata.name = 'redis-master'
+ our_service.metadata.labels.app = 'redis'
+ our_service.metadata.labels.role = 'master'
+ our_service.spec.ports = [{ 'port' => 6379, 'targetPort' => 'redis-server' }]
+ our_service.spec.selector.app = 'redis'
+ our_service.spec.selector.role = 'master'
+ our_service
+ end
+
+ def guestbook_service(namespace)
+ our_service = base_service(namespace)
+ our_service.metadata.name = 'guestbook'
+ our_service.metadata.labels.name = 'guestbook'
+ our_service.spec.ports = [{ 'port' => 3000, 'targetPort' => 'http-server' }]
+ our_service.spec.selector.app = 'guestbook'
+ our_service.type = 'LoadBalancer'
+ our_service
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_helper.rb b/vendor/gems/kubeclient/test/test_helper.rb
new file mode 100644
index 00000000000..042a08a0d80
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_helper.rb
@@ -0,0 +1,28 @@
+require 'bundler/setup'
+require 'minitest/autorun'
+require 'minitest/rg'
+require 'webmock/minitest'
+require 'mocha/minitest'
+require 'json'
+require 'kubeclient'
+
+MiniTest::Test.class_eval do
+ # Assumes test files will be in a subdirectory with the same name as the
+ # file suffix. e.g. a file named foo.json would be a "json" subdirectory.
+ def open_test_file(name)
+ File.new(File.join(File.dirname(__FILE__), name.split('.').last, name))
+ end
+
+ # kubeconfig files deviate from above convention.
+ # They link to relaved certs etc. with various extensions, all in same dir.
+ def config_file(name)
+ File.join(File.dirname(__FILE__), 'config', name)
+ end
+
+ def stub_core_api_list
+ stub_request(:get, %r{/api/v1$})
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
+ end
+end
+
+WebMock.disable_net_connect!
diff --git a/vendor/gems/kubeclient/test/test_kubeclient.rb b/vendor/gems/kubeclient/test/test_kubeclient.rb
new file mode 100644
index 00000000000..f866bfc89df
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_kubeclient.rb
@@ -0,0 +1,881 @@
+require_relative 'test_helper'
+
+# Kubernetes client entity tests
+class KubeclientTest < MiniTest::Test
+ def test_json
+ our_object = Kubeclient::Resource.new
+ our_object.foo = 'bar'
+ our_object.nested = {}
+ our_object.nested.again = {}
+ our_object.nested.again.again = {}
+ our_object.nested.again.again.name = 'aaron'
+
+ expected = {
+ 'foo' => 'bar',
+ 'nested' => { 'again' => { 'again' => { 'name' => 'aaron' } } }
+ }
+
+ assert_equal(expected, JSON.parse(JSON.dump(our_object.to_h)))
+ end
+
+ def test_pass_uri
+ # URI::Generic#hostname= was added in ruby 1.9.3 and will automatically
+ # wrap an ipv6 address in []
+ uri = URI::HTTP.build(port: 8080)
+ uri.hostname = 'localhost'
+ client = Kubeclient::Client.new(uri)
+ rest_client = client.rest_client
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_no_path_in_uri
+ client = Kubeclient::Client.new('http://localhost:8080', 'v1')
+ rest_client = client.rest_client
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_no_version_passed
+ client = Kubeclient::Client.new('http://localhost:8080')
+ rest_client = client.rest_client
+ assert_equal('http://localhost:8080/api/v1', rest_client.url.to_s)
+ end
+
+ def test_pass_proxy
+ uri = URI::HTTP.build(host: 'localhost', port: 8080)
+ proxy_uri = URI::HTTP.build(host: 'myproxyhost', port: 8888)
+ stub_core_api_list
+
+ client = Kubeclient::Client.new(uri, http_proxy_uri: proxy_uri)
+ rest_client = client.rest_client
+ assert_equal(proxy_uri.to_s, rest_client.options[:proxy])
+
+ watch_client = client.watch_pods
+ assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_address], proxy_uri.host)
+ assert_equal(watch_client.send(:build_client_options)[:proxy][:proxy_port], proxy_uri.port)
+ end
+
+ def test_pass_max_redirects
+ max_redirects = 0
+ client = Kubeclient::Client.new('http://localhost:8080/api/', http_max_redirects: max_redirects)
+ rest_client = client.rest_client
+ assert_equal(max_redirects, rest_client.options[:max_redirects])
+
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 302, headers: { location: 'http://localhost:1234/api' })
+
+ exception = assert_raises(Kubeclient::HttpError) { client.api }
+ assert_equal(302, exception.error_code)
+ end
+
+ def test_exception
+ stub_core_api_list
+ stub_request(:post, %r{/services})
+ .to_return(body: open_test_file('namespace_exception.json'), status: 409)
+
+ service = Kubeclient::Resource.new
+ service.metadata = {}
+ service.metadata.name = 'redisslave'
+ service.metadata.namespace = 'default'
+ # service.port = 80
+ # service.container_port = 6379
+ # service.protocol = 'TCP'
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+
+ exception = assert_raises(Kubeclient::HttpError) do
+ service = client.create_service(service)
+ end
+
+ assert_instance_of(Kubeclient::HttpError, exception)
+ assert_equal("converting to : type names don't match (Pod, Namespace)",
+ exception.message)
+
+ assert_includes(exception.to_s, ' for POST http://localhost:8080/api')
+ assert_equal(409, exception.error_code)
+ end
+
+ def test_deprecated_exception
+ error_message = 'certificate verify failed'
+
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_raise(OpenSSL::SSL::SSLError.new(error_message))
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+
+ exception = assert_raises(KubeException) { client.api }
+ assert_equal(error_message, exception.message)
+ end
+
+ def test_api
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: open_test_file('versions_list.json'))
+
+ response = client.api
+ assert_includes(response, 'versions')
+ end
+
+ def test_api_ssl_failure
+ error_message = 'certificate verify failed'
+
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_raise(OpenSSL::SSL::SSLError.new(error_message))
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+
+ exception = assert_raises(Kubeclient::HttpError) { client.api }
+ assert_equal(error_message, exception.message)
+ end
+
+ def test_api_timeout
+ stub_request(:get, 'http://localhost:8080/api').to_timeout
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+
+ exception = assert_raises(Kubeclient::HttpError) { client.api }
+ assert_match(/(timed out|timeout)/i, exception.message)
+ end
+
+ def test_api_valid
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: open_test_file('versions_list.json'))
+
+ args = ['http://localhost:8080/api/']
+
+ [nil, 'v1beta3', 'v1'].each do |version|
+ client = Kubeclient::Client.new(*(version ? args + [version] : args))
+ assert client.api_valid?
+ end
+ end
+
+ def test_api_valid_with_invalid_version
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: open_test_file('versions_list.json'))
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'foobar1')
+ refute client.api_valid?
+ end
+
+ def test_api_valid_with_unreported_versions
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: '{}')
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ refute client.api_valid?
+ end
+
+ def test_api_valid_with_invalid_json
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: '[]')
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ refute client.api_valid?
+ end
+
+ def test_api_valid_with_bad_endpoint
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: [404, 'Resource Not Found'])
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ assert_raises(Kubeclient::HttpError) { client.api_valid? }
+ end
+
+ def test_api_valid_with_non_json
+ stub_request(:get, 'http://localhost:8080/api')
+ .to_return(status: 200, body: '<html></html>')
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ assert_raises(JSON::ParserError) { client.api_valid? }
+ end
+
+ def test_nonjson_exception
+ stub_core_api_list
+ stub_request(:get, %r{/servic})
+ .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
+
+ exception = assert_raises(Kubeclient::ResourceNotFoundError) do
+ client.get_services
+ end
+
+ assert(exception.message.include?('Not Found'))
+ assert_equal(404, exception.error_code)
+ end
+
+ def test_nonjson_exception_raw
+ stub_core_api_list
+ stub_request(:get, %r{/servic})
+ .to_return(body: open_test_file('service_illegal_json_404.json'), status: 404)
+
+ exception = assert_raises(Kubeclient::ResourceNotFoundError) do
+ client.get_services(as: :raw)
+ end
+
+ assert(exception.message.include?('Not Found'))
+ assert_equal(404, exception.error_code)
+ end
+
+ def test_entity_list
+ stub_core_api_list
+ stub_get_services
+
+ services = client.get_services
+
+ refute_empty(services)
+ assert_instance_of(Kubeclient::Common::EntityList, services)
+ # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
+ assert_equal('Service', services.kind)
+ assert_equal(2, services.size)
+ assert_instance_of(Kubeclient::Resource, services[0])
+ assert_instance_of(Kubeclient::Resource, services[1])
+
+ assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1)
+ end
+
+ def test_entity_list_raw
+ stub_core_api_list
+ stub_get_services
+
+ response = client.get_services(as: :raw)
+
+ refute_empty(response)
+ assert_equal(open_test_file('entity_list.json').read, response)
+
+ assert_requested(:get, 'http://localhost:8080/api/v1/services', times: 1)
+ end
+
+ def test_entity_list_parsed
+ stub_core_api_list
+ stub_get_services
+
+ response = client.get_services(as: :parsed)
+ assert_equal Hash, response.class
+ assert_equal 'ServiceList', response['kind']
+ assert_equal %w[metadata spec status], response['items'].first.keys
+ end
+
+ def test_entity_list_parsed_symbolized
+ stub_core_api_list
+ stub_get_services
+
+ response = client.get_services(as: :parsed_symbolized)
+ assert_equal Hash, response.class
+ assert_equal 'ServiceList', response[:kind]
+ assert_equal %i[metadata spec status], response[:items].first.keys
+ end
+
+ def test_entity_list_unknown
+ stub_core_api_list
+ stub_get_services
+
+ e = assert_raises(ArgumentError) { client.get_services(as: :whoops) }
+ assert_equal 'Unsupported format :whoops', e.message
+ end
+
+ def test_entity_list_raw_failure
+ stub_core_api_list
+ stub_request(:get, %r{/services})
+ .to_return(body: open_test_file('entity_list.json'), status: 500)
+
+ exception = assert_raises(Kubeclient::HttpError) { client.get_services(as: :raw) }
+ assert_equal('500 Internal Server Error', exception.message)
+ assert_equal(500, exception.error_code)
+ end
+
+ def test_entities_with_label_selector
+ selector = 'component=apiserver'
+
+ stub_core_api_list
+ stub_get_services
+
+ services = client.get_services(label_selector: selector)
+
+ assert_instance_of(Kubeclient::Common::EntityList, services)
+ assert_requested(
+ :get,
+ "http://localhost:8080/api/v1/services?labelSelector=#{selector}",
+ times: 1
+ )
+ end
+
+ def test_entities_with_resource_version
+ version = '329'
+
+ stub_core_api_list
+ stub_get_services
+
+ services = client.get_services(resource_version: version)
+
+ assert_instance_of(Kubeclient::Common::EntityList, services)
+ assert_requested(
+ :get,
+ "http://localhost:8080/api/v1/services?resourceVersion=#{version}",
+ times: 1
+ )
+ end
+
+ def test_entities_with_field_selector
+ selector = 'involvedObject.name=redis-master'
+
+ stub_core_api_list
+ stub_get_services
+
+ services = client.get_services(field_selector: selector)
+
+ assert_instance_of(Kubeclient::Common::EntityList, services)
+ assert_requested(
+ :get,
+ "http://localhost:8080/api/v1/services?fieldSelector=#{selector}",
+ times: 1
+ )
+ end
+
+ def test_empty_list
+ stub_core_api_list
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('empty_pod_list.json'), status: 200)
+
+ pods = client.get_pods
+ assert_instance_of(Kubeclient::Common::EntityList, pods)
+ assert_equal(0, pods.size)
+ end
+
+ def test_get_all
+ stub_core_api_list
+
+ stub_request(:get, %r{/bindings})
+ .to_return(body: open_test_file('bindings_list.json'), status: 404)
+
+ stub_request(:get, %r{/configmaps})
+ .to_return(body: open_test_file('config_map_list.json'), status: 200)
+
+ stub_request(:get, %r{/podtemplates})
+ .to_return(body: open_test_file('pod_template_list.json'), status: 200)
+
+ stub_request(:get, %r{/services})
+ .to_return(body: open_test_file('service_list.json'), status: 200)
+
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+
+ stub_request(:get, %r{/nodes})
+ .to_return(body: open_test_file('node_list.json'), status: 200)
+
+ stub_request(:get, %r{/replicationcontrollers})
+ .to_return(body: open_test_file('replication_controller_list.json'), status: 200)
+
+ stub_request(:get, %r{/events})
+ .to_return(body: open_test_file('event_list.json'), status: 200)
+
+ stub_request(:get, %r{/endpoints})
+ .to_return(body: open_test_file('endpoint_list.json'), status: 200)
+
+ stub_request(:get, %r{/namespaces})
+ .to_return(body: open_test_file('namespace_list.json'), status: 200)
+
+ stub_request(:get, %r{/secrets})
+ .to_return(body: open_test_file('secret_list.json'), status: 200)
+
+ stub_request(:get, %r{/resourcequotas})
+ .to_return(body: open_test_file('resource_quota_list.json'), status: 200)
+
+ stub_request(:get, %r{/limitranges})
+ .to_return(body: open_test_file('limit_range_list.json'), status: 200)
+
+ stub_request(:get, %r{/persistentvolumes})
+ .to_return(body: open_test_file('persistent_volume_list.json'), status: 200)
+
+ stub_request(:get, %r{/persistentvolumeclaims})
+ .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200)
+
+ stub_request(:get, %r{/componentstatuses})
+ .to_return(body: open_test_file('component_status_list.json'), status: 200)
+
+ stub_request(:get, %r{/serviceaccounts})
+ .to_return(body: open_test_file('service_account_list.json'), status: 200)
+
+ result = client.all_entities
+ assert_equal(16, result.keys.size)
+ assert_instance_of(Kubeclient::Common::EntityList, result['node'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['service'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['replication_controller'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['pod'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['event'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['namespace'])
+ assert_instance_of(Kubeclient::Common::EntityList, result['secret'])
+ assert_instance_of(Kubeclient::Resource, result['service'][0])
+ assert_instance_of(Kubeclient::Resource, result['node'][0])
+ assert_instance_of(Kubeclient::Resource, result['event'][0])
+ assert_instance_of(Kubeclient::Resource, result['endpoint'][0])
+ assert_instance_of(Kubeclient::Resource, result['namespace'][0])
+ assert_instance_of(Kubeclient::Resource, result['secret'][0])
+ assert_instance_of(Kubeclient::Resource, result['resource_quota'][0])
+ assert_instance_of(Kubeclient::Resource, result['limit_range'][0])
+ assert_instance_of(Kubeclient::Resource, result['persistent_volume'][0])
+ assert_instance_of(Kubeclient::Resource, result['persistent_volume_claim'][0])
+ assert_instance_of(Kubeclient::Resource, result['component_status'][0])
+ assert_instance_of(Kubeclient::Resource, result['service_account'][0])
+ end
+
+ def test_get_all_raw
+ stub_core_api_list
+
+ stub_request(:get, %r{/bindings})
+ .to_return(body: open_test_file('bindings_list.json'), status: 404)
+
+ stub_request(:get, %r{/configmaps})
+ .to_return(body: open_test_file('config_map_list.json'), status: 200)
+
+ stub_request(:get, %r{/podtemplates})
+ .to_return(body: open_test_file('pod_template_list.json'), status: 200)
+
+ stub_request(:get, %r{/services})
+ .to_return(body: open_test_file('service_list.json'), status: 200)
+
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+
+ stub_request(:get, %r{/nodes})
+ .to_return(body: open_test_file('node_list.json'), status: 200)
+
+ stub_request(:get, %r{/replicationcontrollers})
+ .to_return(body: open_test_file('replication_controller_list.json'), status: 200)
+
+ stub_request(:get, %r{/events})
+ .to_return(body: open_test_file('event_list.json'), status: 200)
+
+ stub_request(:get, %r{/endpoints})
+ .to_return(body: open_test_file('endpoint_list.json'), status: 200)
+
+ stub_request(:get, %r{/namespaces})
+ .to_return(body: open_test_file('namespace_list.json'), status: 200)
+
+ stub_request(:get, %r{/secrets})
+ .to_return(body: open_test_file('secret_list.json'), status: 200)
+
+ stub_request(:get, %r{/resourcequotas})
+ .to_return(body: open_test_file('resource_quota_list.json'), status: 200)
+
+ stub_request(:get, %r{/limitranges})
+ .to_return(body: open_test_file('limit_range_list.json'), status: 200)
+
+ stub_request(:get, %r{/persistentvolumes})
+ .to_return(body: open_test_file('persistent_volume_list.json'), status: 200)
+
+ stub_request(:get, %r{/persistentvolumeclaims})
+ .to_return(body: open_test_file('persistent_volume_claim_list.json'), status: 200)
+
+ stub_request(:get, %r{/componentstatuses})
+ .to_return(body: open_test_file('component_status_list.json'), status: 200)
+
+ stub_request(:get, %r{/serviceaccounts})
+ .to_return(body: open_test_file('service_account_list.json'), status: 200)
+
+ result = client.all_entities(as: :raw)
+ assert_equal(16, result.keys.size)
+
+ %w[
+ component_status config_map endpoint event limit_range namespace node
+ persistent_volume persistent_volume_claim pod replication_controller
+ resource_quota secret service service_account
+ ].each do |entity|
+ assert_equal(open_test_file("#{entity}_list.json").read, result[entity])
+ end
+ end
+
+ def test_api_bearer_token_with_params_success
+ stub_request(:get, 'http://localhost:8080/api/v1/pods?labelSelector=name=redis-master')
+ .with(headers: { Authorization: 'Bearer valid_token' })
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+ stub_request(:get, %r{/api/v1$})
+ .with(headers: { Authorization: 'Bearer valid_token' })
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { bearer_token: 'valid_token' }
+ )
+
+ pods = client.get_pods(label_selector: 'name=redis-master')
+
+ assert_equal('Pod', pods.kind)
+ assert_equal(1, pods.size)
+ end
+
+ def test_api_bearer_token_success
+ stub_core_api_list
+ stub_request(:get, 'http://localhost:8080/api/v1/pods')
+ .with(headers: { Authorization: 'Bearer valid_token' })
+ .to_return(
+ body: open_test_file('pod_list.json'), status: 200
+ )
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { bearer_token: 'valid_token' }
+ )
+
+ pods = client.get_pods
+
+ assert_equal('Pod', pods.kind)
+ assert_equal(1, pods.size)
+ end
+
+ def test_api_bearer_token_failure
+ error_message =
+ '"/api/v1" is forbidden because ' \
+ 'system:anonymous cannot list on pods in'
+ response = OpenStruct.new(code: 401, message: error_message)
+
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(headers: { Authorization: 'Bearer invalid_token' })
+ .to_raise(Kubeclient::HttpError.new(403, error_message, response))
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { bearer_token: 'invalid_token' }
+ )
+
+ exception = assert_raises(Kubeclient::HttpError) { client.get_pods }
+ assert_equal(403, exception.error_code)
+ assert_equal(error_message, exception.message)
+ assert_equal(response, exception.response)
+ end
+
+ def test_api_bearer_token_failure_raw
+ error_message =
+ '"/api/v1" is forbidden because ' \
+ 'system:anonymous cannot list on pods in'
+ response = OpenStruct.new(code: 401, message: error_message)
+
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(headers: { Authorization: 'Bearer invalid_token' })
+ .to_raise(Kubeclient::HttpError.new(403, error_message, response))
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { bearer_token: 'invalid_token' }
+ )
+
+ exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) }
+ assert_equal(403, exception.error_code)
+ assert_equal(error_message, exception.message)
+ assert_equal(response, exception.response)
+ end
+
+ def test_api_basic_auth_success
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(basic_auth: %w[username password])
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
+ stub_request(:get, 'http://localhost:8080/api/v1/pods')
+ .with(basic_auth: %w[username password])
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { username: 'username', password: 'password' }
+ )
+
+ pods = client.get_pods
+
+ assert_equal('Pod', pods.kind)
+ assert_equal(1, pods.size)
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/pods',
+ times: 1
+ )
+ end
+
+ def test_api_basic_auth_back_comp_success
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(basic_auth: %w[username password])
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 200)
+ stub_request(:get, 'http://localhost:8080/api/v1/pods')
+ .with(basic_auth: %w[username password])
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { user: 'username', password: 'password' }
+ )
+
+ pods = client.get_pods
+
+ assert_equal('Pod', pods.kind)
+ assert_equal(1, pods.size)
+ assert_requested(:get, 'http://localhost:8080/api/v1/pods', times: 1)
+ end
+
+ def test_api_basic_auth_failure
+ error_message = 'HTTP status code 401, 401 Unauthorized'
+ response = OpenStruct.new(code: 401, message: '401 Unauthorized')
+
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(basic_auth: %w[username password])
+ .to_raise(Kubeclient::HttpError.new(401, error_message, response))
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { username: 'username', password: 'password' }
+ )
+
+ exception = assert_raises(Kubeclient::HttpError) { client.get_pods }
+ assert_equal(401, exception.error_code)
+ assert_equal(error_message, exception.message)
+ assert_equal(response, exception.response)
+ assert_requested(:get, 'http://localhost:8080/api/v1', times: 1)
+ end
+
+ def test_api_basic_auth_failure_raw
+ error_message = 'HTTP status code 401, 401 Unauthorized'
+ response = OpenStruct.new(code: 401, message: '401 Unauthorized')
+
+ stub_request(:get, 'http://localhost:8080/api/v1')
+ .with(basic_auth: %w[username password])
+ .to_raise(Kubeclient::HttpError.new(401, error_message, response))
+
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { username: 'username', password: 'password' }
+ )
+
+ exception = assert_raises(Kubeclient::HttpError) { client.get_pods(as: :raw) }
+ assert_equal(401, exception.error_code)
+ assert_equal(error_message, exception.message)
+ assert_equal(response, exception.response)
+
+ assert_requested(:get, 'http://localhost:8080/api/v1', times: 1)
+ end
+
+ def test_init_username_no_password
+ expected_msg = 'Basic auth requires both username & password'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { username: 'username' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_init_user_no_password
+ expected_msg = 'Basic auth requires both username & password'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { user: 'username' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_init_username_and_bearer_token
+ expected_msg = 'Invalid auth options: specify only one of username/password,' \
+ ' bearer_token or bearer_token_file'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { username: 'username', bearer_token: 'token' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_init_username_and_bearer_token_file
+ expected_msg = 'Invalid auth options: specify only one of username/password,' \
+ ' bearer_token or bearer_token_file'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { username: 'username', bearer_token_file: 'token-file' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_bearer_token_and_bearer_token_file
+ expected_msg =
+ 'Invalid auth options: specify only one of username/password,' \
+ ' bearer_token or bearer_token_file'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { bearer_token: 'token', bearer_token_file: 'token-file' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_bearer_token_file_not_exist
+ expected_msg = 'Token file token-file does not exist'
+ exception = assert_raises(ArgumentError) do
+ Kubeclient::Client.new(
+ 'http://localhost:8080',
+ auth_options: { bearer_token_file: 'token-file' }
+ )
+ end
+ assert_equal(expected_msg, exception.message)
+ end
+
+ def test_api_bearer_token_file_success
+ stub_core_api_list
+ stub_request(:get, 'http://localhost:8080/api/v1/pods')
+ .with(headers: { Authorization: 'Bearer valid_token' })
+ .to_return(body: open_test_file('pod_list.json'), status: 200)
+
+ file = File.join(File.dirname(__FILE__), 'valid_token_file')
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ auth_options: { bearer_token_file: file }
+ )
+
+ pods = client.get_pods
+
+ assert_equal('Pod', pods.kind)
+ assert_equal(1, pods.size)
+ end
+
+ def test_proxy_url
+ stub_core_api_list
+
+ client = Kubeclient::Client.new('http://host:8080', 'v1')
+ assert_equal(
+ 'http://host:8080/api/v1/namespaces/ns/services/srvname:srvportname/proxy',
+ client.proxy_url('service', 'srvname', 'srvportname', 'ns')
+ )
+
+ assert_equal(
+ 'http://host:8080/api/v1/namespaces/ns/services/srvname:srvportname/proxy',
+ client.proxy_url('services', 'srvname', 'srvportname', 'ns')
+ )
+
+ assert_equal(
+ 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy',
+ client.proxy_url('pod', 'srvname', 'srvportname', 'ns')
+ )
+
+ assert_equal(
+ 'http://host:8080/api/v1/namespaces/ns/pods/srvname:srvportname/proxy',
+ client.proxy_url('pods', 'srvname', 'srvportname', 'ns')
+ )
+
+ # Check no namespace provided
+ assert_equal(
+ 'http://host:8080/api/v1/nodes/srvname:srvportname/proxy',
+ client.proxy_url('nodes', 'srvname', 'srvportname')
+ )
+
+ assert_equal(
+ 'http://host:8080/api/v1/nodes/srvname:srvportname/proxy',
+ client.proxy_url('node', 'srvname', 'srvportname')
+ )
+
+ # Check integer port
+ assert_equal(
+ 'http://host:8080/api/v1/nodes/srvname:5001/proxy',
+ client.proxy_url('nodes', 'srvname', 5001)
+ )
+
+ assert_equal(
+ 'http://host:8080/api/v1/nodes/srvname:5001/proxy',
+ client.proxy_url('node', 'srvname', 5001)
+ )
+ end
+
+ def test_attr_readers
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ ssl_options: { client_key: 'secret' },
+ auth_options: { bearer_token: 'token' }
+ )
+ assert_equal('/api', client.api_endpoint.path)
+ assert_equal('secret', client.ssl_options[:client_key])
+ assert_equal('token', client.auth_options[:bearer_token])
+ assert_equal('Bearer token', client.headers[:Authorization])
+ end
+
+ def test_nil_items
+ # handle https://github.com/kubernetes/kubernetes/issues/13096
+ stub_core_api_list
+ stub_request(:get, %r{/persistentvolumeclaims})
+ .to_return(body: open_test_file('persistent_volume_claims_nil_items.json'), status: 200)
+
+ client.get_persistent_volume_claims
+ end
+
+ # Timeouts
+
+ def test_timeouts_defaults
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/'
+ )
+ rest_client = client.rest_client
+ assert_default_open_timeout(rest_client.open_timeout)
+ assert_equal(60, rest_client.read_timeout)
+ end
+
+ def test_timeouts_open
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ timeouts: { open: 10 }
+ )
+ rest_client = client.rest_client
+ assert_equal(10, rest_client.open_timeout)
+ assert_equal(60, rest_client.read_timeout)
+ end
+
+ def test_timeouts_read
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ timeouts: { read: 300 }
+ )
+ rest_client = client.rest_client
+ assert_default_open_timeout(rest_client.open_timeout)
+ assert_equal(300, rest_client.read_timeout)
+ end
+
+ def test_timeouts_both
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ timeouts: { open: 10, read: 300 }
+ )
+ rest_client = client.rest_client
+ assert_equal(10, rest_client.open_timeout)
+ assert_equal(300, rest_client.read_timeout)
+ end
+
+ def test_timeouts_infinite
+ client = Kubeclient::Client.new(
+ 'http://localhost:8080/api/',
+ timeouts: { open: nil, read: nil }
+ )
+ rest_client = client.rest_client
+ assert_nil(rest_client.open_timeout)
+ assert_nil(rest_client.read_timeout)
+ end
+
+ def assert_default_open_timeout(actual)
+ if RUBY_VERSION >= '2.3'
+ assert_equal(60, actual)
+ else
+ assert_nil(actual)
+ end
+ end
+
+ private
+
+ def stub_get_services
+ stub_request(:get, %r{/services})
+ .to_return(body: open_test_file('entity_list.json'), status: 200)
+ end
+
+ def client
+ @client ||= Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ end
+
+ # dup method creates a shallow copy which is not good in this case
+ # since rename_keys changes the input hash
+ # hence need to create a deep_copy
+ def deep_copy(hash)
+ Marshal.load(Marshal.dump(hash))
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_limit_range.rb b/vendor/gems/kubeclient/test/test_limit_range.rb
new file mode 100644
index 00000000000..e9822578e00
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_limit_range.rb
@@ -0,0 +1,25 @@
+require_relative 'test_helper'
+
+# LimitRange tests
+class TestLimitRange < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/limitranges})
+ .to_return(body: open_test_file('limit_range.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ limit_range = client.get_limit_range('limits', 'quota-example')
+
+ assert_instance_of(Kubeclient::Resource, limit_range)
+ assert_equal('limits', limit_range.metadata.name)
+ assert_equal('Container', limit_range.spec.limits[0].type)
+ assert_equal('100m', limit_range.spec.limits[0].default.cpu)
+ assert_equal('512Mi', limit_range.spec.limits[0].default.memory)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/namespaces/quota-example/limitranges/limits',
+ times: 1
+ )
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_missing_methods.rb b/vendor/gems/kubeclient/test/test_missing_methods.rb
new file mode 100644
index 00000000000..67614c95adc
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_missing_methods.rb
@@ -0,0 +1,80 @@
+require_relative 'test_helper'
+
+# Test method_missing, respond_to? and respond_to_missing behaviour
+class TestMissingMethods < MiniTest::Test
+ def test_missing
+ stub_core_api_list
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_equal(true, client.respond_to?(:get_pod))
+ assert_equal(true, client.respond_to?(:get_pods))
+ assert_equal(false, client.respond_to?(:get_pie))
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
+ assert_equal(false, client.respond_to?(:get_pie))
+ assert_equal(true, client.respond_to?(:get_pods))
+ assert_equal(true, client.respond_to?(:get_pod))
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
+ assert_instance_of(Method, client.method(:get_pods))
+ assert_raises(NameError) do
+ client.method(:get_pies)
+ end
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1') # Reset discovery
+ assert_raises(NameError) do
+ client.method(:get_pies)
+ end
+ assert_instance_of(Method, client.method(:get_pods))
+
+ stub_request(:get, %r{/api/v1$}).to_return(
+ body: '',
+ status: 404
+ ) # If discovery fails we expect the below raise an exception
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_raises(Kubeclient::HttpError) do
+ client.discover
+ end
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_raises(Kubeclient::HttpError) do
+ client.method(:get_pods)
+ end
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_raises(Kubeclient::HttpError) do
+ client.respond_to?(:get_pods)
+ end
+ end
+
+ def test_nonsuffix_plurals
+ stub_request(:get, %r{/apis/extensions/v1beta1$}).to_return(
+ body: open_test_file('extensions_v1beta1_api_resource_list.json'),
+ status: 200
+ )
+ client = Kubeclient::Client.new('http://localhost:8080/apis/extensions', 'v1beta1')
+ assert_equal(true, client.respond_to?(:get_network_policy))
+ assert_equal(true, client.respond_to?(:get_network_policies))
+ assert_equal(true, client.respond_to?(:get_pod_security_policy))
+ assert_equal(true, client.respond_to?(:get_pod_security_policies))
+ end
+
+ def test_irregular_names
+ stub_core_api_list
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_equal(true, client.respond_to?(:get_endpoint))
+ assert_equal(true, client.respond_to?(:get_endpoints))
+
+ stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
+ body: open_test_file('security.openshift.io_api_resource_list.json'),
+ status: 200
+ )
+ client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
+ assert_equal(true, client.respond_to?(:get_security_context_constraint))
+ assert_equal(true, client.respond_to?(:get_security_context_constraints))
+ end
+
+ def test_lowercase_kind
+ stub_request(:get, %r{/apis/config.istio.io/v1alpha2$}).to_return(
+ body: open_test_file('config.istio.io_api_resource_list.json'),
+ status: 200
+ )
+ client = Kubeclient::Client.new('http://localhost:8080/apis/config.istio.io', 'v1alpha2')
+ assert_equal(true, client.respond_to?(:get_servicecontrolreport))
+ assert_equal(true, client.respond_to?(:get_servicecontrolreports))
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_namespace.rb b/vendor/gems/kubeclient/test/test_namespace.rb
new file mode 100644
index 00000000000..7283aa69b67
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_namespace.rb
@@ -0,0 +1,59 @@
+require_relative 'test_helper'
+
+# Namespace entity tests
+class TestNamespace < MiniTest::Test
+ def test_get_namespace_v1
+ stub_core_api_list
+ stub_request(:get, %r{/namespaces})
+ .to_return(body: open_test_file('namespace.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ namespace = client.get_namespace('staging')
+
+ assert_instance_of(Kubeclient::Resource, namespace)
+ assert_equal('e388bc10-c021-11e4-a514-3c970e4a436a', namespace.metadata.uid)
+ assert_equal('staging', namespace.metadata.name)
+ assert_equal('1168', namespace.metadata.resourceVersion)
+ assert_equal('v1', namespace.apiVersion)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/namespaces/staging',
+ times: 1
+ )
+ end
+
+ def test_delete_namespace_v1
+ our_namespace = Kubeclient::Resource.new
+ our_namespace.metadata = {}
+ our_namespace.metadata.name = 'staging'
+
+ stub_core_api_list
+ stub_request(:delete, %r{/namespaces})
+ .to_return(body: open_test_file('namespace.json'), status: 200)
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ our_namespace = client.delete_namespace(our_namespace.metadata.name)
+ assert_kind_of(RecursiveOpenStruct, our_namespace)
+
+ assert_requested(
+ :delete,
+ 'http://localhost:8080/api/v1/namespaces/staging',
+ times: 1
+ )
+ end
+
+ def test_create_namespace
+ stub_core_api_list
+ stub_request(:post, %r{/namespaces})
+ .to_return(body: open_test_file('created_namespace.json'), status: 201)
+
+ namespace = Kubeclient::Resource.new
+ namespace.metadata = {}
+ namespace.metadata.name = 'development'
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ created_namespace = client.create_namespace(namespace)
+ assert_instance_of(Kubeclient::Resource, created_namespace)
+ assert_equal(namespace.metadata.name, created_namespace.metadata.name)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_node.rb b/vendor/gems/kubeclient/test/test_node.rb
new file mode 100644
index 00000000000..aa7459d63c9
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_node.rb
@@ -0,0 +1,70 @@
+require_relative 'test_helper'
+
+# Node entity tests
+class TestNode < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/nodes})
+ .to_return(body: open_test_file('node.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ node = client.get_node('127.0.0.1')
+
+ assert_instance_of(Kubeclient::Resource, node)
+
+ assert_equal('041143c5-ce39-11e4-ac24-3c970e4a436a', node.metadata.uid)
+ assert_equal('127.0.0.1', node.metadata.name)
+ assert_equal('1724', node.metadata.resourceVersion)
+ assert_equal('v1', node.apiVersion)
+ assert_equal('2015-03-19T15:08:20+02:00', node.metadata.creationTimestamp)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/nodes/127.0.0.1',
+ times: 1
+ )
+ end
+
+ def test_get_from_json_v1_raw
+ stub_core_api_list
+ stub_request(:get, %r{/nodes})
+ .to_return(body: open_test_file('node.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ response = client.get_node('127.0.0.1', nil, as: :raw)
+
+ assert_equal(open_test_file('node.json').read, response)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/nodes/127.0.0.1',
+ times: 1
+ )
+ end
+
+ def test_get_from_json_v1_raw_error
+ stub_request(:get, %r{/nodes})
+ .to_return(body: open_test_file('node.json'), status: 200)
+ stub_request(:get, %r{/api/v1$})
+ .to_return(body: open_test_file('core_api_resource_list.json'), status: 500)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ exception = assert_raises(Kubeclient::HttpError) do
+ client.get_node('127.0.0.1', nil, as: :raw)
+ end
+
+ assert_instance_of(Kubeclient::HttpError, exception)
+ assert_equal('500 Internal Server Error', exception.message)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb b/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb
new file mode 100644
index 00000000000..cdf325e9406
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_oidc_auth_provider.rb
@@ -0,0 +1,103 @@
+require_relative 'test_helper'
+require 'openid_connect'
+
+class OIDCAuthProviderTest < MiniTest::Test
+ def setup
+ @client_id = 'client_id'
+ @client_secret = 'client_secret'
+ @idp_issuer_url = 'idp_issuer_url'
+ @refresh_token = 'refresh_token'
+ @id_token = 'id_token'
+ @new_id_token = 'new_id_token'
+ end
+
+ def test_expired_token
+ OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
+ OpenIDConnect::ResponseObject::IdToken.stub(:decode, id_token_mock(Time.now.to_i - 7200)) do
+ OpenIDConnect::Client.stub(:new, openid_client_mock) do
+ retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
+ 'client-id' => @client_id,
+ 'client-secret' => @client_secret,
+ 'id-token' => @id_token,
+ 'idp-issuer-url' => @idp_issuer_url,
+ 'refresh-token' => @refresh_token
+ )
+ assert_equal(@new_id_token, retrieved_id_token)
+ end
+ end
+ end
+ end
+
+ def test_valid_token
+ OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
+ OpenIDConnect::ResponseObject::IdToken.stub(:decode, id_token_mock(Time.now.to_i + 7200)) do
+ retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
+ 'client-id' => @client_id,
+ 'client-secret' => @client_secret,
+ 'id-token' => @id_token,
+ 'idp-issuer-url' => @idp_issuer_url,
+ 'refresh-token' => @refresh_token
+ )
+ assert_equal(@id_token, retrieved_id_token)
+ end
+ end
+ end
+
+ def test_missing_id_token
+ OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
+ OpenIDConnect::Client.stub(:new, openid_client_mock) do
+ retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
+ 'client-id' => @client_id,
+ 'client-secret' => @client_secret,
+ 'idp-issuer-url' => @idp_issuer_url,
+ 'refresh-token' => @refresh_token
+ )
+ assert_equal(@new_id_token, retrieved_id_token)
+ end
+ end
+ end
+
+ def test_token_with_unknown_kid
+ OpenIDConnect::Discovery::Provider::Config.stub(:discover!, discovery_mock) do
+ OpenIDConnect::ResponseObject::IdToken.stub(
+ :decode, ->(_token, _jwks) { raise JSON::JWK::Set::KidNotFound }
+ ) do
+ OpenIDConnect::Client.stub(:new, openid_client_mock) do
+ retrieved_id_token = Kubeclient::OIDCAuthProvider.token(
+ 'client-id' => @client_id,
+ 'client-secret' => @client_secret,
+ 'id-token' => @id_token,
+ 'idp-issuer-url' => @idp_issuer_url,
+ 'refresh-token' => @refresh_token
+ )
+ assert_equal(@new_id_token, retrieved_id_token)
+ end
+ end
+ end
+ end
+
+ private
+
+ def openid_client_mock
+ access_token = Minitest::Mock.new
+ access_token.expect(@id_token, @new_id_token)
+
+ openid_client = Minitest::Mock.new
+ openid_client.expect(:refresh_token=, nil, [@refresh_token])
+ openid_client.expect(:access_token!, access_token)
+ end
+
+ def id_token_mock(expiry)
+ id_token_mock = Minitest::Mock.new
+ id_token_mock.expect(:exp, expiry)
+ end
+
+ def discovery_mock
+ discovery = Minitest::Mock.new
+ discovery.expect(:jwks, 'jwks')
+ discovery.expect(:authorization_endpoint, 'authz_endpoint')
+ discovery.expect(:token_endpoint, 'token_endpoint')
+ discovery.expect(:userinfo_endpoint, 'userinfo_endpoint')
+ discovery
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_persistent_volume.rb b/vendor/gems/kubeclient/test/test_persistent_volume.rb
new file mode 100644
index 00000000000..8b283868a1f
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_persistent_volume.rb
@@ -0,0 +1,29 @@
+require_relative 'test_helper'
+
+# PersistentVolume tests
+class TestPersistentVolume < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/persistentvolumes})
+ .to_return(body: open_test_file('persistent_volume.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ volume = client.get_persistent_volume('pv0001')
+
+ assert_instance_of(Kubeclient::Resource, volume)
+ assert_equal('pv0001', volume.metadata.name)
+ assert_equal('10Gi', volume.spec.capacity.storage)
+ assert_equal('/tmp/data01', volume.spec.hostPath.path)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/persistentvolumes/pv0001',
+ times: 1
+ )
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb b/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb
new file mode 100644
index 00000000000..e51d8562e60
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_persistent_volume_claim.rb
@@ -0,0 +1,28 @@
+require_relative 'test_helper'
+
+# PersistentVolumeClaim tests
+class TestPersistentVolumeClaim < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/persistentvolumeclaims})
+ .to_return(body: open_test_file('persistent_volume_claim.json'), status: 200)
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ claim = client.get_persistent_volume_claim('myclaim-1', 'default')
+
+ assert_instance_of(Kubeclient::Resource, claim)
+ assert_equal('myclaim-1', claim.metadata.name)
+ assert_equal('3Gi', claim.spec.resources.requests.storage)
+ assert_equal('pv0001', claim.spec.volumeName)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/namespaces/default/persistentvolumeclaims/myclaim-1',
+ times: 1
+ )
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_pod.rb b/vendor/gems/kubeclient/test/test_pod.rb
new file mode 100644
index 00000000000..afad1774f5e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_pod.rb
@@ -0,0 +1,81 @@
+require_relative 'test_helper'
+
+# Pod entity tests
+class TestPod < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pod.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ pod = client.get_pod('redis-master-pod', 'default')
+
+ assert_instance_of(Kubeclient::Resource, pod)
+ assert_equal('redis-master3', pod.metadata.name)
+ assert_equal('dockerfile/redis', pod.spec.containers[0]['image'])
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod',
+ times: 1
+ )
+ end
+
+ def test_get_chunks
+ stub_core_api_list
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pods_1.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ pods = client.get_pods(limit: 2)
+
+ assert_equal(2, pods.count)
+ assert_equal('eyJ2IjoibWV0YS5rOHMua', pods.continue)
+
+ continue = pods.continue
+
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pods_2.json'), status: 200)
+
+ pods = client.get_pods(limit: 2, continue: continue)
+ assert_equal(2, pods.count)
+ assert_nil(pods.continue)
+
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ 'http://localhost:8080/api/v1/pods?limit=2',
+ times: 1
+ )
+ assert_requested(
+ :get,
+ "http://localhost:8080/api/v1/pods?continue=#{continue}&limit=2",
+ times: 1
+ )
+ end
+
+ def test_get_chunks_410_gone
+ stub_core_api_list
+ stub_request(:get, %r{/pods})
+ .to_return(body: open_test_file('pods_410.json'), status: 410)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ err = assert_raises Kubeclient::HttpError do
+ client.get_pods(limit: 2, continue: 'eyJ2IjoibWV0YS5')
+ end
+
+ assert_equal(err.message,
+ "The provided from parameter is too old to display a consistent list result. \
+You must start a new list without the from.")
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_pod_log.rb b/vendor/gems/kubeclient/test/test_pod_log.rb
new file mode 100644
index 00000000000..d9ba3eaabbd
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_pod_log.rb
@@ -0,0 +1,157 @@
+require_relative 'test_helper'
+
+# Pod log tests
+class TestPodLog < MiniTest::Test
+ def test_get_pod_log
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ retrieved_log = client.get_pod_log('redis-master-pod', 'default')
+
+ assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log',
+ times: 1)
+ end
+
+ def test_get_pod_log_container
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ retrieved_log = client.get_pod_log('redis-master-pod', 'default', container: 'ruby')
+
+ assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?container=ruby',
+ times: 1)
+ end
+
+ def test_get_pod_log_since_time
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ retrieved_log = client.get_pod_log('redis-master-pod',
+ 'default',
+ timestamps: true,
+ since_time: '2018-04-27T18:30:17.480321984Z')
+
+ assert_equal(open_test_file('pod_log.txt').read, retrieved_log)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?sinceTime=2018-04-27T18:30:17.480321984Z&timestamps=true',
+ times: 1)
+ end
+
+ def test_get_pod_log_tail_lines
+ selected_lines = open_test_file('pod_log.txt').to_a[-2..1].join
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
+ .to_return(body: selected_lines,
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ retrieved_log = client.get_pod_log('redis-master-pod',
+ 'default',
+ tail_lines: 2)
+
+ assert_equal(selected_lines, retrieved_log)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?tailLines=2',
+ times: 1)
+ end
+
+ def test_get_pod_limit_bytes
+ selected_bytes = open_test_file('pod_log.txt').read(10)
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log})
+ .to_return(body: selected_bytes,
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ retrieved_log = client.get_pod_log('redis-master-pod',
+ 'default',
+ limit_bytes: 10)
+
+ assert_equal(selected_bytes, retrieved_log)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/pods/redis-master-pod/log?limitBytes=10',
+ times: 1)
+ end
+
+ def test_watch_pod_log
+ file = open_test_file('pod_log.txt')
+ expected_lines = file.read.split("\n")
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
+ .to_return(body: file, status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ stream = client.watch_pod_log('redis-master-pod', 'default')
+ stream.to_enum.with_index do |notice, index|
+ assert_instance_of(String, notice)
+ assert_equal(expected_lines[index], notice)
+ end
+ end
+
+ def test_watch_pod_log_with_block
+ file = open_test_file('pod_log.txt')
+ first = file.readlines.first.chomp
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
+ .to_return(body: file, status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ client.watch_pod_log('redis-master-pod', 'default') do |line|
+ assert_equal first, line
+ break
+ end
+ end
+
+ def test_watch_pod_log_follow_redirect
+ expected_lines = open_test_file('pod_log.txt').read.split("\n")
+ redirect = 'http://localhost:1234/api/namespaces/default/pods/redis-master-pod/log'
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
+ .to_return(status: 302, headers: { location: redirect })
+
+ stub_request(:get, redirect)
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ stream = client.watch_pod_log('redis-master-pod', 'default')
+ stream.to_enum.with_index do |notice, index|
+ assert_instance_of(String, notice)
+ assert_equal(expected_lines[index], notice)
+ end
+ end
+
+ def test_watch_pod_log_max_redirect
+ redirect = 'http://localhost:1234/api/namespaces/default/pods/redis-master-pod/log'
+
+ stub_request(:get, %r{/namespaces/default/pods/[a-z0-9-]+/log\?.*follow})
+ .to_return(status: 302, headers: { location: redirect })
+
+ stub_request(:get, redirect)
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', http_max_redirects: 0)
+ assert_raises(Kubeclient::HttpError) do
+ client.watch_pod_log('redis-master-pod', 'default').each do
+ end
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_process_template.rb b/vendor/gems/kubeclient/test/test_process_template.rb
new file mode 100644
index 00000000000..e3b4670fb87
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_process_template.rb
@@ -0,0 +1,80 @@
+require_relative 'test_helper'
+
+# Process Template tests
+class TestProcessTemplate < MiniTest::Test
+ def test_process_template
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ template = {}
+ template[:metadata] = {}
+ template[:metadata][:name] = 'my-template'
+ template[:metadata][:namespace] = 'default'
+ template[:kind] = 'Template'
+ template[:apiVersion] = 'v1'
+ service = {}
+ service[:metadata] = {}
+ service[:metadata][:name] = '${NAME_PREFIX}my-service'
+ service[:kind] = 'Service'
+ service[:apiVersion] = 'v1'
+ template[:objects] = [service]
+ param = { name: 'NAME_PREFIX', value: 'test/' }
+ template[:parameters] = [param]
+
+ req_body = '{"metadata":{"name":"my-template","namespace":"default"},' \
+ '"kind":"Template","apiVersion":"v1","objects":[{"metadata":' \
+ '{"name":"${NAME_PREFIX}my-service"},"kind":"Service","apiVersion":"v1"}],' \
+ '"parameters":[{"name":"NAME_PREFIX","value":"test/"}]}'
+
+ expected_url = 'http://localhost:8080/api/v1/namespaces/default/processedtemplates'
+ stub_request(:post, expected_url)
+ .with(body: req_body, headers: { 'Content-Type' => 'application/json' })
+ .to_return(body: open_test_file('processed_template.json'), status: 200)
+
+ processed_template = client.process_template(template)
+
+ assert_equal('test/my-service', processed_template['objects'].first['metadata']['name'])
+
+ assert_requested(:post, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['kind'] == 'Template' &&
+ data['apiVersion'] == 'v1' &&
+ data['metadata']['name'] == 'my-template' &&
+ data['metadata']['namespace'] == 'default'
+ end
+ end
+
+ # Ensure _template and _templates methods hit `/templates` rather than
+ # `/processedtemplates` URL.
+ def test_templates_methods
+ stub_request(:get, %r{/apis/template\.openshift\.io/v1$}).to_return(
+ body: open_test_file('template.openshift.io_api_resource_list.json'),
+ status: 200
+ )
+ client = Kubeclient::Client.new('http://localhost:8080/apis/template.openshift.io', 'v1')
+
+ expected_url = 'http://localhost:8080/apis/template.openshift.io/v1/namespaces/default/templates'
+ stub_request(:get, expected_url)
+ .to_return(body: open_test_file('template_list.json'), status: 200)
+ client.get_templates(namespace: 'default')
+ assert_requested(:get, expected_url, times: 1)
+
+ expected_url = 'http://localhost:8080/apis/template.openshift.io/v1/namespaces/default/templates/my-template'
+ stub_request(:get, expected_url)
+ .to_return(body: open_test_file('template.json'), status: 200)
+ client.get_template('my-template', 'default')
+ assert_requested(:get, expected_url, times: 1)
+ end
+
+ def test_no_processedtemplates_methods
+ stub_request(:get, %r{/apis/template\.openshift\.io/v1$}).to_return(
+ body: open_test_file('template.openshift.io_api_resource_list.json'),
+ status: 200
+ )
+ client = Kubeclient::Client.new('http://localhost:8080/apis/template.openshift.io', 'v1')
+ client.discover
+
+ refute_respond_to(client, :get_processedtemplates)
+ refute_respond_to(client, :get_processedtemplate)
+ refute_respond_to(client, :get_processed_templates)
+ refute_respond_to(client, :get_processed_template)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_real_cluster.rb b/vendor/gems/kubeclient/test/test_real_cluster.rb
new file mode 100644
index 00000000000..7ce9493a1bb
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_real_cluster.rb
@@ -0,0 +1,162 @@
+require_relative 'test_helper'
+
+class KubeclientRealClusterTest < MiniTest::Test
+ # Tests here actually connect to a cluster!
+ # For simplicity, these tests use same config/*.kubeconfig files as test_config.rb,
+ # so are intended to run from config/update_certs_k0s.rb script.
+ def setup
+ if ENV['KUBECLIENT_TEST_REAL_CLUSTER'] == 'true'
+ WebMock.enable_net_connect!
+ else
+ skip('Requires real cluster, see test/config/update_certs_k0s.rb.')
+ end
+ end
+
+ def teardown
+ WebMock.disable_net_connect! # Don't allow any connections in other tests.
+ end
+
+ # Partially isolated tests that check Client behavior with given `verify_ssl` value:
+
+ # localhost and 127.0.0.1 are among names on the certificate
+ HOSTNAME_COVERED_BY_CERT = 'https://127.0.0.1:6443'.freeze
+ # 127.0.0.2 also means localhost but is not included in the certificate.
+ HOSTNAME_NOT_ON_CERT = 'https://127.0.0.2:6443'.freeze
+
+ def test_real_cluster_verify_peer
+ config = Kubeclient::Config.read(config_file('external.kubeconfig'))
+ context = config.context
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER),
+ auth_options: context.auth_options
+ )
+ check_cert_accepted(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_PEER),
+ auth_options: context.auth_options
+ )
+ check_cert_rejected(client2)
+ end
+
+ def test_real_cluster_verify_none
+ config = Kubeclient::Config.read(config_file('external.kubeconfig'))
+ context = config.context
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE),
+ auth_options: context.auth_options
+ )
+ check_cert_accepted(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options.merge(verify_ssl: OpenSSL::SSL::VERIFY_NONE),
+ auth_options: context.auth_options
+ )
+ check_cert_accepted(client2)
+ end
+
+ # Integration tests that check combined Config -> Client behavior wrt. `verify_ssl`.
+ # Quite redundant, but this was an embarrasing vulnerability so want to confirm...
+
+ def test_real_cluster_concatenated_ca
+ config = Kubeclient::Config.read(config_file('concatenated-ca.kubeconfig'))
+ context = config.context
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_accepted(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_rejected(client2)
+ end
+
+ def test_real_cluster_verify_ssl_with_ca
+ config = Kubeclient::Config.read(config_file('external.kubeconfig'))
+ context = config.context
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_accepted(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_rejected(client2)
+ end
+
+ def test_real_cluster_verify_ssl_without_ca
+ config = Kubeclient::Config.read(config_file('external-without-ca.kubeconfig'))
+ context = config.context
+ # Hostname matches cert but the local cluster uses self-signed certs from custom CA,
+ # and this config omits CA data, so verification can't succeed.
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_rejected(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_rejected(client2)
+ end
+
+ def test_real_cluster_insecure_without_ca
+ config = Kubeclient::Config.read(config_file('insecure.kubeconfig'))
+ context = config.context
+ # Hostname matches cert but the local cluster uses self-signed certs from custom CA,
+ # and this config omits CA data, so verification would fail;
+ # however, this config specifies `insecure-skip-tls-verify: true` so any cert goes.
+ client1 = Kubeclient::Client.new(
+ HOSTNAME_COVERED_BY_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_accepted(client1)
+ client2 = Kubeclient::Client.new(
+ HOSTNAME_NOT_ON_CERT, 'v1',
+ ssl_options: context.ssl_options, auth_options: context.auth_options
+ )
+ check_cert_accepted(client2)
+ end
+
+ private
+
+ # Test cert checking on discovery, CRUD, and watch code paths.
+ def check_cert_accepted(client)
+ client.discover
+ client.get_nodes
+ exercise_watcher_with_timeout(client.watch_nodes)
+ end
+
+ def check_cert_rejected(client)
+ # TODO: all OpenSSL exceptions should be wrapped with Kubeclient error.
+ assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
+ client.discover
+ end
+ # Since discovery fails, methods like .get_nodes, .watch_nodes would all fail
+ # on method_missing -> discover. Call lower-level methods to test actual connection.
+ assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
+ client.get_entities('Node', 'nodes', {})
+ end
+ assert_raises(Kubeclient::HttpError, OpenSSL::SSL::SSLError) do
+ exercise_watcher_with_timeout(client.watch_entities('nodes'))
+ end
+ end
+
+ def exercise_watcher_with_timeout(watcher)
+ thread = Thread.new do
+ sleep(1)
+ watcher.finish
+ end
+ watcher.each do |_notice|
+ break
+ end
+ thread.join
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_replication_controller.rb b/vendor/gems/kubeclient/test/test_replication_controller.rb
new file mode 100644
index 00000000000..47af72210e5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_replication_controller.rb
@@ -0,0 +1,47 @@
+require_relative 'test_helper'
+
+# Replication Controller entity tests
+class TestReplicationController < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/replicationcontrollers})
+ .to_return(body: open_test_file('replication_controller.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ rc = client.get_replication_controller('frontendController', 'default')
+
+ assert_instance_of(Kubeclient::Resource, rc)
+ assert_equal('guestbook-controller', rc.metadata.name)
+ assert_equal('c71aa4c0-a240-11e4-a265-3c970e4a436a', rc.metadata.uid)
+ assert_equal('default', rc.metadata.namespace)
+ assert_equal(3, rc.spec.replicas)
+ assert_equal('guestbook', rc.spec.selector.name)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController',
+ times: 1)
+ end
+
+ def test_delete_replicaset_cascade
+ stub_core_api_list
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ opts = Kubeclient::Resource.new(
+ apiVersion: 'meta/v1',
+ gracePeriodSeconds: 0,
+ kind: 'DeleteOptions',
+ propagationPolicy: 'Foreground'
+ )
+
+ stub_request(:delete,
+ 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController')
+ .with(body: opts.to_hash.to_json)
+ .to_return(status: 200, body: open_test_file('replication_controller.json'), headers: {})
+ rc = client.delete_replication_controller('frontendController', 'default', delete_options: opts)
+ assert_kind_of(RecursiveOpenStruct, rc)
+
+ assert_requested(:delete,
+ 'http://localhost:8080/api/v1/namespaces/default/replicationcontrollers/frontendController',
+ times: 1)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb b/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb
new file mode 100644
index 00000000000..89ab042b5f5
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_resource_list_without_kind.rb
@@ -0,0 +1,78 @@
+require_relative 'test_helper'
+
+# Core api resource list without kind tests
+class TestResourceListWithoutKind < MiniTest::Test
+ def test_get_from_json_api_v1
+ stub_request(:get, %r{/api/v1$})
+ .to_return(body: open_test_file('core_api_resource_list_without_kind.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ client.discover
+
+ [
+ {
+ entity: 'pod',
+ type: 'Pod',
+ name: 'pods',
+ methods: %w[pod pods]
+ },
+ {
+ entity: 'node',
+ type: 'Node',
+ name: 'nodes',
+ methods: %w[node nodes]
+ },
+ {
+ entity: 'service',
+ type: 'Service',
+ name: 'services',
+ methods: %w[service services]
+ }
+ ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) }
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1',
+ times: 1)
+ end
+
+ def test_get_from_json_oapi_v1
+ stub_request(:get, %r{/oapi/v1$})
+ .to_return(body: open_test_file('core_oapi_resource_list_without_kind.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/oapi/', 'v1')
+ client.discover
+
+ [
+ {
+ entity: 'template',
+ type: 'Template',
+ name: 'templates',
+ methods: %w[template templates]
+ },
+ {
+ entity: 'build',
+ type: 'Build',
+ name: 'builds',
+ methods: %w[build builds]
+ },
+ {
+ entity: 'project',
+ type: 'Project',
+ name: 'projects',
+ methods: %w[project projects]
+ }
+ ].each { |h| assert_entities(client.instance_variable_get(:@entities)[h[:entity]], h) }
+
+ assert_requested(:get,
+ 'http://localhost:8080/oapi/v1',
+ times: 1)
+ end
+
+ def assert_entities(entity, h)
+ assert_equal(entity.entity_type, h[:type])
+ assert_equal(entity.resource_name, h[:name])
+ assert_equal(entity.method_names, h[:methods])
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_resource_quota.rb b/vendor/gems/kubeclient/test/test_resource_quota.rb
new file mode 100644
index 00000000000..cf91a111196
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_resource_quota.rb
@@ -0,0 +1,23 @@
+require_relative 'test_helper'
+
+# ResourceQuota tests
+class TestResourceQuota < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/resourcequotas})
+ .to_return(body: open_test_file('resource_quota.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ quota = client.get_resource_quota('quota', 'quota-example')
+
+ assert_instance_of(Kubeclient::Resource, quota)
+ assert_equal('quota', quota.metadata.name)
+ assert_equal('20', quota.spec.hard.cpu)
+ assert_equal('10', quota.spec.hard.secrets)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/quota-example/resourcequotas/quota',
+ times: 1)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_secret.rb b/vendor/gems/kubeclient/test/test_secret.rb
new file mode 100644
index 00000000000..ec129075a14
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_secret.rb
@@ -0,0 +1,62 @@
+require_relative 'test_helper'
+
+# Namespace entity tests
+class TestSecret < MiniTest::Test
+ def test_get_secret_v1
+ stub_core_api_list
+ stub_request(:get, %r{/secrets})
+ .to_return(body: open_test_file('created_secret.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ secret = client.get_secret('test-secret', 'dev')
+
+ assert_instance_of(Kubeclient::Resource, secret)
+ assert_equal('4e38a198-2bcb-11e5-a483-0e840567604d', secret.metadata.uid)
+ assert_equal('test-secret', secret.metadata.name)
+ assert_equal('v1', secret.apiVersion)
+ assert_equal('Y2F0J3MgYXJlIGF3ZXNvbWUK', secret.data['super-secret'])
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret',
+ times: 1)
+ end
+
+ def test_delete_secret_v1
+ stub_core_api_list
+ stub_request(:delete, %r{/secrets})
+ .to_return(status: 200, body: open_test_file('created_secret.json'))
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ secret = client.delete_secret('test-secret', 'dev')
+ assert_kind_of(RecursiveOpenStruct, secret)
+
+ assert_requested(:delete,
+ 'http://localhost:8080/api/v1/namespaces/dev/secrets/test-secret',
+ times: 1)
+ end
+
+ def test_create_secret_v1
+ stub_core_api_list
+ stub_request(:post, %r{/secrets})
+ .to_return(body: open_test_file('created_secret.json'),
+ status: 201)
+
+ secret = Kubeclient::Resource.new
+ secret.metadata = {}
+ secret.metadata.name = 'test-secret'
+ secret.metadata.namespace = 'dev'
+ secret.data = {}
+ secret.data['super-secret'] = 'Y2F0J3MgYXJlIGF3ZXNvbWUK'
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ created_secret = client.create_secret(secret)
+ assert_instance_of(Kubeclient::Resource, created_secret)
+ assert_equal(secret.metadata.name, created_secret.metadata.name)
+ assert_equal(secret.metadata.namespace, created_secret.metadata.namespace)
+ assert_equal(
+ secret.data['super-secret'],
+ created_secret.data['super-secret']
+ )
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_security_context_constraint.rb b/vendor/gems/kubeclient/test/test_security_context_constraint.rb
new file mode 100644
index 00000000000..23e53c4464e
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_security_context_constraint.rb
@@ -0,0 +1,62 @@
+require_relative 'test_helper'
+
+# kind: 'SecurityContextConstraints' entity tests.
+# This is one of the unusual `kind`s that are already plural (https://github.com/kubernetes/kubernetes/issues/8115).
+# We force singular in method names like 'create_endpoint',
+# but `kind` should remain plural as in kubernetes.
+class TestSecurityContextConstraints < MiniTest::Test
+ def test_create_security_context_constraint
+ stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
+ body: open_test_file('security.openshift.io_api_resource_list.json'),
+ status: 200
+ )
+
+ testing_scc = Kubeclient::Resource.new(
+ metadata: {
+ name: 'teleportation'
+ },
+ runAsUser: {
+ type: 'MustRunAs'
+ },
+ seLinuxContext: {
+ type: 'MustRunAs'
+ }
+ )
+ req_body = '{"metadata":{"name":"teleportation"},"runAsUser":{"type":"MustRunAs"},' \
+ '"seLinuxContext":{"type":"MustRunAs"},' \
+ '"kind":"SecurityContextConstraints","apiVersion":"security.openshift.io/v1"}'
+
+ stub_request(:post, 'http://localhost:8080/apis/security.openshift.io/v1/securitycontextconstraints')
+ .with(body: req_body)
+ .to_return(body: open_test_file('created_security_context_constraint.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
+ created_scc = client.create_security_context_constraint(testing_scc)
+ assert_equal('SecurityContextConstraints', created_scc.kind)
+ assert_equal('security.openshift.io/v1', created_scc.apiVersion)
+
+ client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1',
+ as: :parsed_symbolized)
+ created_scc = client.create_security_context_constraint(testing_scc)
+ assert_equal('SecurityContextConstraints', created_scc[:kind])
+ assert_equal('security.openshift.io/v1', created_scc[:apiVersion])
+ end
+
+ def test_get_security_context_constraints
+ stub_request(:get, %r{/apis/security.openshift.io/v1$}).to_return(
+ body: open_test_file('security.openshift.io_api_resource_list.json'),
+ status: 200
+ )
+ stub_request(:get, %r{/securitycontextconstraints})
+ .to_return(body: open_test_file('security_context_constraint_list.json'), status: 200)
+ client = Kubeclient::Client.new('http://localhost:8080/apis/security.openshift.io', 'v1')
+
+ collection = client.get_security_context_constraints(as: :parsed_symbolized)
+ assert_equal('SecurityContextConstraintsList', collection[:kind])
+ assert_equal('security.openshift.io/v1', collection[:apiVersion])
+
+ # Stripping of 'List' in collection.kind RecursiveOpenStruct mode only is historic.
+ collection = client.get_security_context_constraints
+ assert_equal('SecurityContextConstraints', collection.kind)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_service.rb b/vendor/gems/kubeclient/test/test_service.rb
new file mode 100644
index 00000000000..6ef3368780d
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_service.rb
@@ -0,0 +1,357 @@
+require_relative 'test_helper'
+
+# Service entity tests
+class TestService < MiniTest::Test
+ def test_construct_our_own_service
+ our_service = Kubeclient::Resource.new
+ our_service.metadata = {}
+ our_service.metadata.name = 'guestbook'
+ our_service.metadata.namespace = 'staging'
+ our_service.metadata.labels = {}
+ our_service.metadata.labels.name = 'guestbook'
+
+ our_service.spec = {}
+ our_service.spec.ports = [{
+ 'port' => 3000,
+ 'targetPort' => 'http-server',
+ 'protocol' => 'TCP'
+ }]
+
+ assert_equal('guestbook', our_service.metadata.labels.name)
+
+ hash = our_service.to_h
+
+ assert_equal(our_service.metadata.labels.name,
+ hash[:metadata][:labels][:name])
+
+ expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
+ stub_core_api_list
+ stub_request(:post, expected_url)
+ .to_return(body: open_test_file('created_service.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ created = client.create_service(our_service)
+
+ assert_instance_of(Kubeclient::Resource, created)
+ assert_equal(created.metadata.name, our_service.metadata.name)
+ assert_equal(created.spec.ports.size, our_service.spec.ports.size)
+
+ # Check that original entity_config is not modified by kind/apiVersion patches:
+ assert_nil(our_service.kind)
+
+ assert_requested(:post, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['kind'] == 'Service' &&
+ data['apiVersion'] == 'v1' &&
+ data['metadata']['name'] == 'guestbook' &&
+ data['metadata']['namespace'] == 'staging'
+ end
+ end
+
+ def test_construct_service_from_symbol_keys
+ service = Kubeclient::Resource.new
+ service.metadata = {
+ labels: { tier: 'frontend' },
+ name: 'test-service',
+ namespace: 'staging'
+ }
+ service.spec = {
+ ports: [{
+ port: 3000,
+ targetPort: 'http-server',
+ protocol: 'TCP'
+ }]
+ }
+
+ expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
+ stub_core_api_list
+ stub_request(:post, expected_url)
+ .to_return(body: open_test_file('created_service.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ client.create_service(service)
+
+ assert_requested(:post, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['kind'] == 'Service' &&
+ data['apiVersion'] == 'v1' &&
+ data['metadata']['name'] == 'test-service' &&
+ data['metadata']['labels']['tier'] == 'frontend' &&
+ data['metadata']['namespace'] == 'staging'
+ end
+ end
+
+ def test_construct_service_from_string_keys
+ service = Kubeclient::Resource.new
+ service.metadata = {
+ 'labels' => { 'tier' => 'frontend' },
+ 'name' => 'test-service',
+ 'namespace' => 'staging'
+ }
+ service.spec = {
+ 'ports' => [{
+ 'port' => 3000,
+ 'targetPort' => 'http-server',
+ 'protocol' => 'TCP'
+ }]
+ }
+
+ stub_core_api_list
+ expected_url = 'http://localhost:8080/api/v1/namespaces/staging/services'
+ stub_request(:post, %r{namespaces/staging/services})
+ .to_return(body: open_test_file('created_service.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ client.create_service(service)
+
+ assert_requested(:post, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['kind'] == 'Service' &&
+ data['apiVersion'] == 'v1' &&
+ data['metadata']['name'] == 'test-service' &&
+ data['metadata']['labels']['tier'] == 'frontend' &&
+ data['metadata']['namespace'] == 'staging'
+ end
+ end
+
+ def test_conversion_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/services})
+ .to_return(body: open_test_file('service.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ service = client.get_service('redis-slave', 'development')
+
+ assert_instance_of(Kubeclient::Resource, service)
+ assert_equal('2015-04-05T13:00:31Z',
+ service.metadata.creationTimestamp)
+ assert_equal('bdb80a8f-db93-11e4-b293-f8b156af4ae1', service.metadata.uid)
+ assert_equal('redis-slave', service.metadata.name)
+ assert_equal('2815', service.metadata.resourceVersion)
+ assert_equal('v1', service.apiVersion)
+ assert_equal('10.0.0.140', service.spec.clusterIP)
+ assert_equal('development', service.metadata.namespace)
+
+ assert_equal('TCP', service.spec.ports[0].protocol)
+ assert_equal(6379, service.spec.ports[0].port)
+ assert_equal('', service.spec.ports[0].name)
+ assert_equal('redis-server', service.spec.ports[0].targetPort)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave',
+ times: 1)
+ end
+
+ def test_delete_service
+ our_service = Kubeclient::Resource.new
+ our_service.name = 'redis-service'
+ # TODO, new ports assignment to be added
+ our_service.labels = {}
+ our_service.labels.component = 'apiserver'
+ our_service.labels.provider = 'kubernetes'
+
+ stub_core_api_list
+ stub_request(:delete, %r{/namespaces/default/services})
+ .to_return(body: open_test_file('service.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ our_service = client.delete_service(our_service.name, 'default')
+ assert_kind_of(RecursiveOpenStruct, our_service)
+
+ assert_requested(:delete,
+ 'http://localhost:8080/api/v1/namespaces/default/services/redis-service',
+ times: 1)
+ end
+
+ def test_get_service_no_ns
+ stub_core_api_list
+ # when not specifying namespace for entities which
+ # are not node or namespace, the request will fail
+ stub_request(:get, %r{/services/redis-slave})
+ .to_return(status: 404)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+
+ exception = assert_raises(Kubeclient::HttpError) do
+ client.get_service('redis-slave')
+ end
+ assert_equal(404, exception.error_code)
+ end
+
+ def test_get_service
+ stub_core_api_list
+ stub_request(:get, %r{/namespaces/development/services/redis-slave})
+ .to_return(body: open_test_file('service.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/')
+ service = client.get_service('redis-slave', 'development')
+ assert_equal('redis-slave', service.metadata.name)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/namespaces/development/services/redis-slave',
+ times: 1)
+ end
+
+ def test_update_service
+ service = Kubeclient::Resource.new
+ name = 'my_service'
+
+ service.metadata = {}
+ service.metadata.name = name
+ service.metadata.namespace = 'development'
+
+ stub_core_api_list
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
+ stub_request(:put, expected_url)
+ .to_return(body: open_test_file('service_update.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.update_service(service)
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:put, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['metadata']['name'] == name &&
+ data['metadata']['namespace'] == 'development'
+ end
+ end
+
+ def test_update_service_with_string_keys
+ service = Kubeclient::Resource.new
+ name = 'my_service'
+
+ service.metadata = {
+ 'name' => name,
+ 'namespace' => 'development'
+ }
+
+ stub_core_api_list
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
+ stub_request(:put, expected_url)
+ .to_return(body: open_test_file('service_update.json'), status: 201)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.update_service(service)
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:put, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['metadata']['name'] == name &&
+ data['metadata']['namespace'] == 'development'
+ end
+ end
+
+ def test_patch_service
+ service = Kubeclient::Resource.new
+ name = 'my_service'
+
+ service.metadata = {}
+ service.metadata.name = name
+ service.metadata.namespace = 'development'
+
+ stub_core_api_list
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
+ stub_request(:patch, expected_url)
+ .to_return(body: open_test_file('service_patch.json'), status: 200)
+
+ patch = {
+ metadata: {
+ annotations: {
+ key: 'value'
+ }
+ }
+ }
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.patch_service(name, patch, 'development')
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:patch, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ data['metadata']['annotations']['key'] == 'value'
+ end
+ end
+
+ def test_apply_service
+ service = Kubeclient::Resource.new
+ name = 'my_service'
+
+ service.metadata = {}
+ service.metadata.name = name
+ service.metadata.namespace = 'development'
+ service.metadata.annotations = {}
+ service.metadata.annotations['key'] = 'value'
+
+ stub_core_api_list
+ resource_name = "#{name}?fieldManager=myapp&force=true"
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{resource_name}"
+ stub_request(:patch, expected_url)
+ .to_return(body: open_test_file('service_patch.json'), status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.apply_service(service, field_manager: 'myapp')
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:patch, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ req.headers['Content-Type'] == 'application/apply-patch+yaml' &&
+ data['metadata']['annotations']['key'] == 'value'
+ end
+ end
+
+ def test_json_patch_service
+ service = Kubeclient::Resource.new
+ name = 'my-service'
+
+ service.metadata = {}
+ service.metadata.name = name
+ service.metadata.namespace = 'development'
+
+ stub_core_api_list
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
+ stub_request(:patch, expected_url)
+ .to_return(body: open_test_file('service_json_patch.json'), status: 200)
+
+ patch = [
+ { 'op' => 'add', 'path' => '/spec/type', 'value' => 'LoadBalancer' }
+ ]
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.json_patch_service(name, patch, 'development')
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:patch, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ req.headers['Content-Type'] == 'application/json-patch+json' &&
+ data == patch
+ end
+ end
+
+ def test_merge_patch_service
+ service = Kubeclient::Resource.new
+ name = 'my-service'
+
+ service.metadata = {}
+ service.metadata.name = name
+ service.metadata.namespace = 'development'
+
+ stub_core_api_list
+ expected_url = "http://localhost:8080/api/v1/namespaces/development/services/#{name}"
+ stub_request(:patch, expected_url)
+ .to_return(body: open_test_file('service_merge_patch.json'), status: 200)
+
+ patch = { spec: { type: 'NodePort' } }
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ service = client.merge_patch_service(name, patch, 'development')
+ assert_kind_of(RecursiveOpenStruct, service)
+
+ assert_requested(:patch, expected_url, times: 1) do |req|
+ data = JSON.parse(req.body)
+ req.headers['Content-Type'] == 'application/merge-patch+json' &&
+ data['spec']['type'] == 'NodePort'
+ end
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_service_account.rb b/vendor/gems/kubeclient/test/test_service_account.rb
new file mode 100644
index 00000000000..87a08a215bd
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_service_account.rb
@@ -0,0 +1,26 @@
+require_relative 'test_helper'
+
+# ServiceAccount tests
+class TestServiceAccount < MiniTest::Test
+ def test_get_from_json_v1
+ stub_core_api_list
+ stub_request(:get, %r{/serviceaccounts})
+ .to_return(body: open_test_file('service_account.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ account = client.get_service_account('default')
+
+ assert_instance_of(Kubeclient::Resource, account)
+ assert_equal('default', account.metadata.name)
+ assert_equal('default-token-6s23q', account.secrets[0].name)
+ assert_equal('default-dockercfg-62tf3', account.secrets[1].name)
+
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1/serviceaccounts/default',
+ times: 1)
+ assert_requested(:get,
+ 'http://localhost:8080/api/v1',
+ times: 1)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/test_watch.rb b/vendor/gems/kubeclient/test/test_watch.rb
new file mode 100644
index 00000000000..8d74008c851
--- /dev/null
+++ b/vendor/gems/kubeclient/test/test_watch.rb
@@ -0,0 +1,195 @@
+require_relative 'test_helper'
+
+# Watch entity tests
+class TestWatch < MiniTest::Test
+ def test_watch_pod_success
+ stub_core_api_list
+
+ expected = [
+ { 'type' => 'ADDED', 'resourceVersion' => '1389' },
+ { 'type' => 'MODIFIED', 'resourceVersion' => '1390' },
+ { 'type' => 'DELETED', 'resourceVersion' => '1398' }
+ ]
+
+ stub_request(:get, %r{/watch/pods})
+ .to_return(body: open_test_file('watch_stream.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ client.watch_pods.to_enum.with_index do |notice, index|
+ assert_instance_of(Kubeclient::Resource, notice)
+ assert_equal(expected[index]['type'], notice.type)
+ assert_equal('Pod', notice.object.kind)
+ assert_equal('php', notice.object.metadata.name)
+ assert_equal(expected[index]['resourceVersion'],
+ notice.object.metadata.resourceVersion)
+ end
+ end
+
+ def test_watch_pod_block
+ stub_core_api_list
+ stub_request(:get, %r{/watch/pods})
+ .to_return(body: open_test_file('watch_stream.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ yielded = []
+ client.watch_pods { |notice| yielded << notice.type }
+
+ assert_equal %w[ADDED MODIFIED DELETED], yielded
+ end
+
+ def test_watch_pod_raw
+ stub_core_api_list
+
+ stub_request(:get, %r{/watch/pods}).to_return(
+ body: open_test_file('watch_stream.json'),
+ status: 200
+ )
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ got = nil
+ client.watch_pods(as: :raw).each { |notice| got = notice }
+ assert_match(/\A{"type":"DELETED"/, got)
+ end
+
+ def test_watch_pod_failure
+ stub_core_api_list
+ stub_request(:get, %r{/watch/pods}).to_return(status: 404)
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+ assert_raises(Kubeclient::HttpError) do
+ client.watch_pods.each do
+ end
+ end
+ end
+
+ def test_watch_pod_follow_redirect
+ stub_core_api_list
+
+ redirect = 'http://localhost:1234/api/v1/watch/pods'
+ stub_request(:get, %r{/watch/pods})
+ .to_return(status: 302, headers: { location: redirect })
+
+ stub_request(:get, redirect).to_return(
+ body: open_test_file('watch_stream.json'),
+ status: 200
+ )
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1')
+
+ got = nil
+ client.watch_pods.each { |notice| got = notice }
+ assert_equal('DELETED', got.type)
+ end
+
+ def test_watch_pod_max_redirect
+ stub_core_api_list
+
+ redirect = 'http://localhost:1234/api/v1/watcher/pods'
+ stub_request(:get, %r{/watch/pods})
+ .to_return(status: 302, headers: { location: redirect })
+
+ stub_request(:get, redirect).to_return(
+ body: open_test_file('watch_stream.json'),
+ status: 200
+ )
+
+ client = Kubeclient::Client.new('http://localhost:8080/api/', 'v1', http_max_redirects: 0)
+
+ assert_raises(Kubeclient::HttpError) do
+ client.watch_pods.each do
+ end
+ end
+ end
+
+ # Ensure that WatchStream respects a format that's not JSON
+ def test_watch_stream_text
+ url = 'http://www.example.com/foobar'
+ expected_lines = open_test_file('pod_log.txt').read.split("\n")
+
+ stub_request(:get, url)
+ .to_return(body: open_test_file('pod_log.txt'),
+ status: 200)
+
+ stream = Kubeclient::Common::WatchStream.new(URI.parse(url), {}, formatter: ->(v) { v })
+ stream.to_enum.with_index do |line, index|
+ assert_instance_of(String, line)
+ assert_equal(expected_lines[index], line)
+ end
+ end
+
+ def test_watch_with_resource_version
+ api_host = 'http://localhost:8080/api'
+ version = '1995'
+ stub_core_api_list
+ stub_request(:get, %r{.*\/watch/events})
+ .to_return(body: open_test_file('watch_stream.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new(api_host, 'v1')
+ results = client.watch_events(version).to_enum
+
+ assert_equal(3, results.count)
+ assert_requested(:get,
+ "#{api_host}/v1/watch/events?resourceVersion=#{version}",
+ times: 1)
+ end
+
+ def test_watch_with_label_selector
+ api_host = 'http://localhost:8080/api'
+ selector = 'name=redis-master'
+
+ stub_core_api_list
+ stub_request(:get, %r{.*\/watch/events})
+ .to_return(body: open_test_file('watch_stream.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new(api_host, 'v1')
+ results = client.watch_events(label_selector: selector).to_enum
+
+ assert_equal(3, results.count)
+ assert_requested(:get,
+ "#{api_host}/v1/watch/events?labelSelector=#{selector}",
+ times: 1)
+ end
+
+ def test_watch_with_field_selector
+ api_host = 'http://localhost:8080/api'
+ selector = 'involvedObject.kind=Pod'
+
+ stub_core_api_list
+ stub_request(:get, %r{.*\/watch/events})
+ .to_return(body: open_test_file('watch_stream.json'),
+ status: 200)
+
+ client = Kubeclient::Client.new(api_host, 'v1')
+ results = client.watch_events(field_selector: selector).to_enum
+
+ assert_equal(3, results.count)
+ assert_requested(:get,
+ "#{api_host}/v1/watch/events?fieldSelector=#{selector}",
+ times: 1)
+ end
+
+ def test_watch_with_finish_and_ebadf
+ api_host = 'http://localhost:8080/api'
+
+ stub_core_api_list
+ stub_request(:get, %r{.*\/watch/events})
+ .to_return(body: open_test_file('watch_stream.json'), status: 200)
+
+ client = Kubeclient::Client.new(api_host, 'v1')
+ watcher = client.watch_events
+
+ # explodes when StandardError is not caught
+ watcher.each do
+ watcher.finish
+ raise StandardError
+ end
+
+ assert_requested(:get, "#{api_host}/v1/watch/events", times: 1)
+ end
+end
diff --git a/vendor/gems/kubeclient/test/txt/pod_log.txt b/vendor/gems/kubeclient/test/txt/pod_log.txt
new file mode 100644
index 00000000000..9f9a75157aa
--- /dev/null
+++ b/vendor/gems/kubeclient/test/txt/pod_log.txt
@@ -0,0 +1,6 @@
+Initializing server...
+...loaded configuration
+...updated settings
+...discovered local servers
+...frobinated disks
+Complete!
diff --git a/vendor/gems/kubeclient/test/valid_token_file b/vendor/gems/kubeclient/test/valid_token_file
new file mode 100644
index 00000000000..df2c2eb6572
--- /dev/null
+++ b/vendor/gems/kubeclient/test/valid_token_file
@@ -0,0 +1 @@
+valid_token