configgin 0.18.4 → 0.18.5
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 +5 -5
- data/Gemfile +2 -2
- data/Gemfile.lock +4 -4
- data/Guardfile +2 -2
- data/configgin.gemspec +3 -5
- data/lib/cli.rb +1 -0
- data/lib/configgin.rb +92 -29
- data/lib/configgin/version.rb +1 -1
- data/lib/environment_config_transmogrifier.rb +9 -8
- data/lib/job.rb +16 -16
- data/lib/kube_link_generator.rb +29 -15
- data/lib/property_digest.rb +18 -0
- metadata +17 -16
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 2d250aa3c47fcfe842c8c4f3e486c16ec9b48ea99fa0efd61f5d4719cbf74049
|
|
4
|
+
data.tar.gz: 7f60d97717a06afffd187383774b88ce34235629f28767a6bb26701c6b32e89a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: bef1e310e3a86b54779c77afb415172176abe2156a17ae086d59d355d09aafbe05bb0217c97af3a77a6563f46237fca34b4ee02ba6c335e919c9049f27301b48
|
|
7
|
+
data.tar.gz: c5849fc9480b269426d0dd1dd9de590ff54045c6e536fffdfa5d6492c212b3499a0833b265b8f3b3b18835239d77c592257b86085875e188db93786dc99907c9
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
configgin (0.18.
|
|
4
|
+
configgin (0.18.5)
|
|
5
5
|
bosh-template (~> 2.0)
|
|
6
6
|
deep_merge (~> 1.1)
|
|
7
7
|
kubeclient (~> 2.0)
|
|
@@ -11,7 +11,7 @@ PATH
|
|
|
11
11
|
GEM
|
|
12
12
|
remote: https://rubygems.org/
|
|
13
13
|
specs:
|
|
14
|
-
addressable (2.
|
|
14
|
+
addressable (2.6.0)
|
|
15
15
|
public_suffix (>= 2.0.2, < 4.0)
|
|
16
16
|
ast (2.4.0)
|
|
17
17
|
bosh-template (2.2.0)
|
|
@@ -59,7 +59,7 @@ GEM
|
|
|
59
59
|
method_source (0.9.0)
|
|
60
60
|
mime-types (3.2.2)
|
|
61
61
|
mime-types-data (~> 3.2015)
|
|
62
|
-
mime-types-data (3.
|
|
62
|
+
mime-types-data (3.2019.0331)
|
|
63
63
|
mustache (1.1.0)
|
|
64
64
|
nenv (0.3.0)
|
|
65
65
|
netrc (0.11.0)
|
|
@@ -129,4 +129,4 @@ DEPENDENCIES
|
|
|
129
129
|
rubocop
|
|
130
130
|
|
|
131
131
|
BUNDLED WITH
|
|
132
|
-
1.
|
|
132
|
+
1.17.3
|
data/Guardfile
CHANGED
data/configgin.gemspec
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
lib = File.expand_path('../lib', __FILE__)
|
|
1
|
+
lib = File.expand_path('lib', __dir__)
|
|
4
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
5
3
|
require 'configgin/version'
|
|
6
4
|
|
|
@@ -25,8 +23,8 @@ Gem::Specification.new do |spec|
|
|
|
25
23
|
spec.add_development_dependency 'rake', '~> 10.0'
|
|
26
24
|
|
|
27
25
|
spec.add_dependency 'bosh-template', '~> 2.0'
|
|
28
|
-
spec.add_dependency 'rainbow', '~>2.0', '!=2.2.1'
|
|
29
26
|
spec.add_dependency 'deep_merge', '~> 1.1'
|
|
30
|
-
spec.add_dependency 'mustache', '~> 1.0'
|
|
31
27
|
spec.add_dependency 'kubeclient', '~>2.0'
|
|
28
|
+
spec.add_dependency 'mustache', '~> 1.0'
|
|
29
|
+
spec.add_dependency 'rainbow', '~>2.0', '!=2.2.1'
|
|
32
30
|
end
|
data/lib/cli.rb
CHANGED
data/lib/configgin.rb
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
1
3
|
require_relative 'cli'
|
|
2
4
|
require_relative 'job'
|
|
3
5
|
require_relative 'environment_config_transmogrifier'
|
|
4
6
|
require_relative 'bosh_deployment_manifest_config_transmogrifier'
|
|
5
7
|
require_relative 'kube_link_generator'
|
|
6
8
|
require_relative 'bosh_deployment_manifest'
|
|
9
|
+
require_relative 'property_digest'
|
|
7
10
|
|
|
8
11
|
# Configgin is the main class which puts all the pieces together and configures
|
|
9
12
|
# the container according to the options.
|
|
@@ -11,16 +14,18 @@ class Configgin
|
|
|
11
14
|
# SVC_ACC_PATH is the location of the service account secrets
|
|
12
15
|
SVC_ACC_PATH = '/var/run/secrets/kubernetes.io/serviceaccount'.freeze
|
|
13
16
|
|
|
14
|
-
def initialize(
|
|
15
|
-
@job_configs = JSON.parse(File.read(
|
|
16
|
-
@templates = YAML.load_file(
|
|
17
|
-
@bosh_deployment_manifest =
|
|
17
|
+
def initialize(jobs:, env2conf:, bosh_deployment_manifest:, self_name: ENV['HOSTNAME'])
|
|
18
|
+
@job_configs = JSON.parse(File.read(jobs))
|
|
19
|
+
@templates = YAML.load_file(env2conf)
|
|
20
|
+
@bosh_deployment_manifest = bosh_deployment_manifest
|
|
21
|
+
@self_name = self_name
|
|
18
22
|
end
|
|
19
23
|
|
|
20
24
|
def run
|
|
21
25
|
jobs = generate_jobs(@job_configs, @templates)
|
|
22
|
-
|
|
26
|
+
job_digests = patch_job_metadata(jobs)
|
|
23
27
|
render_job_templates(jobs, @job_configs)
|
|
28
|
+
restart_affected_pods expected_annotations(@job_configs, job_digests)
|
|
24
29
|
end
|
|
25
30
|
|
|
26
31
|
def generate_jobs(job_configs, templates)
|
|
@@ -41,19 +46,37 @@ class Configgin
|
|
|
41
46
|
exit 1
|
|
42
47
|
end
|
|
43
48
|
|
|
44
|
-
jobs[job] = Job.new(
|
|
49
|
+
jobs[job] = Job.new(
|
|
50
|
+
spec: bosh_spec,
|
|
51
|
+
namespace: kube_namespace,
|
|
52
|
+
client: kube_client,
|
|
53
|
+
client_stateful_set: kube_client_stateful_set,
|
|
54
|
+
self_name: @self_name
|
|
55
|
+
)
|
|
45
56
|
end
|
|
46
57
|
jobs
|
|
47
58
|
end
|
|
48
59
|
|
|
49
|
-
|
|
60
|
+
# Set the exported properties and their digests, and return the digests.
|
|
61
|
+
def patch_job_metadata(jobs)
|
|
62
|
+
digests = {}
|
|
50
63
|
jobs.each do |name, job|
|
|
64
|
+
digest = property_digest(job.exported_properties)
|
|
51
65
|
kube_client.patch_pod(
|
|
52
|
-
|
|
53
|
-
{
|
|
66
|
+
@self_name,
|
|
67
|
+
{
|
|
68
|
+
metadata: {
|
|
69
|
+
annotations: {
|
|
70
|
+
:"skiff-exported-properties-#{name}" => job.exported_properties.to_json,
|
|
71
|
+
:"skiff-exported-digest-#{name}" => digest
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
},
|
|
54
75
|
kube_namespace
|
|
55
76
|
)
|
|
77
|
+
digests[name] = digest
|
|
56
78
|
end
|
|
79
|
+
digests
|
|
57
80
|
end
|
|
58
81
|
|
|
59
82
|
def render_job_templates(jobs, job_configs)
|
|
@@ -66,6 +89,55 @@ class Configgin
|
|
|
66
89
|
end
|
|
67
90
|
end
|
|
68
91
|
|
|
92
|
+
# Some pods might have depended on the properties exported by this pod; given
|
|
93
|
+
# the annotations expected on the pods (keyed by the instance group name),
|
|
94
|
+
# patch the StatefulSets such that they will be restarted.
|
|
95
|
+
def restart_affected_pods(expected_annotations)
|
|
96
|
+
expected_annotations.each_pair do |instance_group_name, digests|
|
|
97
|
+
begin
|
|
98
|
+
kube_client_stateful_set.patch_stateful_set(
|
|
99
|
+
instance_group_name,
|
|
100
|
+
{ spec: { template: { metadata: { annotations: digests } } } },
|
|
101
|
+
kube_namespace
|
|
102
|
+
)
|
|
103
|
+
warn "Patched StatefulSet #{instance_group_name} for new exported digests"
|
|
104
|
+
rescue KubeException => e
|
|
105
|
+
begin
|
|
106
|
+
begin
|
|
107
|
+
response = JSON.parse(e.response || '')
|
|
108
|
+
rescue JSON::ParseError
|
|
109
|
+
response = {}
|
|
110
|
+
end
|
|
111
|
+
if response['reason'] == 'NotFound'
|
|
112
|
+
# The StatefulSet can be missing if we're configured to not have an
|
|
113
|
+
# optional instance group.
|
|
114
|
+
warn "Skipping patch of non-existant StatefulSet #{instance_group_name}"
|
|
115
|
+
next
|
|
116
|
+
end
|
|
117
|
+
warn "Error patching #{instance_group_name}: #{response.to_json}"
|
|
118
|
+
raise
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
# Given the active jobs, and a hash of the expected annotations for each,
|
|
125
|
+
# return the annotations we expect to be on each pod based on what properties
|
|
126
|
+
# each job imports.
|
|
127
|
+
def expected_annotations(job_configs, job_digests)
|
|
128
|
+
instance_groups_to_examine = Hash.new { |h, k| h[k] = {} }
|
|
129
|
+
job_configs.values.each do |job_config|
|
|
130
|
+
base_config = JSON.parse(File.read(job_config['base']))
|
|
131
|
+
base_config.fetch('consumed_by', {}).each_pair do |provider_name, consumer_jobs|
|
|
132
|
+
consumer_jobs.each do |consumer_job|
|
|
133
|
+
digest_key = "skiff-imported-properties-#{instance_group}-#{provider_name}"
|
|
134
|
+
instance_groups_to_examine[consumer_job['role']][digest_key] = job_digests[provider_name]
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
instance_groups_to_examine
|
|
139
|
+
end
|
|
140
|
+
|
|
69
141
|
def kube_namespace
|
|
70
142
|
@kube_namespace ||= File.read("#{SVC_ACC_PATH}/namespace")
|
|
71
143
|
end
|
|
@@ -76,13 +148,14 @@ class Configgin
|
|
|
76
148
|
|
|
77
149
|
private
|
|
78
150
|
|
|
79
|
-
def
|
|
80
|
-
|
|
151
|
+
def create_kube_client(path: nil, version: 'v1')
|
|
152
|
+
Kubeclient::Client.new(
|
|
81
153
|
URI::HTTPS.build(
|
|
82
154
|
host: ENV['KUBERNETES_SERVICE_HOST'],
|
|
83
|
-
port: ENV['KUBERNETES_SERVICE_PORT_HTTPS']
|
|
155
|
+
port: ENV['KUBERNETES_SERVICE_PORT_HTTPS'],
|
|
156
|
+
path: path
|
|
84
157
|
),
|
|
85
|
-
|
|
158
|
+
version,
|
|
86
159
|
ssl_options: {
|
|
87
160
|
ca_file: "#{SVC_ACC_PATH}/ca.crt",
|
|
88
161
|
verify_ssl: OpenSSL::SSL::VERIFY_PEER
|
|
@@ -93,26 +166,16 @@ class Configgin
|
|
|
93
166
|
)
|
|
94
167
|
end
|
|
95
168
|
|
|
169
|
+
def kube_client
|
|
170
|
+
@kube_client ||= create_kube_client
|
|
171
|
+
end
|
|
172
|
+
|
|
96
173
|
def kube_client_stateful_set
|
|
97
|
-
@kube_client_stateful_set ||=
|
|
98
|
-
URI::HTTPS.build(
|
|
99
|
-
host: ENV['KUBERNETES_SERVICE_HOST'],
|
|
100
|
-
port: ENV['KUBERNETES_SERVICE_PORT_HTTPS'],
|
|
101
|
-
path: '/apis/apps'
|
|
102
|
-
),
|
|
103
|
-
'v1beta1',
|
|
104
|
-
ssl_options: {
|
|
105
|
-
ca_file: "#{SVC_ACC_PATH}/ca.crt",
|
|
106
|
-
verify_ssl: OpenSSL::SSL::VERIFY_PEER
|
|
107
|
-
},
|
|
108
|
-
auth_options: {
|
|
109
|
-
bearer_token: kube_token
|
|
110
|
-
}
|
|
111
|
-
)
|
|
174
|
+
@kube_client_stateful_set ||= create_kube_client(path: '/apis/apps')
|
|
112
175
|
end
|
|
113
176
|
|
|
114
177
|
def instance_group
|
|
115
|
-
pod = kube_client.get_pod(
|
|
178
|
+
pod = kube_client.get_pod(@self_name, kube_namespace)
|
|
116
179
|
pod['metadata']['labels']['app.kubernetes.io/component']
|
|
117
180
|
end
|
|
118
181
|
end
|
data/lib/configgin/version.rb
CHANGED
|
@@ -17,6 +17,7 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
17
17
|
def escapeHTML(str)
|
|
18
18
|
str
|
|
19
19
|
end
|
|
20
|
+
# rubocop:enable MethodName
|
|
20
21
|
end
|
|
21
22
|
|
|
22
23
|
# Processes the mustache templates and injects new keys into the configuration
|
|
@@ -27,7 +28,7 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
27
28
|
input_hash = ENV.to_hash
|
|
28
29
|
|
|
29
30
|
# load secrets
|
|
30
|
-
|
|
31
|
+
extend_replace(input_hash, secrets) if secrets && File.directory?(secrets)
|
|
31
32
|
|
|
32
33
|
# remove empty values
|
|
33
34
|
input_hash.reject! { |_, v| v.nil? || v.empty? }
|
|
@@ -41,7 +42,7 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
41
42
|
# by default, all values are strings, because they come from the environment
|
|
42
43
|
# we need to unmarshall them using YAML.load
|
|
43
44
|
loop do
|
|
44
|
-
value =
|
|
45
|
+
value = process_mustache_template(value, input_hash, key)
|
|
45
46
|
break unless value.respond_to?(:include?) && value.include?('((')
|
|
46
47
|
end
|
|
47
48
|
|
|
@@ -52,7 +53,7 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
52
53
|
base_config
|
|
53
54
|
end
|
|
54
55
|
|
|
55
|
-
def self.
|
|
56
|
+
def self.process_mustache_template(value, input_hash, key)
|
|
56
57
|
val = @@memoize_mustache.fetch(value, {})[input_hash]
|
|
57
58
|
return val if val
|
|
58
59
|
|
|
@@ -63,14 +64,14 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
63
64
|
mustache_value = mustache_value.to_s.gsub("\n", "\n\n")
|
|
64
65
|
@@memoize_mustache[value] ||= {}
|
|
65
66
|
@@memoize_mustache[value][input_hash] = YAML.safe_load(mustache_value)
|
|
66
|
-
rescue => e
|
|
67
|
-
msg =
|
|
67
|
+
rescue StandardError => e
|
|
68
|
+
msg = mustache_message_from_error(e)
|
|
68
69
|
raise LoadYamlFromMustacheError, "Could not load config key '#{key}': #{msg}"
|
|
69
70
|
end
|
|
70
71
|
end
|
|
71
72
|
|
|
72
|
-
def self.
|
|
73
|
-
lines =
|
|
73
|
+
def self.mustache_message_from_error(error)
|
|
74
|
+
lines = error.message.split(/\n/)
|
|
74
75
|
return 'No reason for failure given by mustache library' if lines.empty?
|
|
75
76
|
return lines.first if lines.size < 4
|
|
76
77
|
|
|
@@ -84,7 +85,7 @@ class EnvironmentConfigTransmogrifier < BaseTransmogrifier
|
|
|
84
85
|
lines[0] + ": Error at or near position #{caret_pos - leading_junk} of template value."
|
|
85
86
|
end
|
|
86
87
|
|
|
87
|
-
def self.
|
|
88
|
+
def self.extend_replace(hash, path)
|
|
88
89
|
# This code assumes that 'path' points to a directory of files.
|
|
89
90
|
# The name of each file is the key into the hash, and the contents
|
|
90
91
|
# of the file are the value to enter, as-is. The order of the
|
data/lib/job.rb
CHANGED
|
@@ -4,10 +4,11 @@ require_relative 'kube_link_generator'
|
|
|
4
4
|
|
|
5
5
|
# Job describes a single BOSH job
|
|
6
6
|
class Job
|
|
7
|
-
def initialize(spec
|
|
7
|
+
def initialize(spec:, namespace:, client:, client_stateful_set:, self_name: ENV['HOSTNAME'])
|
|
8
8
|
@spec = spec
|
|
9
9
|
@namespace = namespace
|
|
10
10
|
@client = client
|
|
11
|
+
@self_name = self_name
|
|
11
12
|
links = @spec['links'] = KubeLinkSpecs.new(@spec, @namespace, @client, client_stateful_set)
|
|
12
13
|
|
|
13
14
|
# Figure out whether _this_ should bootstrap
|
|
@@ -19,25 +20,24 @@ class Job
|
|
|
19
20
|
attr_reader :spec
|
|
20
21
|
|
|
21
22
|
def exported_properties
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
23
|
+
@exported_properties ||= {}.tap do |exported_properties|
|
|
24
|
+
spec['exported_properties'].each do |prop|
|
|
25
|
+
src = spec['properties']
|
|
26
|
+
dst = exported_properties
|
|
27
|
+
keys = prop.split('.')
|
|
28
|
+
leaf = keys.pop
|
|
29
|
+
keys.each do |key|
|
|
30
|
+
dst[key] ||= {}
|
|
31
|
+
dst = dst[key]
|
|
32
|
+
src = src.fetch(key, {})
|
|
33
|
+
end
|
|
34
|
+
dst[leaf] = src[leaf]
|
|
33
35
|
end
|
|
34
|
-
dst[leaf] = src[leaf]
|
|
35
36
|
end
|
|
36
|
-
@exported_properties = exported_properties
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
def self_pod
|
|
40
|
-
@self_pod ||= @client.get_pod(
|
|
40
|
+
@self_pod ||= @client.get_pod(@self_name, @namespace)
|
|
41
41
|
end
|
|
42
42
|
|
|
43
43
|
def self_role
|
|
@@ -82,7 +82,7 @@ class Job
|
|
|
82
82
|
out_file = nil
|
|
83
83
|
raise "failed to open output file #{output_file_path}: #{e}"
|
|
84
84
|
ensure
|
|
85
|
-
out_file
|
|
85
|
+
out_file&.close
|
|
86
86
|
end
|
|
87
87
|
end
|
|
88
88
|
end
|
data/lib/kube_link_generator.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
require 'digest/sha1'
|
|
1
2
|
require 'kubeclient'
|
|
2
3
|
require 'uri'
|
|
3
4
|
require_relative 'exceptions'
|
|
@@ -28,6 +29,7 @@ class KubeLinkSpecs
|
|
|
28
29
|
def pod_index(name)
|
|
29
30
|
index = name.rpartition('-').last
|
|
30
31
|
return index.to_i if /^\d+$/ =~ index
|
|
32
|
+
|
|
31
33
|
# The pod name is something like role-abcxyz
|
|
32
34
|
# Derive the index from the randomness that went into the suffix.
|
|
33
35
|
# chars are the characters kubernetes might use to generate names
|
|
@@ -49,6 +51,7 @@ class KubeLinkSpecs
|
|
|
49
51
|
good_pods = pods.select do |pod|
|
|
50
52
|
next false unless pod.status.podIP
|
|
51
53
|
next true if pod.metadata.annotations["skiff-exported-properties-#{job}"]
|
|
54
|
+
|
|
52
55
|
# Fall back to non-job-specific properties, for upgrades from older versions
|
|
53
56
|
pod.metadata.annotations['skiff-exported-properties']
|
|
54
57
|
end
|
|
@@ -66,17 +69,27 @@ class KubeLinkSpecs
|
|
|
66
69
|
end
|
|
67
70
|
end
|
|
68
71
|
|
|
69
|
-
def get_exported_properties(pod,
|
|
70
|
-
if pod.metadata.annotations["skiff-exported-properties-#{
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
def get_exported_properties(role_name, pod, job_name)
|
|
73
|
+
if pod.metadata.annotations["skiff-exported-properties-#{job_name}"]
|
|
74
|
+
if pod.metadata.annotations["skiff-exported-digest-#{job_name}"]
|
|
75
|
+
# Copy the digest over, so that if the source role changes we can be
|
|
76
|
+
# restarted.
|
|
77
|
+
digest = pod.metadata.annotations["skiff-exported-digest-#{job_name}"]
|
|
78
|
+
client.patch_pod(
|
|
79
|
+
ENV['HOSTNAME'],
|
|
80
|
+
{ metadata: { annotations: { :"skiff-imported-properties-#{role_name}-#{job_name}" => digest } } },
|
|
81
|
+
namespace
|
|
82
|
+
)
|
|
83
|
+
end
|
|
84
|
+
JSON.parse(pod.metadata.annotations["skiff-exported-properties-#{job_name}"])
|
|
85
|
+
elsif pod.metadata.annotations['skiff-exported-properties']
|
|
86
|
+
JSON.parse(pod.metadata.annotations['skiff-exported-properties'])[job_name]
|
|
74
87
|
else
|
|
75
88
|
{}
|
|
76
89
|
end
|
|
77
90
|
end
|
|
78
91
|
|
|
79
|
-
def get_pod_instance_info(pod, job, pods_per_image)
|
|
92
|
+
def get_pod_instance_info(role_name, pod, job, pods_per_image)
|
|
80
93
|
index = pod_index(pod.metadata.name)
|
|
81
94
|
# Use pod DNS name for address field, instead of IP address which may change
|
|
82
95
|
{
|
|
@@ -85,7 +98,7 @@ class KubeLinkSpecs
|
|
|
85
98
|
'id' => pod.metadata.name,
|
|
86
99
|
'az' => pod.metadata.annotations['failure-domain.beta.kubernetes.io/zone'] || 'az0',
|
|
87
100
|
'address' => "#{pod.metadata.name}.#{pod.spec.subdomain}.#{ENV['KUBERNETES_NAMESPACE']}.svc.#{ENV['KUBERNETES_CLUSTER_DOMAIN']}",
|
|
88
|
-
'properties' => get_exported_properties(pod, job),
|
|
101
|
+
'properties' => get_exported_properties(role_name, pod, job),
|
|
89
102
|
'bootstrap' => pods_per_image[pod.metadata.uid] < 2
|
|
90
103
|
}
|
|
91
104
|
end
|
|
@@ -97,6 +110,7 @@ class KubeLinkSpecs
|
|
|
97
110
|
keys = {}
|
|
98
111
|
pods.each do |pod|
|
|
99
112
|
next if pod.status.containerStatuses.nil?
|
|
113
|
+
|
|
100
114
|
key = pod.status.containerStatuses.map(&:imageID).sort.join("\n")
|
|
101
115
|
sets[key] += 1
|
|
102
116
|
keys[pod.metadata.uid] = key
|
|
@@ -116,7 +130,7 @@ class KubeLinkSpecs
|
|
|
116
130
|
'id' => svc.metadata.name,
|
|
117
131
|
'az' => pod.metadata.annotations['failure-domain.beta.kubernetes.io/zone'] || 'az0',
|
|
118
132
|
'address' => svc.spec.clusterIP,
|
|
119
|
-
'properties' => get_exported_properties(pod, job),
|
|
133
|
+
'properties' => get_exported_properties(role_name, pod, job),
|
|
120
134
|
'bootstrap' => true
|
|
121
135
|
}
|
|
122
136
|
end
|
|
@@ -132,7 +146,7 @@ class KubeLinkSpecs
|
|
|
132
146
|
'id' => ss.metadata.name,
|
|
133
147
|
'az' => pod.metadata.annotations['failure-domain.beta.kubernetes.io/zone'] || 'az0',
|
|
134
148
|
'address' => "#{ss.metadata.name}-#{i}.#{ss.spec.serviceName}",
|
|
135
|
-
'properties' => get_exported_properties(pod, job),
|
|
149
|
+
'properties' => get_exported_properties(role_name, pod, job),
|
|
136
150
|
'bootstrap' => i.zero?
|
|
137
151
|
}
|
|
138
152
|
end
|
|
@@ -151,27 +165,27 @@ class KubeLinkSpecs
|
|
|
151
165
|
# Resolve the role we're looking for
|
|
152
166
|
provider = spec['consumes'][key]
|
|
153
167
|
unless provider
|
|
154
|
-
|
|
168
|
+
warn "No link provider found for #{key}"
|
|
155
169
|
return @links[key] = nil
|
|
156
170
|
end
|
|
157
171
|
|
|
158
172
|
if provider['role'] == this_name
|
|
159
|
-
|
|
173
|
+
warn "Resolving link #{key} via self provider #{provider}"
|
|
160
174
|
pods = get_pods_for_role(provider['role'], provider['job'], wait_for_all: true)
|
|
161
175
|
pods_per_image = get_pods_per_image(pods)
|
|
162
|
-
instances = pods.map { |p| get_pod_instance_info(p, provider['job'], pods_per_image) }
|
|
176
|
+
instances = pods.map { |p| get_pod_instance_info(provider['role'], p, provider['job'], pods_per_image) }
|
|
163
177
|
elsif service? provider['role']
|
|
164
178
|
# Getting pods for a different service; since we have kube services, we don't handle it in configgin
|
|
165
|
-
|
|
179
|
+
warn "Resolving link #{key} via service #{provider}"
|
|
166
180
|
instances = [get_svc_instance_info(provider['role'], provider['job'])]
|
|
167
181
|
else
|
|
168
182
|
# If there's no service associated, check the statefulset instead
|
|
169
|
-
|
|
183
|
+
warn "Resolving link #{key} via statefulset #{provider}"
|
|
170
184
|
instances = get_statefulset_instance_info(provider['role'], provider['job'])
|
|
171
185
|
end
|
|
172
186
|
|
|
173
187
|
# Underscores aren't valid hostnames, so jobs are transformed in fissile to use dashes
|
|
174
|
-
job_name = provider['job'].
|
|
188
|
+
job_name = provider['job'].tr('_', '-')
|
|
175
189
|
service_name = provider['service_name'] || "#{provider['role']}-#{job_name}"
|
|
176
190
|
|
|
177
191
|
@links[key] = {
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
require 'digest/sha1'
|
|
2
|
+
require 'json'
|
|
3
|
+
|
|
4
|
+
# Given a properties (a JSON-serializable Hash), generate a digest that will be
|
|
5
|
+
# consistent across runs even if the enumeration order of hashes changes.
|
|
6
|
+
def property_digest(properties)
|
|
7
|
+
normalize_object = lambda do |obj|
|
|
8
|
+
case obj
|
|
9
|
+
when Hash
|
|
10
|
+
{}.tap { |result| obj.sort.each { |k, v| result[k] = normalize_object.call(v) } }
|
|
11
|
+
when Enumerable
|
|
12
|
+
obj.map(&normalize_object)
|
|
13
|
+
else
|
|
14
|
+
obj
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
"sha1:#{Digest::SHA1.hexdigest(normalize_object.call(properties).to_json)}"
|
|
18
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: configgin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.18.
|
|
4
|
+
version: 0.18.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- SUSE
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2019-04-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -53,39 +53,33 @@ dependencies:
|
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
54
|
version: '2.0'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
|
-
name:
|
|
56
|
+
name: deep_merge
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '
|
|
62
|
-
- - "!="
|
|
63
|
-
- !ruby/object:Gem::Version
|
|
64
|
-
version: 2.2.1
|
|
61
|
+
version: '1.1'
|
|
65
62
|
type: :runtime
|
|
66
63
|
prerelease: false
|
|
67
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
68
65
|
requirements:
|
|
69
66
|
- - "~>"
|
|
70
67
|
- !ruby/object:Gem::Version
|
|
71
|
-
version: '
|
|
72
|
-
- - "!="
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: 2.2.1
|
|
68
|
+
version: '1.1'
|
|
75
69
|
- !ruby/object:Gem::Dependency
|
|
76
|
-
name:
|
|
70
|
+
name: kubeclient
|
|
77
71
|
requirement: !ruby/object:Gem::Requirement
|
|
78
72
|
requirements:
|
|
79
73
|
- - "~>"
|
|
80
74
|
- !ruby/object:Gem::Version
|
|
81
|
-
version: '
|
|
75
|
+
version: '2.0'
|
|
82
76
|
type: :runtime
|
|
83
77
|
prerelease: false
|
|
84
78
|
version_requirements: !ruby/object:Gem::Requirement
|
|
85
79
|
requirements:
|
|
86
80
|
- - "~>"
|
|
87
81
|
- !ruby/object:Gem::Version
|
|
88
|
-
version: '
|
|
82
|
+
version: '2.0'
|
|
89
83
|
- !ruby/object:Gem::Dependency
|
|
90
84
|
name: mustache
|
|
91
85
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -101,12 +95,15 @@ dependencies:
|
|
|
101
95
|
- !ruby/object:Gem::Version
|
|
102
96
|
version: '1.0'
|
|
103
97
|
- !ruby/object:Gem::Dependency
|
|
104
|
-
name:
|
|
98
|
+
name: rainbow
|
|
105
99
|
requirement: !ruby/object:Gem::Requirement
|
|
106
100
|
requirements:
|
|
107
101
|
- - "~>"
|
|
108
102
|
- !ruby/object:Gem::Version
|
|
109
103
|
version: '2.0'
|
|
104
|
+
- - "!="
|
|
105
|
+
- !ruby/object:Gem::Version
|
|
106
|
+
version: 2.2.1
|
|
110
107
|
type: :runtime
|
|
111
108
|
prerelease: false
|
|
112
109
|
version_requirements: !ruby/object:Gem::Requirement
|
|
@@ -114,6 +111,9 @@ dependencies:
|
|
|
114
111
|
- - "~>"
|
|
115
112
|
- !ruby/object:Gem::Version
|
|
116
113
|
version: '2.0'
|
|
114
|
+
- - "!="
|
|
115
|
+
- !ruby/object:Gem::Version
|
|
116
|
+
version: 2.2.1
|
|
117
117
|
description: A simple cli app in Ruby to generate configurations using BOSH ERB templates
|
|
118
118
|
and a BOSH spec, but also using configurations based on environment variables, processed
|
|
119
119
|
using a set of templates.
|
|
@@ -150,6 +150,7 @@ files:
|
|
|
150
150
|
- lib/exceptions.rb
|
|
151
151
|
- lib/job.rb
|
|
152
152
|
- lib/kube_link_generator.rb
|
|
153
|
+
- lib/property_digest.rb
|
|
153
154
|
- make/include/darwin-support
|
|
154
155
|
- make/lint
|
|
155
156
|
- make/test
|
|
@@ -181,7 +182,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
181
182
|
version: '0'
|
|
182
183
|
requirements: []
|
|
183
184
|
rubyforge_project:
|
|
184
|
-
rubygems_version: 2.6
|
|
185
|
+
rubygems_version: 2.7.6
|
|
185
186
|
signing_key:
|
|
186
187
|
specification_version: 4
|
|
187
188
|
summary: A simple cli app in Ruby to generate configurations using BOSH ERB templates
|