Skip to content
This repository was archived by the owner on Jun 12, 2021. It is now read-only.

Commit 88fd5d0

Browse files
committed
Support kube config
1 parent 6fcb1c7 commit 88fd5d0

File tree

9 files changed

+706
-0
lines changed

9 files changed

+706
-0
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# Copyright 2017 The Kubernetes Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
module Kubernetes
16+
class ConfigError < RuntimeError; end
17+
end
Lines changed: 180 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
# Copyright 2017 The Kubernetes Authors.
2+
#
3+
# Licensed under the Apache License, Version 2.0 (the "License");
4+
# you may not use this file except in compliance with the License.
5+
# You may obtain a copy of the License at
6+
#
7+
# http://www.apache.org/licenses/LICENSE-2.0
8+
#
9+
# Unless required by applicable law or agreed to in writing, software
10+
# distributed under the License is distributed on an "AS IS" BASIS,
11+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
# See the License for the specific language governing permissions and
13+
# limitations under the License.
14+
15+
require 'base64'
16+
require 'yaml'
17+
require 'tempfile'
18+
require 'uri'
19+
20+
require 'kubernetes/api_client'
21+
require 'kubernetes/configuration'
22+
require 'kubernetes/config/error'
23+
24+
module Kubernetes
25+
26+
class KubeConfig
27+
28+
KUBE_CONFIG_DEFAULT_LOCATION = File.expand_path('~/.kube/config')
29+
30+
class << self
31+
32+
#
33+
# Loads authentication and cluster information from kube-config file
34+
# and stores them in Kubernetes::Configuration.
35+
# @param config_file [String] Path of the kube-config file.
36+
# @param context [String] Set the active context. If is set to nil, current_context from config file will be used.
37+
# @param client_configuration [Kubernetes::Configuration] The Kubernetes::Configuration tp set configs to.
38+
def load(
39+
config_file=ENV['KUBE_CONFIG'],
40+
context: nil,
41+
client_configuration: Configuration.default
42+
)
43+
config_file ||= KUBE_CONFIG_DEFAULT_LOCATION
44+
config = self.new(config_file)
45+
config.configure(client_configuration, context)
46+
end
47+
48+
#
49+
# Loads configuration the same as load_kube_config but returns an ApiClient
50+
# to be used with any API object. This will allow the caller to concurrently
51+
# talk with multiple clusters.
52+
# @param config_file [String] Path of the kube-config file.
53+
# @param context [String] Set the active context. If is set to nil, current_context from config file will be used.
54+
# @return [Kubernetes::ApiClient] Api client for Kubernetes cluster
55+
def new_client(
56+
config_file=ENV['KUBE_CONFIG'],
57+
context: nil
58+
)
59+
config_file ||= KUBE_CONFIG_DEFAULT_LOCATION
60+
client_configuration = Configuration.new
61+
load(config_file, context: context, client_configuration: client_configuration)
62+
ApiClient.new(client_configuration)
63+
end
64+
65+
def list_context_names(config_file=KUBE_CONFIG_DEFAULT_LOCATION)
66+
config = self.new(config_file)
67+
return config.list_context_names
68+
end
69+
70+
end
71+
72+
@@temp_files = {}
73+
attr_accessor :path
74+
attr_writer :config
75+
76+
def initialize(path, config_hash=nil)
77+
@path = path
78+
@config = config_hash
79+
end
80+
81+
def base_path
82+
File.dirname(self.path)
83+
end
84+
85+
def config
86+
@config ||= open(self.path) do |io|
87+
::YAML.load(io.read)
88+
end
89+
end
90+
91+
def configure(configuration, context_name=nil)
92+
context = context_name ? self.find_context(context_name) : self.current_context
93+
user = context['user'] || {}
94+
cluster = context['cluster'] || {}
95+
96+
configuration.tap do |c|
97+
if user['authorization']
98+
c.api_key['authorization'] = user['authorization']
99+
end
100+
if server = cluster['server']
101+
server = URI.parse(server)
102+
c.scheme = server.scheme
103+
host = "#{server.host}:#{server.port}"
104+
host = "#{server.userinfo}@#{host}" if server.userinfo
105+
c.host = host
106+
c.base_path = server.path
107+
108+
if server.scheme == 'https'
109+
c.verify_ssl = cluster['verify_ssl']
110+
c.ssl_ca_cert = cluster['certificate-authority']
111+
c.cert_file = user['client-certificate']
112+
c.key_file = user['client-key']
113+
end
114+
end
115+
end
116+
end
117+
118+
def find_cluster(name)
119+
self.find_by_name(self.config['clusters'], 'cluster', name).tap do |cluster|
120+
create_temp_file_and_set(cluster, 'certificate-authority')
121+
cluster['verify_ssl'] = !cluster['insecure-skip-tls-verify']
122+
end
123+
end
124+
125+
def find_user(name)
126+
self.find_by_name(self.config['users'], 'user', name).tap do |user|
127+
create_temp_file_and_set(user, 'client-certificate')
128+
create_temp_file_and_set(user, 'client-key')
129+
# If tokenFile is specified, then set token
130+
if !user['token'] && user['tokenFile']
131+
open(user['tokenFile']) do |io|
132+
user['token'] = io.read.chomp
133+
end
134+
end
135+
# Convert token field to http header
136+
if user['token']
137+
user['authorization'] = "Bearer #{user['token']}"
138+
elsif user['username'] && user['password']
139+
user_pass = "#{user['username']}:#{user['password']}"
140+
user['authorization'] = "Basic #{Base64.strict_encode64(user_pass)}"
141+
end
142+
end
143+
end
144+
145+
def list_context_names
146+
self.config['contexts'].map { |e| e['name'] }
147+
end
148+
149+
def find_context(name)
150+
self.find_by_name(self.config['contexts'], 'context', name).tap do |context|
151+
context['cluster'] = find_cluster(context['cluster']) if context['cluster']
152+
context['user'] = find_user(context['user']) if context['user']
153+
end
154+
end
155+
156+
def current_context
157+
find_context(self.config['current-context'])
158+
end
159+
160+
protected
161+
def find_by_name(list, key, name)
162+
obj = list.find {|item| item['name'] == name }
163+
raise ConfigError.new("#{key}: #{name} not found") unless obj
164+
obj[key].dup
165+
end
166+
167+
def create_temp_file_and_set(obj, key)
168+
if !obj[key] && obj["#{key}-data"]
169+
obj[key] = create_temp_file_with_base64content(obj["#{key}-data"])
170+
end
171+
end
172+
173+
def create_temp_file_with_base64content(content)
174+
@@temp_files[content] ||= Tempfile.open('kube') do |temp|
175+
temp.write(Base64.strict_decode64(content))
176+
temp.path
177+
end
178+
end
179+
end
180+
end

0 commit comments

Comments
 (0)