k8y 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/k8y.gemspec +2 -4
- data/lib/k8y/client/api_builder.rb +3 -2
- data/lib/k8y/client/client.rb +0 -5
- data/lib/k8y/client.rb +5 -0
- data/lib/k8y/kubeconfig/auth_info.rb +0 -2
- data/lib/k8y/kubeconfig/cluster.rb +1 -1
- data/lib/k8y/kubeconfig/config.rb +10 -8
- data/lib/k8y/kubeconfig.rb +41 -2
- data/lib/k8y/rest/auth.rb +77 -0
- data/lib/k8y/rest/client.rb +72 -0
- data/lib/k8y/rest/config.rb +37 -0
- data/lib/k8y/rest/config_validator.rb +48 -0
- data/lib/k8y/rest/connection.rb +31 -0
- data/lib/k8y/rest/error.rb +6 -0
- data/lib/k8y/{client → rest}/response_formatter.rb +1 -1
- data/lib/k8y/rest/transport.rb +88 -0
- data/lib/k8y/rest.rb +8 -0
- data/lib/k8y/version.rb +1 -1
- data/lib/k8y.rb +1 -0
- metadata +20 -13
- data/lib/k8y/client/rest_client.rb +0 -90
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 967e0fcf49dc5ff373df45925be7c14ee0d8da75d12f348373cc70c72621ff23
|
4
|
+
data.tar.gz: e02d82838c724f96557d3769421a2ba40557dba6501f012433b1be64ef4204f9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5937b19b84140f2a81c0935bce8892c92ae709eb8382ce658297911f65790b311e847c92ae71887d33a6920beca1f8f69d535ab32ce125d6f697cbad0dd99c51
|
7
|
+
data.tar.gz: c4635b0a99227890b7ef4dc7c88ab285771d83ea5926a53b599e90f6e5ff20965c5b51b72ad062f513716b598322422eea53825d908094c9441ae32eac54cc59
|
data/CHANGELOG.md
CHANGED
@@ -1 +1,17 @@
|
|
1
1
|
## next
|
2
|
+
|
3
|
+
## 0.2.0
|
4
|
+
|
5
|
+
**Enhancements**
|
6
|
+
|
7
|
+
- K8y::Client::from_in_cluster for easily building in-cluster clients [#23](https://github.com/tsontario/k8y/pull/23)
|
8
|
+
|
9
|
+
**Testing**
|
10
|
+
|
11
|
+
- Integration test suite to run against (KinD) cluster [#11](https://github.com/tsontario/k8y/pull/11)
|
12
|
+
- Run integration tests in parallel [#22](https://github.com/tsontario/k8y/pull/22)
|
13
|
+
|
14
|
+
**Design**
|
15
|
+
|
16
|
+
- Move generated API methods (get_pods, delete_service, etc.) into separate API class, out of top-level K8y::Client::Client [#17](https://github.com/tsontario/k8y/pull/17)
|
17
|
+
|
data/k8y.gemspec
CHANGED
@@ -13,8 +13,6 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.homepage = "https://github.com/tsontario/k8y"
|
14
14
|
spec.required_ruby_version = Gem::Requirement.new(">= 2.7.0")
|
15
15
|
|
16
|
-
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
17
|
-
|
18
16
|
spec.metadata["homepage_uri"] = spec.homepage
|
19
17
|
spec.metadata["source_code_uri"] = spec.homepage
|
20
18
|
spec.metadata["changelog_uri"] = spec.homepage
|
@@ -28,10 +26,10 @@ Gem::Specification.new do |spec|
|
|
28
26
|
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
29
27
|
spec.require_paths = ["lib"]
|
30
28
|
|
29
|
+
spec.add_dependency("activesupport", "~> 6.0")
|
31
30
|
spec.add_dependency("faraday", "~> 1.6")
|
32
|
-
spec.add_dependency("recursive-open-struct", "~>1.1")
|
33
31
|
spec.add_dependency("railties", "~> 6.0")
|
34
|
-
spec.add_dependency("
|
32
|
+
spec.add_dependency("recursive-open-struct", "~>1.1")
|
35
33
|
|
36
34
|
spec.add_development_dependency("byebug", "~> 11")
|
37
35
|
spec.add_development_dependency("minitest", "~> 5")
|
@@ -27,12 +27,13 @@ module K8y
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def build!
|
30
|
-
|
30
|
+
rest_config = REST::Config.from_kubeconfig(config, path: api.path)
|
31
|
+
rest_client = REST::Client.new(connection: REST::Connection.from_config(rest_config))
|
32
|
+
|
31
33
|
response = rest_client.get(as: :raw)
|
32
34
|
resource_descriptions = JSON.parse(response.body)["resources"].map do |resource_description|
|
33
35
|
ResourceDescription.from_hash(resource_description)
|
34
36
|
end
|
35
|
-
|
36
37
|
resource_descriptions.each do |resource_description|
|
37
38
|
next if resource_description.subresource?
|
38
39
|
|
data/lib/k8y/client/client.rb
CHANGED
@@ -1,6 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative "rest_client"
|
4
3
|
require_relative "api_builder"
|
5
4
|
require_relative "apis"
|
6
5
|
|
@@ -22,10 +21,6 @@ module K8y
|
|
22
21
|
apis.each { |api| APIBuilder.new(api: api, config: config, context: context.name).build! }
|
23
22
|
end
|
24
23
|
|
25
|
-
def set_context(context_name)
|
26
|
-
@context = config.context(context_name)
|
27
|
-
end
|
28
|
-
|
29
24
|
def method_missing(method_name, *args, &block)
|
30
25
|
candidate_apis = apis.apis_for_method(method_name)
|
31
26
|
case candidate_apis.length
|
data/lib/k8y/client.rb
CHANGED
@@ -13,5 +13,10 @@ module K8y
|
|
13
13
|
def self.from_config(config, context: nil, group_versions: DEFAULT_GROUP_VERSIONS)
|
14
14
|
Client.new(config: config, context: context || config.current_context, group_versions: group_versions)
|
15
15
|
end
|
16
|
+
|
17
|
+
def self.from_in_cluster(group_versions: DEFAULT_GROUP_VERSIONS)
|
18
|
+
config = Kubeconfig.in_cluster_config
|
19
|
+
Client.new(config: config, context: Kubeconfig::IN_CLUSTER_NAME, group_versions: group_versions)
|
20
|
+
end
|
16
21
|
end
|
17
22
|
end
|
@@ -18,9 +18,7 @@ module K8y
|
|
18
18
|
as_user_extra: hash.fetch("as-user-extra", nil),
|
19
19
|
username: hash.fetch("username", nil),
|
20
20
|
password: hash.fetch("password", nil),
|
21
|
-
# TODO: this needs something like polymorphic classes, not just raw hash, eventually
|
22
21
|
auth_provider: hash.fetch("auth-provider", nil),
|
23
|
-
# TODO: This will likely benefit from actual domain models eventually, as well.
|
24
22
|
exec_options: hash.fetch("exec", nil),
|
25
23
|
extensions: hash.fetch("extensions", nil)
|
26
24
|
)
|
@@ -28,7 +28,7 @@ module K8y
|
|
28
28
|
raise Error, e
|
29
29
|
end
|
30
30
|
|
31
|
-
def initialize(api_version
|
31
|
+
def initialize(api_version: "v1", kind: "Config", preferences: {}, clusters:, contexts:, users:, current_context:)
|
32
32
|
@api_version = api_version
|
33
33
|
@kind = kind
|
34
34
|
@preferences = preferences
|
@@ -38,9 +38,11 @@ module K8y
|
|
38
38
|
@current_context = current_context
|
39
39
|
end
|
40
40
|
|
41
|
-
def context(
|
42
|
-
context
|
43
|
-
|
41
|
+
def context(context)
|
42
|
+
return context if context.is_a?(Context)
|
43
|
+
|
44
|
+
context = contexts.find { |c| c.name == context }
|
45
|
+
raise ContextNotFoundError, "Could not find context #{context} in config" unless context
|
44
46
|
context
|
45
47
|
end
|
46
48
|
|
@@ -56,13 +58,13 @@ module K8y
|
|
56
58
|
user
|
57
59
|
end
|
58
60
|
|
59
|
-
def cluster_for_context(
|
60
|
-
cluster_name = context(
|
61
|
+
def cluster_for_context(context)
|
62
|
+
cluster_name = context(context).cluster
|
61
63
|
cluster(cluster_name)
|
62
64
|
end
|
63
65
|
|
64
|
-
def user_for_context(
|
65
|
-
user(context(
|
66
|
+
def user_for_context(context)
|
67
|
+
user(context(context).user)
|
66
68
|
end
|
67
69
|
end
|
68
70
|
end
|
data/lib/k8y/kubeconfig.rb
CHANGED
@@ -5,12 +5,51 @@ require_relative "kubeconfig/config"
|
|
5
5
|
module K8y
|
6
6
|
module Kubeconfig
|
7
7
|
Error = Class.new(Error)
|
8
|
+
NotInClusterError = Class.new(Error)
|
8
9
|
|
9
|
-
|
10
|
+
IN_CLUSTER_NAME = "in-cluster"
|
10
11
|
|
11
|
-
|
12
|
+
TOKEN_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/token"
|
13
|
+
ROOT_CA_FILE = "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"
|
14
|
+
|
15
|
+
def self.from_file(file = File.open(ENV["KUBECONFIG"]))
|
12
16
|
hash = YAML.safe_load(file.read, permitted_classes: [Date, Time])
|
13
17
|
Config.from_hash(hash)
|
14
18
|
end
|
19
|
+
|
20
|
+
def self.in_cluster_config
|
21
|
+
host = ENV.fetch("KUBERNETES_SERVICE_HOST", nil)
|
22
|
+
port = ENV.fetch("KUBERNETES_SERVICE_PORT", nil)
|
23
|
+
raise NotInClusterError unless host && port
|
24
|
+
|
25
|
+
token_data = File.read(TOKEN_FILE)
|
26
|
+
auth_info = AuthInfo.new(token: token_data, token_file: TOKEN_FILE)
|
27
|
+
user = User.new(
|
28
|
+
name: IN_CLUSTER_NAME,
|
29
|
+
auth_info: auth_info
|
30
|
+
)
|
31
|
+
|
32
|
+
ca_data = Base64.encode64(File.read(ROOT_CA_FILE))
|
33
|
+
cluster = Cluster.new(
|
34
|
+
name: IN_CLUSTER_NAME,
|
35
|
+
insecure_skip_tls_verify: false,
|
36
|
+
certificate_authority: nil,
|
37
|
+
certificate_authority_data: ca_data,
|
38
|
+
server: "https://#{host}:#{port}",
|
39
|
+
)
|
40
|
+
context = Context.new(
|
41
|
+
name: IN_CLUSTER_NAME,
|
42
|
+
cluster: IN_CLUSTER_NAME,
|
43
|
+
namespace: nil,
|
44
|
+
user: IN_CLUSTER_NAME
|
45
|
+
)
|
46
|
+
|
47
|
+
Config.new(
|
48
|
+
clusters: [cluster],
|
49
|
+
contexts: [context],
|
50
|
+
current_context: context,
|
51
|
+
users: [user]
|
52
|
+
)
|
53
|
+
end
|
15
54
|
end
|
16
55
|
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module K8y
|
3
|
+
module REST
|
4
|
+
class Auth
|
5
|
+
InvalidAuthTypeError = Class.new(Error)
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_kubeconfig(kubeconfig, context: nil)
|
9
|
+
context = context ? context : kubeconfig.current_context
|
10
|
+
auth_info = kubeconfig.user_for_context(context).auth_info
|
11
|
+
|
12
|
+
new(token: token(auth_info), username: auth_info.username, password: auth_info.password,
|
13
|
+
auth_provider: auth_provider(auth_info), exec_provider: exec_provider(auth_info))
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def token(auth_info)
|
19
|
+
return auth_info.token if auth_info.token
|
20
|
+
File.read(auth_info.token_file) if auth_info.token_file
|
21
|
+
end
|
22
|
+
|
23
|
+
def auth_provider(auth_info)
|
24
|
+
# TODO
|
25
|
+
end
|
26
|
+
|
27
|
+
def exec_provider(auth_info)
|
28
|
+
# TODO
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(token: nil, username: nil, password: nil, auth_provider: nil, exec_provider: nil)
|
33
|
+
@token = token
|
34
|
+
@username = username
|
35
|
+
@password = password
|
36
|
+
@auth_provider = auth_provider
|
37
|
+
@exec_provider = exec_provider
|
38
|
+
end
|
39
|
+
|
40
|
+
def configure_connection(connection)
|
41
|
+
case auth_type
|
42
|
+
when :basic
|
43
|
+
connection.basic_auth(username, password)
|
44
|
+
when :token
|
45
|
+
connection.headers[:Authorization] = "Bearer #{token}"
|
46
|
+
# TODO...
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
attr_reader :token, :username, :password, :auth_provider, :exec_provider
|
53
|
+
|
54
|
+
def auth_type
|
55
|
+
if username && password
|
56
|
+
:basic
|
57
|
+
elsif token
|
58
|
+
:token
|
59
|
+
elsif auth_provider
|
60
|
+
:auth_provider
|
61
|
+
elsif exec_provider
|
62
|
+
:exec_provider
|
63
|
+
else
|
64
|
+
:none
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def basic?
|
69
|
+
auth_type == :basic
|
70
|
+
end
|
71
|
+
|
72
|
+
def token?
|
73
|
+
auth_type == :token
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "faraday"
|
4
|
+
require "base64"
|
5
|
+
require "recursive_open_struct"
|
6
|
+
|
7
|
+
require_relative "config"
|
8
|
+
require_relative "connection"
|
9
|
+
require_relative "response_formatter"
|
10
|
+
|
11
|
+
module K8y
|
12
|
+
module REST
|
13
|
+
class Client
|
14
|
+
attr_reader :connection
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def from_config(config)
|
18
|
+
new(
|
19
|
+
connection: Connection.new(
|
20
|
+
host: config.host,
|
21
|
+
ssl: config.transport.to_faraday_options,
|
22
|
+
auth: config.auth
|
23
|
+
)
|
24
|
+
)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def host
|
29
|
+
connection.host
|
30
|
+
end
|
31
|
+
|
32
|
+
def initialize(connection:)
|
33
|
+
@connection = connection
|
34
|
+
end
|
35
|
+
|
36
|
+
def get(path = "", headers: {}, as: :ros)
|
37
|
+
response = connection.get(formatted_uri(path))
|
38
|
+
format_response(response, as: as)
|
39
|
+
end
|
40
|
+
|
41
|
+
def post(path = "", data:, headers: {}, as: :ros)
|
42
|
+
response = connection.post(formatted_uri(path), data, headers)
|
43
|
+
format_response(response, as: as)
|
44
|
+
end
|
45
|
+
|
46
|
+
def put(path = "", data:, headers: {}, as: :ros)
|
47
|
+
response = connection.put(formatted_uri(path), data, headers)
|
48
|
+
format_response(response, as: as)
|
49
|
+
end
|
50
|
+
|
51
|
+
def patch(path = "", strategy:, data:, headers: {}, as: :ros)
|
52
|
+
response = connection.patch(formatted_uri(path), data, headers)
|
53
|
+
format_response(response, as: as)
|
54
|
+
end
|
55
|
+
|
56
|
+
def delete(path = "", headers: {}, as: :ros)
|
57
|
+
response = connection.delete(formatted_uri(path))
|
58
|
+
format_response(response, as: as)
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
|
63
|
+
def formatted_uri(path = "")
|
64
|
+
File.join(connection.host, path)
|
65
|
+
end
|
66
|
+
|
67
|
+
def format_response(response, as: :ros)
|
68
|
+
ResponseFormatter.new(response).format(as: as)
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative "config_validator"
|
3
|
+
require_relative "transport"
|
4
|
+
require_relative "auth"
|
5
|
+
|
6
|
+
module K8y
|
7
|
+
module REST
|
8
|
+
class Config
|
9
|
+
attr_reader :host, :transport, :auth
|
10
|
+
|
11
|
+
class << self
|
12
|
+
def from_kubeconfig(kubeconfig, path:)
|
13
|
+
context = context ? context : kubeconfig.current_context
|
14
|
+
ConfigValidator.new(kubeconfig, context: context).validate!
|
15
|
+
|
16
|
+
cluster = kubeconfig.cluster_for_context(context)
|
17
|
+
host = File.join(cluster.server, path)
|
18
|
+
transport = if URI(host).scheme == "https"
|
19
|
+
Transport.from_kubeconfig(kubeconfig, context: context)
|
20
|
+
end
|
21
|
+
auth = Auth.from_kubeconfig(kubeconfig, context: context)
|
22
|
+
new(
|
23
|
+
host: host,
|
24
|
+
transport: transport,
|
25
|
+
auth: auth
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def initialize(host:, transport:, auth:)
|
31
|
+
@host = host
|
32
|
+
@transport = transport
|
33
|
+
@auth = auth
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module K8y
|
3
|
+
module REST
|
4
|
+
class ConfigValidator
|
5
|
+
class ValidationError < Error
|
6
|
+
def initialize(validation_errors)
|
7
|
+
super
|
8
|
+
@message = "Kubeconfig validation failed with the following errors: " + validation_errors.join(",")
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
VALIDATIONS = [
|
13
|
+
:validate_auth_info,
|
14
|
+
:validate_context,
|
15
|
+
:validate_cluster,
|
16
|
+
:validate_usable,
|
17
|
+
].freeze
|
18
|
+
|
19
|
+
def initialize(kubeconfig, context:)
|
20
|
+
@kubeconfig = kubeconfig
|
21
|
+
@context = context
|
22
|
+
end
|
23
|
+
|
24
|
+
def validate!
|
25
|
+
errors = VALIDATIONS.map { |validation| send(validation) }.compact
|
26
|
+
raise ValidationError, errors if errors.present?
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def validate_auth_info
|
32
|
+
# TODO
|
33
|
+
end
|
34
|
+
|
35
|
+
def validate_context
|
36
|
+
# TODO
|
37
|
+
end
|
38
|
+
|
39
|
+
def validate_cluster
|
40
|
+
# TODO
|
41
|
+
end
|
42
|
+
|
43
|
+
def validate_usable
|
44
|
+
# TODO
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "forwardable"
|
4
|
+
|
5
|
+
module K8y
|
6
|
+
module REST
|
7
|
+
class Connection
|
8
|
+
extend Forwardable
|
9
|
+
|
10
|
+
attr_reader :host, :connection
|
11
|
+
|
12
|
+
VERBS = [:get, :post, :put, :patch, :delete]
|
13
|
+
def_delegators(:connection, *VERBS)
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Initialize a Connection object using a provided REST::Config instance
|
17
|
+
def from_config(config)
|
18
|
+
new(host: config.host, ssl: config.transport.to_faraday_options, auth: config.auth)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(host:, ssl:, auth:, &conn_options)
|
23
|
+
@host = host
|
24
|
+
@connection = Faraday.new(host, ssl: ssl) do |connection|
|
25
|
+
auth.configure_connection(connection)
|
26
|
+
yield connection if block_given?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module K8y
|
3
|
+
module REST
|
4
|
+
class Transport
|
5
|
+
attr_reader :cert_file, :key_file, :ca_file, :cert_data, :key_data, :ca_data
|
6
|
+
|
7
|
+
class << self
|
8
|
+
def from_kubeconfig(kubeconfig, context: nil)
|
9
|
+
context = context ? context : kubeconfig.current_context
|
10
|
+
cluster = kubeconfig.cluster_for_context(context)
|
11
|
+
auth_info = kubeconfig.user_for_context(context).auth_info
|
12
|
+
|
13
|
+
transport = new(cert_file: auth_info.client_certificate, key_file: auth_info.client_key,
|
14
|
+
ca_file: cluster.certificate_authority, cert_data: auth_info.client_certificate_data,
|
15
|
+
key_data: auth_info.client_key_data, ca_data: cluster.certificate_authority_data)
|
16
|
+
transport.reconcile!
|
17
|
+
transport
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def initialize(cert_file: nil, key_file: nil, ca_file: nil, cert_data: nil, key_data: nil, ca_data: nil)
|
22
|
+
@cert_file = cert_file
|
23
|
+
@key_file = key_file
|
24
|
+
@ca_file = ca_file
|
25
|
+
|
26
|
+
@cert_data = cert_data
|
27
|
+
@key_data = key_data
|
28
|
+
@ca_data = ca_data
|
29
|
+
end
|
30
|
+
|
31
|
+
def reconcile!
|
32
|
+
return if reconciled?
|
33
|
+
reconcile_cert_data!
|
34
|
+
reconcile_key_data!
|
35
|
+
reconcile_ca_data!
|
36
|
+
|
37
|
+
@reconciled = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def to_faraday_options
|
41
|
+
if ca_data
|
42
|
+
cert_store = OpenSSL::X509::Store.new
|
43
|
+
cert_store.add_cert(OpenSSL::X509::Certificate.new(ca_data))
|
44
|
+
end
|
45
|
+
|
46
|
+
{
|
47
|
+
client_cert: (OpenSSL::X509::Certificate.new(cert_data) if cert_data),
|
48
|
+
client_key: (OpenSSL::PKey::RSA.new(key_data) if key_data),
|
49
|
+
cert_store: cert_store,
|
50
|
+
verify: OpenSSL::SSL::VERIFY_PEER,
|
51
|
+
}
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
attr_reader :reconciled
|
57
|
+
attr_writer :cert_data, :key_data, :ca_data
|
58
|
+
|
59
|
+
def reconcile_cert_data!
|
60
|
+
@cert_data = if cert_data
|
61
|
+
Base64.decode64(cert_data)
|
62
|
+
elsif cert_file
|
63
|
+
File.read(cert_file)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
def reconcile_key_data!
|
68
|
+
@key_data = if key_data
|
69
|
+
Base64.decode64(key_data)
|
70
|
+
elsif key_file
|
71
|
+
File.read(key_file)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def reconcile_ca_data!
|
76
|
+
@ca_data = if ca_data
|
77
|
+
Base64.decode64(ca_data)
|
78
|
+
elsif ca_file
|
79
|
+
File.read(ca_file)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def reconciled?
|
84
|
+
reconciled
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
data/lib/k8y/rest.rb
ADDED
data/lib/k8y/version.rb
CHANGED
data/lib/k8y.rb
CHANGED
metadata
CHANGED
@@ -1,43 +1,43 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: k8y
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Timothy Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-09-
|
11
|
+
date: 2021-09-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
19
|
+
version: '6.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '
|
26
|
+
version: '6.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: faraday
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.6'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.6'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: railties
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -53,19 +53,19 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '6.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: recursive-open-struct
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '1.1'
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '1.1'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: byebug
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
@@ -203,8 +203,6 @@ files:
|
|
203
203
|
- lib/k8y/client/apis.rb
|
204
204
|
- lib/k8y/client/client.rb
|
205
205
|
- lib/k8y/client/resource_description.rb
|
206
|
-
- lib/k8y/client/response_formatter.rb
|
207
|
-
- lib/k8y/client/rest_client.rb
|
208
206
|
- lib/k8y/error.rb
|
209
207
|
- lib/k8y/group_version.rb
|
210
208
|
- lib/k8y/kubeconfig.rb
|
@@ -213,6 +211,15 @@ files:
|
|
213
211
|
- lib/k8y/kubeconfig/config.rb
|
214
212
|
- lib/k8y/kubeconfig/context.rb
|
215
213
|
- lib/k8y/kubeconfig/user.rb
|
214
|
+
- lib/k8y/rest.rb
|
215
|
+
- lib/k8y/rest/auth.rb
|
216
|
+
- lib/k8y/rest/client.rb
|
217
|
+
- lib/k8y/rest/config.rb
|
218
|
+
- lib/k8y/rest/config_validator.rb
|
219
|
+
- lib/k8y/rest/connection.rb
|
220
|
+
- lib/k8y/rest/error.rb
|
221
|
+
- lib/k8y/rest/response_formatter.rb
|
222
|
+
- lib/k8y/rest/transport.rb
|
216
223
|
- lib/k8y/version.rb
|
217
224
|
homepage: https://github.com/tsontario/k8y
|
218
225
|
licenses: []
|
@@ -1,90 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "faraday"
|
4
|
-
require "base64"
|
5
|
-
require "recursive_open_struct"
|
6
|
-
|
7
|
-
require_relative "response_formatter"
|
8
|
-
|
9
|
-
module K8y
|
10
|
-
module Client
|
11
|
-
class RESTClient
|
12
|
-
attr_reader :context, :path
|
13
|
-
|
14
|
-
def initialize(config:, context:, path: "")
|
15
|
-
@config = config
|
16
|
-
@context = context
|
17
|
-
@path = path
|
18
|
-
|
19
|
-
# TODO: generically handle auth depending on provided config
|
20
|
-
hardcoded_auth
|
21
|
-
end
|
22
|
-
|
23
|
-
def get(sub_path = "", headers: {}, as: :ros)
|
24
|
-
response = connection.get(formatted_uri(host, path, sub_path))
|
25
|
-
format_response(response, as: as)
|
26
|
-
end
|
27
|
-
|
28
|
-
def post(sub_path = "", data:, headers: {}, as: :ros)
|
29
|
-
response = connection.post(formatted_uri(host, path, sub_path), data, headers)
|
30
|
-
format_response(response, as: as)
|
31
|
-
end
|
32
|
-
|
33
|
-
def put(sub_path = "", data:, headers: {}, as: :ros)
|
34
|
-
response = connection.put(formatted_uri(host, path, sub_path), data, headers)
|
35
|
-
format_response(response, as: as)
|
36
|
-
end
|
37
|
-
|
38
|
-
def patch(sub_path = "", strategy:, data:, headers: {}, as: :ros)
|
39
|
-
response = connection.patch(formatted_uri(host, path, sub_path), data, headers)
|
40
|
-
format_response(response, as: as)
|
41
|
-
end
|
42
|
-
|
43
|
-
def delete(sub_path = "", headers: {}, as: :ros)
|
44
|
-
response = connection.delete(formatted_uri(host, path, sub_path))
|
45
|
-
format_response(response, as: as)
|
46
|
-
end
|
47
|
-
|
48
|
-
private
|
49
|
-
|
50
|
-
attr_reader :config, :connection
|
51
|
-
|
52
|
-
def hardcoded_auth
|
53
|
-
cert_store = OpenSSL::X509::Store.new
|
54
|
-
cert_store.add_cert(OpenSSL::X509::Certificate.new(Base64.decode64(cluster.certificate_authority_data)))
|
55
|
-
@connection = Faraday.new(
|
56
|
-
host,
|
57
|
-
ssl: {
|
58
|
-
client_cert: OpenSSL::X509::Certificate.new(Base64.decode64(user.auth_info.client_certificate_data)),
|
59
|
-
client_key: OpenSSL::PKey::RSA.new(Base64.decode64(user.auth_info.client_key_data)),
|
60
|
-
cert_store: cert_store,
|
61
|
-
}
|
62
|
-
)
|
63
|
-
end
|
64
|
-
|
65
|
-
def host
|
66
|
-
cluster.server
|
67
|
-
end
|
68
|
-
|
69
|
-
def cluster
|
70
|
-
config.cluster_for_context(context)
|
71
|
-
end
|
72
|
-
|
73
|
-
def user
|
74
|
-
config.user_for_context(context)
|
75
|
-
end
|
76
|
-
|
77
|
-
def formatted_uri(host, path, sub_path = "")
|
78
|
-
if !sub_path.empty? && !path.end_with?("/")
|
79
|
-
URI.join(host, "#{path}/", sub_path)
|
80
|
-
else
|
81
|
-
URI.join(host, path, sub_path)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def format_response(response, as: :ros)
|
86
|
-
ResponseFormatter.new(response).format(as: as)
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
end
|