kube-platform 3.3.1.gk.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 +7 -0
- data/Gemfile +31 -0
- data/README.md +192 -0
- data/bin/kube-platform +37 -0
- data/lib/kube-platform/application.rb +203 -0
- data/lib/kube-platform/cli.rb +114 -0
- data/lib/kube-platform/client.rb +217 -0
- data/lib/kube-platform/cluster.rb +224 -0
- data/lib/kube-platform/cluster_definition.rb +115 -0
- data/lib/kube-platform/configuration.rb +145 -0
- data/lib/kube-platform/exceptions.rb +9 -0
- data/lib/kube-platform/handlers/dockerhub_secret_copy.rb +52 -0
- data/lib/kube-platform/handlers/ebs_from_snapshot.rb +108 -0
- data/lib/kube-platform/handlers/handler.rb +36 -0
- data/lib/kube-platform/handlers/recreate_resource.rb +11 -0
- data/lib/kube-platform/handlers/secret_copy.rb +43 -0
- data/lib/kube-platform/handlers/wait_for_job_completion.rb +69 -0
- data/lib/kube-platform/handlers/wait_for_termination.rb +47 -0
- data/lib/kube-platform/health_check.rb +19 -0
- data/lib/kube-platform/health_checks/pods_ready.rb +188 -0
- data/lib/kube-platform/health_checks/r53_records.rb +82 -0
- data/lib/kube-platform/helpers/retry.rb +20 -0
- data/lib/kube-platform/images/descriptor.rb +49 -0
- data/lib/kube-platform/images/docker_hub_image.rb +49 -0
- data/lib/kube-platform/images/dockerhub_image_factory.rb +64 -0
- data/lib/kube-platform/images/kubernetes_docker_hub_secret_provider.rb +44 -0
- data/lib/kube-platform/images/repository.rb +77 -0
- data/lib/kube-platform/images/tag_associator.rb +80 -0
- data/lib/kube-platform/images/tagged_dockerhub_image.rb +36 -0
- data/lib/kube-platform/logger.rb +32 -0
- data/lib/kube-platform/manifest.rb +61 -0
- data/lib/kube-platform/pre_checks/r53_records.rb +66 -0
- data/lib/kube-platform/pre_checks/valid_platform_dependencies.rb +52 -0
- data/lib/kube-platform/pre_checks.rb +19 -0
- data/lib/kube-platform/resource.rb +152 -0
- data/lib/kube-platform/resource_repository.rb +73 -0
- data/lib/kube-platform/thor/descriptor_to_option_adapter.rb +33 -0
- data/lib/kube-platform/update_checker.rb +39 -0
- data/lib/kube-platform/version.rb +5 -0
- data/lib/kube-platform.rb +40 -0
- metadata +179 -0
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash/indifferent_access"
|
4
|
+
|
5
|
+
module KubePlatform
|
6
|
+
module Images
|
7
|
+
class Descriptor
|
8
|
+
DEFAULT_IMAGE_CONFIG = "../../../config/images.yaml"
|
9
|
+
|
10
|
+
attr_reader :name, :default_tag, :default_tag_from_key, :key, :description, :key_alias
|
11
|
+
|
12
|
+
def initialize(name:, default_tag:, default_tag_from_key:, key:, description:, key_alias: nil)
|
13
|
+
@name = name
|
14
|
+
@default_tag = default_tag
|
15
|
+
@default_tag_from_key = default_tag_from_key
|
16
|
+
@key = key.to_sym
|
17
|
+
@description = description
|
18
|
+
@key_alias = key_alias&.to_sym
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def with_image_defaults
|
23
|
+
images_path = File.expand_path(File.join(__dir__, DEFAULT_IMAGE_CONFIG))
|
24
|
+
array_from_yaml_file(filename: images_path)
|
25
|
+
end
|
26
|
+
|
27
|
+
def array_from_yaml_file(filename:)
|
28
|
+
yaml_to_hash(filename).map do |item|
|
29
|
+
new(
|
30
|
+
name: item[:name],
|
31
|
+
default_tag: item[:default_tag],
|
32
|
+
default_tag_from_key: item[:default_tag_from_key],
|
33
|
+
key: item[:key],
|
34
|
+
description: item[:description],
|
35
|
+
key_alias: item[:key_alias]
|
36
|
+
)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def yaml_to_hash(filename)
|
43
|
+
YAML.load_file(filename).with_indifferent_access[:images] or # TODO: get rid of indifferent access
|
44
|
+
raise ConfigException, "#{filename} does not contain a set of valid image descriptors"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "base64"
|
4
|
+
|
5
|
+
module KubePlatform
|
6
|
+
module Images
|
7
|
+
class DockerHubImage
|
8
|
+
include Logger
|
9
|
+
|
10
|
+
attr_reader :image_name, :secret_provider
|
11
|
+
|
12
|
+
def initialize(image_name:, secret_provider:)
|
13
|
+
@image_name = image_name
|
14
|
+
@secret_provider = secret_provider
|
15
|
+
end
|
16
|
+
|
17
|
+
def tag_exist?(tag)
|
18
|
+
response = RestClient.get(
|
19
|
+
"https://index.docker.io/v2/#{image_name}/manifests/#{tag}",
|
20
|
+
Authorization: "Bearer #{dockerhub_token}", Accept: "application/json"
|
21
|
+
)
|
22
|
+
response.code == 200
|
23
|
+
rescue RestClient::RequestFailed
|
24
|
+
false
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def basic_auth_secret
|
30
|
+
secret_provider.secret
|
31
|
+
end
|
32
|
+
|
33
|
+
def dockerhub_token
|
34
|
+
@dockerhub_token ||= read_dockerhub_token
|
35
|
+
end
|
36
|
+
|
37
|
+
def read_dockerhub_token
|
38
|
+
response = RestClient.get(
|
39
|
+
"https://auth.docker.io/token?service=registry.docker.io&scope=repository:#{image_name}:pull",
|
40
|
+
Authorization: "Basic #{basic_auth_secret}", Accept: "application/json"
|
41
|
+
)
|
42
|
+
|
43
|
+
JSON.parse(response.body)["token"]
|
44
|
+
rescue RestClient::RequestFailed => e
|
45
|
+
raise KubePlatformException, "Could not retrieve Docker Hub token: #{e.message}"
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
module Images
|
5
|
+
class DockerHubImageFactory
|
6
|
+
def initialize(secret_provider:)
|
7
|
+
@secret_provider = secret_provider
|
8
|
+
@image_cache = {}
|
9
|
+
@tagged_image_cache = {}
|
10
|
+
end
|
11
|
+
|
12
|
+
def build(image_name:, tag:)
|
13
|
+
if fully_qualified_docker_image?(tag)
|
14
|
+
parsed_tag = parse_tag_for_full_docker_image(tag)
|
15
|
+
tagged_dockerhub_image(parsed_tag[:image_name], parsed_tag[:image_tag])
|
16
|
+
else
|
17
|
+
tagged_dockerhub_image(image_name, tag)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def fully_qualified_docker_image?(image_tag)
|
24
|
+
image_tag.split(":").count > 1
|
25
|
+
end
|
26
|
+
|
27
|
+
def parse_tag_for_full_docker_image(image_tag)
|
28
|
+
split_tag = image_tag.split(":")
|
29
|
+
{ image_name: split_tag[0], image_tag: split_tag[1] }
|
30
|
+
end
|
31
|
+
|
32
|
+
def tagged_dockerhub_image(image_name, image_tag)
|
33
|
+
retrieve_tagged_image(image_name, image_tag) || create_tagged_dockerhub_image(image_name, image_tag)
|
34
|
+
end
|
35
|
+
|
36
|
+
def retrieve_tagged_image(image_name, image_tag)
|
37
|
+
@tagged_image_cache[tagged_image_hash_key(image_name, image_tag)]
|
38
|
+
end
|
39
|
+
|
40
|
+
def tagged_image_hash_key(image_name, image_tag)
|
41
|
+
[image_name, image_tag]
|
42
|
+
end
|
43
|
+
|
44
|
+
def create_tagged_dockerhub_image(image_name, image_tag)
|
45
|
+
dockerhub_image = dockerhub_image(image_name)
|
46
|
+
@tagged_image_cache[tagged_image_hash_key(image_name, image_tag)] = KubePlatform::Images::TaggedDockerHubImage.new(
|
47
|
+
image: dockerhub_image, tag: image_tag
|
48
|
+
)
|
49
|
+
end
|
50
|
+
|
51
|
+
def dockerhub_image(image_name)
|
52
|
+
retrieve_cached_image(image_name) || create_dockerhub_image(image_name)
|
53
|
+
end
|
54
|
+
|
55
|
+
def retrieve_cached_image(image_name)
|
56
|
+
@image_cache[image_name]
|
57
|
+
end
|
58
|
+
|
59
|
+
def create_dockerhub_image(image_name)
|
60
|
+
@image_cache[image_name] = KubePlatform::Images::DockerHubImage.new(image_name: image_name, secret_provider: @secret_provider)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
module Images
|
5
|
+
class KubernetesDockerHubSecretProvider
|
6
|
+
include Logger
|
7
|
+
|
8
|
+
attr_reader :client, :secret_namespace, :secret_name
|
9
|
+
|
10
|
+
def initialize(client:, secret_name:, secret_namespace:)
|
11
|
+
@client = client
|
12
|
+
@secret_name = secret_name
|
13
|
+
@secret_namespace = secret_namespace
|
14
|
+
end
|
15
|
+
|
16
|
+
def secret
|
17
|
+
basic_auth_secret
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def basic_auth_secret
|
23
|
+
resource = client.get(secret_resource)
|
24
|
+
if resource.nil?
|
25
|
+
message = "Could not retrieve Docker Hub secret from #{secret_namespace}/#{secret_name}"
|
26
|
+
logger.error(message) # TODO: don't double-log this
|
27
|
+
raise KubePlatform::KubePlatformException, message
|
28
|
+
end
|
29
|
+
|
30
|
+
decode_token(resource.unwrap.data[".dockercfg"])
|
31
|
+
end
|
32
|
+
|
33
|
+
def secret_resource
|
34
|
+
@secret_resource ||= KubePlatform::Resource.from_spec(apiVersion: "v1", kind: "Secret",
|
35
|
+
metadata: { name: secret_name, namespace: secret_namespace })
|
36
|
+
end
|
37
|
+
|
38
|
+
def decode_token(data)
|
39
|
+
decoded = Base64.decode64(data)
|
40
|
+
JSON.parse(decoded).dig("https://index.docker.io/v1/", "auth") or raise TokenNotFound, "Token not found in #{decoded}"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
module Images
|
5
|
+
class Repository
|
6
|
+
def initialize(image_descriptors:, image_tags:, image_factory:)
|
7
|
+
@image_descriptors = image_descriptors
|
8
|
+
@image_tags = image_tags.compact
|
9
|
+
@image_factory = image_factory
|
10
|
+
end
|
11
|
+
|
12
|
+
def get(key)
|
13
|
+
registry[key.to_sym]
|
14
|
+
end
|
15
|
+
|
16
|
+
def missing_images
|
17
|
+
registry.values.reject(&:exist?)
|
18
|
+
end
|
19
|
+
|
20
|
+
def key_tag_pairs
|
21
|
+
registry.each_with_object({}) { |(key, image), pairs| pairs[key] = image.tag }
|
22
|
+
end
|
23
|
+
|
24
|
+
def key_tag_pairs_without_defaults
|
25
|
+
@image_tags
|
26
|
+
end
|
27
|
+
|
28
|
+
def add_key_tag_pairs(additional_pairs)
|
29
|
+
@image_tags.merge!(additional_pairs) { |_key, old, _new| old }
|
30
|
+
rebuild_registry
|
31
|
+
end
|
32
|
+
|
33
|
+
def update_image_tag_defaults(key_tag_pairs)
|
34
|
+
(keys_with_default_tags & key_tag_pairs.keys).each do |key|
|
35
|
+
descriptor = descriptor_for_key(key)
|
36
|
+
registry[key] = @image_factory.build(image_name: descriptor.name, tag: key_tag_pairs[key])
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def registry
|
43
|
+
@registry ||= build_registry
|
44
|
+
end
|
45
|
+
|
46
|
+
def build_registry
|
47
|
+
image_key_tag_map = associate_tags(@image_descriptors, @image_tags)
|
48
|
+
|
49
|
+
@image_descriptors.each_with_object({}) do |descriptor, registry|
|
50
|
+
key = descriptor.key
|
51
|
+
registry[key] = @image_factory.build(image_name: descriptor.name, tag: image_key_tag_map[key])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def rebuild_registry
|
56
|
+
@registry = nil
|
57
|
+
registry
|
58
|
+
end
|
59
|
+
|
60
|
+
def associate_tags(image_descriptors, image_tags)
|
61
|
+
TagAssociator.new(image_descriptors: image_descriptors, image_tags: image_tags).run
|
62
|
+
end
|
63
|
+
|
64
|
+
def keys_with_default_tags
|
65
|
+
registry.keys - @image_tags.keys
|
66
|
+
end
|
67
|
+
|
68
|
+
def descriptor_for_key(key)
|
69
|
+
key_descriptor_map[key]
|
70
|
+
end
|
71
|
+
|
72
|
+
def key_descriptor_map
|
73
|
+
@key_descriptor_map ||= @image_descriptors.each_with_object({}) { |descriptor, hash| hash[descriptor.key] = descriptor }
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
module Images
|
5
|
+
class TagAssociator
|
6
|
+
DescriptorTagPair = Struct.new(:descriptor, :tag)
|
7
|
+
|
8
|
+
def initialize(image_descriptors:, image_tags:)
|
9
|
+
@image_descriptors = image_descriptors
|
10
|
+
@image_tags = image_tags
|
11
|
+
@associated = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def run
|
15
|
+
descriptors_with_image_tags, descriptors_requiring_defaults = @image_descriptors.partition { |d| @image_tags.key?(d.key) }
|
16
|
+
associate_descriptors_with_image_tags(descriptors_with_image_tags)
|
17
|
+
associate_descriptors_with_defaults(descriptors_requiring_defaults)
|
18
|
+
transform_descriptor_tag_map_to_image_key_tag_map
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def associate_descriptors_with_image_tags(descriptors)
|
24
|
+
descriptors.each { |d| associate_tag_to_descriptor(d, @image_tags[d.key]) }
|
25
|
+
end
|
26
|
+
|
27
|
+
def associate_tag_to_descriptor(descriptor, tag)
|
28
|
+
@associated[descriptor.key] = DescriptorTagPair.new(descriptor, tag)
|
29
|
+
end
|
30
|
+
|
31
|
+
def associate_descriptors_with_defaults(descriptors)
|
32
|
+
remaining_untagged = associate_tags_to_descriptors_containing_default_tag_attributes(descriptors)
|
33
|
+
remaining_untagged = associate_tags_to_descriptors_containing_references_to_other_descriptors(remaining_untagged)
|
34
|
+
remaining_untagged.empty? or
|
35
|
+
raise ConfigException, "No tag could be found for image with key '#{remaining_untagged.first.key}'"
|
36
|
+
end
|
37
|
+
|
38
|
+
def associate_tags_to_descriptors_containing_default_tag_attributes(descriptors)
|
39
|
+
descriptors.reject do |d|
|
40
|
+
if (tag = d.default_tag)
|
41
|
+
associate_tag_to_descriptor(d, tag)
|
42
|
+
true
|
43
|
+
else
|
44
|
+
false
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def associate_tags_to_descriptors_containing_references_to_other_descriptors(descriptors)
|
50
|
+
descriptors.reject do |d|
|
51
|
+
if (ref = d.default_tag_from_key)
|
52
|
+
resolve_descriptor_reference(d, ref)
|
53
|
+
true
|
54
|
+
else
|
55
|
+
false
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def resolve_descriptor_reference(descriptor, ref)
|
61
|
+
descriptor_tag_pair = @associated[ref.to_sym] or
|
62
|
+
raise ConfigException,
|
63
|
+
"#{descriptor.key} wants to use the image tag from the image with key '#{ref}', but that image does not have a tag"
|
64
|
+
|
65
|
+
if descriptor.name != descriptor_tag_pair.descriptor.name &&
|
66
|
+
([descriptor.name, descriptor_tag_pair.descriptor.name] - ['invocaops/web_app', 'invocaops/ringswitch']).any?
|
67
|
+
raise ConfigException,
|
68
|
+
"#{descriptor.key} is trying to use the default_tag_from_key directive against #{ref}, "\
|
69
|
+
"but the image names don't match"
|
70
|
+
end
|
71
|
+
|
72
|
+
associate_tag_to_descriptor(descriptor, descriptor_tag_pair.tag)
|
73
|
+
end
|
74
|
+
|
75
|
+
def transform_descriptor_tag_map_to_image_key_tag_map
|
76
|
+
@associated.each_with_object({}) { |(key, descriptor_tag_pair), hash| hash[key] = descriptor_tag_pair.tag }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
module Images
|
5
|
+
class TaggedDockerHubImage
|
6
|
+
include Logger
|
7
|
+
|
8
|
+
attr_reader :tag
|
9
|
+
|
10
|
+
def initialize(image:, tag:)
|
11
|
+
@image = image
|
12
|
+
@tag = tag
|
13
|
+
end
|
14
|
+
|
15
|
+
def name
|
16
|
+
"#{@image.image_name}:#{@tag}"
|
17
|
+
end
|
18
|
+
|
19
|
+
def exist?
|
20
|
+
defined?(@exists) or @exists = log_success_fail(@image.tag_exist?(@tag))
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def log_success_fail(success)
|
26
|
+
if success
|
27
|
+
logger.info("Successfully located Docker Hub image for #{name}")
|
28
|
+
else
|
29
|
+
logger.info("Could not locate Docker Hub image for #{name}")
|
30
|
+
end
|
31
|
+
|
32
|
+
success
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "logger"
|
4
|
+
|
5
|
+
module KubePlatform
|
6
|
+
module Logger
|
7
|
+
ANSI_ESCAPE = "\x1B"
|
8
|
+
ANSI_GOTO_START_OF_LINE = ANSI_ESCAPE + "[0F"
|
9
|
+
ANSI_CLEAR_TO_END_OF_LINE = ANSI_ESCAPE + "[J"
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :verbose
|
13
|
+
attr_writer :logger
|
14
|
+
|
15
|
+
def logger
|
16
|
+
@logger ||= ::Logger.new(STDOUT).tap do |logger|
|
17
|
+
logger.formatter = -> (severity, time, programname, msg) do
|
18
|
+
if STDOUT.isatty && !verbose
|
19
|
+
ANSI_GOTO_START_OF_LINE + ANSI_CLEAR_TO_END_OF_LINE + "%5s %s\n" % [severity, msg]
|
20
|
+
else
|
21
|
+
::Logger::Formatter.new.call(severity, time, programname, msg)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def logger
|
29
|
+
Logger.logger
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/core_ext/hash"
|
4
|
+
require "active_support/core_ext/string"
|
5
|
+
require "jsonnet"
|
6
|
+
|
7
|
+
module KubePlatform
|
8
|
+
class Manifest
|
9
|
+
attr_reader :resource_dir, :filename, :config
|
10
|
+
|
11
|
+
FILENAME_ANNOTATION = "invoca.com/resource_filename"
|
12
|
+
|
13
|
+
def initialize(filename:, resource_dir:, config:)
|
14
|
+
@filename = filename
|
15
|
+
@resource_dir = resource_dir
|
16
|
+
@config = config
|
17
|
+
end
|
18
|
+
|
19
|
+
def cluster_definition_by_name(name)
|
20
|
+
raise_if_definition_not_found(name)
|
21
|
+
definitions[name]
|
22
|
+
end
|
23
|
+
|
24
|
+
def version
|
25
|
+
manifest[:version] or raise ManifestException, "The manifest does not contain a 'version' key"
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
def raise_if_definition_not_found(definition_name)
|
31
|
+
definitions[definition_name] or raise ManifestException, "A platform definition named #{definition_name} was not found in #{filename}"
|
32
|
+
end
|
33
|
+
|
34
|
+
def definitions
|
35
|
+
@definitions ||= manifest[:definitions].each_with_object({}) do |(name, definition), clusters|
|
36
|
+
clusters[name] = ClusterDefinition.new(name: name, definition: definition, resource_dir: resource_dir, config: config)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def manifest
|
41
|
+
@manifest ||= case filename
|
42
|
+
when /\.jsonnet$/
|
43
|
+
load_jsonnet_manifest
|
44
|
+
else
|
45
|
+
load_yaml_manifest
|
46
|
+
end.with_indifferent_access
|
47
|
+
end
|
48
|
+
|
49
|
+
def load_yaml_manifest
|
50
|
+
template = File.read(filename)
|
51
|
+
renderer = ERB.new(template)
|
52
|
+
YAML.safe_load(renderer.result(config.binding), aliases: true)
|
53
|
+
end
|
54
|
+
|
55
|
+
def load_jsonnet_manifest
|
56
|
+
vm = Jsonnet::VM.new
|
57
|
+
vm.tla_code("vars", config.to_json)
|
58
|
+
JSON.parse(vm.evaluate_file(filename))
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "aws-sdk-route53"
|
4
|
+
require_relative "../logger"
|
5
|
+
require_relative "../helpers/retry"
|
6
|
+
|
7
|
+
module KubePlatform
|
8
|
+
module PreChecks
|
9
|
+
class R53Records < PreCheck
|
10
|
+
include Logger
|
11
|
+
|
12
|
+
DEFAULT_CONFIG = { }.freeze
|
13
|
+
|
14
|
+
def initialize(name, config)
|
15
|
+
super(name, config.apply_defaults(DEFAULT_CONFIG))
|
16
|
+
end
|
17
|
+
|
18
|
+
def run(_client, _cluster_definition)
|
19
|
+
logger.info("Checking for Route53 DNS records")
|
20
|
+
|
21
|
+
exists = []
|
22
|
+
|
23
|
+
fully_qualified_names.each do |record|
|
24
|
+
if record_exists?(record)
|
25
|
+
exists << record
|
26
|
+
logger.error("Route53 record #{record} already exists!")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
exists.length > 0 ? false : true
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def fully_qualified_names
|
36
|
+
@fully_qualified_names ||= r53_records.map { |record| record.end_with?(".") ? record : "#{record}." }
|
37
|
+
end
|
38
|
+
|
39
|
+
def record_exists?(record)
|
40
|
+
response = r53_client.list_resource_record_sets(
|
41
|
+
hosted_zone_id: r53_zone_id,
|
42
|
+
start_record_name: record,
|
43
|
+
start_record_type: "A",
|
44
|
+
max_items: 1
|
45
|
+
)
|
46
|
+
response.resource_record_sets.first&.name == record
|
47
|
+
end
|
48
|
+
|
49
|
+
def r53_client
|
50
|
+
@r53_client ||= Aws::Route53::Client.new(region: region)
|
51
|
+
end
|
52
|
+
|
53
|
+
def region
|
54
|
+
config[:region]
|
55
|
+
end
|
56
|
+
|
57
|
+
def r53_zone_id
|
58
|
+
config[:r53_zone_id]
|
59
|
+
end
|
60
|
+
|
61
|
+
def r53_records
|
62
|
+
@r53_records ||= config[:r53_records]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../health_check"
|
4
|
+
require_relative "../logger"
|
5
|
+
|
6
|
+
module KubePlatform
|
7
|
+
module PreChecks
|
8
|
+
class ValidPlatformDependencies < PreCheck
|
9
|
+
PlatformDependencyException = Class.new(KubePlatformException)
|
10
|
+
|
11
|
+
include Logger
|
12
|
+
|
13
|
+
def run(_client, cluster_definition)
|
14
|
+
pod_names = Set.new(cluster_definition.resources.map(&:name))
|
15
|
+
pods_with_invalid_dependencies = invalid_platform_startup_dependencies(cluster_definition, pod_names)
|
16
|
+
pods_with_invalid_dependencies.empty? or raise PlatformDependencyException, invalid_dependency_details(pods_with_invalid_dependencies)
|
17
|
+
logger.info("Platform startup dependencies are valid")
|
18
|
+
true
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def invalid_platform_startup_dependencies(cluster_definition, pod_names)
|
24
|
+
cluster_definition.resources.map do |resource|
|
25
|
+
if (dependencies_csv = resource.pod_annotation(:platform_startup_dependencies))
|
26
|
+
unless valid_dependency_list?(dependencies_csv, pod_names)
|
27
|
+
{ name: resource.name, dependencies: dependencies_csv }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end.compact
|
31
|
+
end
|
32
|
+
|
33
|
+
def valid_dependency_list?(dependencies_csv, expected_pod_names)
|
34
|
+
dependencies_csv.split(/, */).all? { |dependency| expected_pod_names.include?(dependency) }
|
35
|
+
end
|
36
|
+
|
37
|
+
def invalid_dependency_details(pods_with_invalid_dependencies)
|
38
|
+
if pods_with_invalid_dependencies.size > 5
|
39
|
+
<<~EOS.chomp
|
40
|
+
Found #{pods_with_invalid_dependencies.size} pod templates with startup dependencies that don't match existing pod names. Showing the first 5.
|
41
|
+
#{pods_with_invalid_dependencies.first(5).join("\n")}
|
42
|
+
EOS
|
43
|
+
else
|
44
|
+
<<~EOS.chomp
|
45
|
+
Found pod templates with startup dependencies that don't match existing pod names.
|
46
|
+
#{pods_with_invalid_dependencies.join("\n")}
|
47
|
+
EOS
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module KubePlatform
|
4
|
+
class PreCheck
|
5
|
+
attr_reader :name, :config
|
6
|
+
|
7
|
+
def initialize(name, config)
|
8
|
+
@name = name
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
class << self
|
13
|
+
def load(class_name:, name:, config:)
|
14
|
+
klass = "KubePlatform::PreChecks::#{class_name}".constantize
|
15
|
+
klass.new(name, config)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|