kitchen-pulumi 0.1.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +21 -0
  3. data/README.md +4 -0
  4. data/lib/kitchen/driver/pulumi.rb +170 -0
  5. data/lib/kitchen/provisioner/pulumi.rb +24 -0
  6. data/lib/kitchen/pulumi.rb +8 -0
  7. data/lib/kitchen/pulumi/command.rb +11 -0
  8. data/lib/kitchen/pulumi/command/input.rb +33 -0
  9. data/lib/kitchen/pulumi/command/output.rb +33 -0
  10. data/lib/kitchen/pulumi/config_attribute.rb +12 -0
  11. data/lib/kitchen/pulumi/config_attribute/backend.rb +34 -0
  12. data/lib/kitchen/pulumi/config_attribute/color.rb +34 -0
  13. data/lib/kitchen/pulumi/config_attribute/config.rb +35 -0
  14. data/lib/kitchen/pulumi/config_attribute/config_file.rb +34 -0
  15. data/lib/kitchen/pulumi/config_attribute/directory.rb +34 -0
  16. data/lib/kitchen/pulumi/config_attribute/fail_fast.rb +34 -0
  17. data/lib/kitchen/pulumi/config_attribute/plugins.rb +34 -0
  18. data/lib/kitchen/pulumi/config_attribute/refresh_config.rb +34 -0
  19. data/lib/kitchen/pulumi/config_attribute/secrets.rb +35 -0
  20. data/lib/kitchen/pulumi/config_attribute/stack.rb +33 -0
  21. data/lib/kitchen/pulumi/config_attribute/stack_evolution.rb +37 -0
  22. data/lib/kitchen/pulumi/config_attribute/systems.rb +33 -0
  23. data/lib/kitchen/pulumi/config_attribute_cacher.rb +28 -0
  24. data/lib/kitchen/pulumi/config_attribute_definer.rb +39 -0
  25. data/lib/kitchen/pulumi/config_schemas.rb +11 -0
  26. data/lib/kitchen/pulumi/config_schemas/array_of_hashes.rb +12 -0
  27. data/lib/kitchen/pulumi/config_schemas/boolean.rb +12 -0
  28. data/lib/kitchen/pulumi/config_schemas/config_evolution_array.rb +40 -0
  29. data/lib/kitchen/pulumi/config_schemas/error_messages.yml +21 -0
  30. data/lib/kitchen/pulumi/config_schemas/hash.rb +12 -0
  31. data/lib/kitchen/pulumi/config_schemas/stack_settings_hash.rb +20 -0
  32. data/lib/kitchen/pulumi/config_schemas/string.rb +12 -0
  33. data/lib/kitchen/pulumi/config_schemas/system.rb +577 -0
  34. data/lib/kitchen/pulumi/config_schemas/systems.rb +20 -0
  35. data/lib/kitchen/pulumi/configurable.rb +27 -0
  36. data/lib/kitchen/pulumi/error.rb +10 -0
  37. data/lib/kitchen/pulumi/file_path_config_attribute_definer.rb +25 -0
  38. data/lib/kitchen/pulumi/inspec.rb +66 -0
  39. data/lib/kitchen/pulumi/inspec_options_mapper.rb +69 -0
  40. data/lib/kitchen/pulumi/inspec_with_hosts.rb +40 -0
  41. data/lib/kitchen/pulumi/inspec_without_hosts.rb +34 -0
  42. data/lib/kitchen/pulumi/kitchen_instance.rb +12 -0
  43. data/lib/kitchen/pulumi/shell_out.rb +40 -0
  44. data/lib/kitchen/pulumi/system.rb +130 -0
  45. data/lib/kitchen/pulumi/system_attrs_resolver.rb +59 -0
  46. data/lib/kitchen/pulumi/system_hosts_resolver.rb +34 -0
  47. data/lib/kitchen/pulumi/version.rb +5 -0
  48. data/lib/kitchen/verifier/pulumi.rb +177 -0
  49. metadata +323 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 364ba19dd3c354faa5da8dced15d5a512ddd5632049a7b833ae9be70988986cc
4
+ data.tar.gz: 38b0bde440532a316ffeaf1da6fba1556a071d5b3021ed3e10adc90447325862
5
+ SHA512:
6
+ metadata.gz: 1ddea6c299dfe2537cf3b356af371415bebd01b134abf5f5d7a5ae053fea66f7975fa400914f53d8d8074a571a394829ff3524bc259feed9d9ea0722d3aafa0b
7
+ data.tar.gz: 362722b88d15305c290f580c3f5363e3b61d1b84bd084ec88dbe59d345111d50151d64e295b585bfc5916fcb33307f8e3033cb0c12f290490644601edca09e56
data/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2018 jacoblearned
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,4 @@
1
+ [![CircleCI](https://circleci.com/gh/jacoblearned/kitchen-pulumi/tree/master.svg?style=shield)](https://circleci.com/gh/jacoblearned/kitchen-pulumi/tree/master)
2
+
3
+ # kitchen-pulumi
4
+ Test-Kitchen plugins for Pulumi projects
@@ -0,0 +1,170 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen'
4
+ require 'kitchen/driver/base'
5
+ require 'kitchen/pulumi/error'
6
+ require 'kitchen/pulumi/shell_out'
7
+ require 'kitchen/pulumi/configurable'
8
+ require 'kitchen/pulumi/command/input'
9
+ require 'kitchen/pulumi/command/output'
10
+ require 'kitchen/pulumi/config_attribute/config'
11
+ require 'kitchen/pulumi/config_attribute/config_file'
12
+ require 'kitchen/pulumi/config_attribute/directory'
13
+ require 'kitchen/pulumi/config_attribute/plugins'
14
+ require 'kitchen/pulumi/config_attribute/backend'
15
+ require 'kitchen/pulumi/config_attribute/secrets'
16
+ require 'kitchen/pulumi/config_attribute/stack'
17
+ require 'kitchen/pulumi/config_attribute/stack_evolution'
18
+ require 'kitchen/pulumi/config_attribute/refresh_config'
19
+
20
+ module Kitchen
21
+ module Driver
22
+ # Driver class implementing the CLI equivalency between Kitchen and Pulumi
23
+ class Pulumi < ::Kitchen::Driver::Base
24
+ kitchen_driver_api_version 2
25
+
26
+ include ::Kitchen::Pulumi::Configurable
27
+
28
+ # Include config attributes consumable via .kitchen.yml
29
+ include ::Kitchen::Pulumi::ConfigAttribute::Config
30
+ include ::Kitchen::Pulumi::ConfigAttribute::ConfigFile
31
+ include ::Kitchen::Pulumi::ConfigAttribute::Directory
32
+ include ::Kitchen::Pulumi::ConfigAttribute::Plugins
33
+ include ::Kitchen::Pulumi::ConfigAttribute::Backend
34
+ include ::Kitchen::Pulumi::ConfigAttribute::Secrets
35
+ include ::Kitchen::Pulumi::ConfigAttribute::Stack
36
+ include ::Kitchen::Pulumi::ConfigAttribute::StackEvolution
37
+ include ::Kitchen::Pulumi::ConfigAttribute::RefreshConfig
38
+
39
+ def create(_state)
40
+ dir = "-C #{config_directory}"
41
+ stack = config_stack.empty? ? instance.suite.name : config_stack
42
+ conf_file = config_file
43
+
44
+ login
45
+ initialize_stack(stack, dir)
46
+ configure(config_config, stack, dir, conf_file)
47
+ configure(config_secrets, stack, dir, conf_file, is_secret: true)
48
+ end
49
+
50
+ def update(_state)
51
+ dir = "-C #{config_directory}"
52
+ stack = config_stack.empty? ? instance.suite.name : config_stack
53
+ conf_file = config_file
54
+
55
+ login
56
+ refresh_config(stack, dir, conf_file) if config_refresh_config
57
+ update_stack(stack, dir, conf_file)
58
+ evolve_stack(stack, dir) unless config_stack_evolution.empty?
59
+ end
60
+
61
+ def destroy(_state)
62
+ dir = "-C #{config_directory}"
63
+ stack = config_stack.empty? ? instance.suite.name : config_stack
64
+
65
+ cmds = [
66
+ "destroy -y -r --show-config -s #{stack} #{dir}",
67
+ "stack rm --preserve-config -y -s #{stack} #{dir}",
68
+ ]
69
+
70
+ login
71
+ ::Kitchen::Pulumi::ShellOut.run(cmd: cmds, logger: logger)
72
+ rescue ::Kitchen::Pulumi::Error => e
73
+ puts 'Continuing...' if e.message.match?(/no stack named '#{stack}' found/)
74
+ end
75
+
76
+ def login
77
+ backend = config_backend == 'local' ? '--local' : config_backend
78
+ ::Kitchen::Pulumi::ShellOut.run(
79
+ cmd: "login #{backend}",
80
+ logger: logger,
81
+ )
82
+ end
83
+
84
+ def initialize_stack(stack, dir = '')
85
+ ::Kitchen::Pulumi::ShellOut.run(
86
+ cmd: "stack init #{stack} #{dir}",
87
+ logger: logger,
88
+ )
89
+ rescue ::Kitchen::Pulumi::Error => e
90
+ puts 'Continuing...' if e.message.match?(/stack '#{stack}' already exists/)
91
+ end
92
+
93
+ def configure(stack_confs, stack, conf_file, dir = '', is_secret: false)
94
+ secret = is_secret ? '--secret' : ''
95
+ base_cmd = "config set #{secret} -s #{stack} #{dir} #{conf_file}"
96
+
97
+ stack_confs.each do |namespace, stack_settings|
98
+ stack_settings.each do |key, val|
99
+ ::Kitchen::Pulumi::ShellOut.run(
100
+ cmd: "#{base_cmd} #{namespace}:#{key} \"#{val}\"",
101
+ logger: logger,
102
+ )
103
+ end
104
+ end
105
+ end
106
+
107
+ def refresh_config(stack, conf_file, dir = '')
108
+ ::Kitchen::Pulumi::ShellOut.run(
109
+ cmd: "config refresh -s #{stack} #{dir} #{conf_file}",
110
+ logger: logger,
111
+ )
112
+ rescue ::Kitchen::Pulumi::Error => e
113
+ puts 'Continuing...' if e.message.match?(/no previous deployment/)
114
+ end
115
+
116
+ def config_file(conf_file = '')
117
+ file = conf_file.empty? ? config_config_file : conf_file
118
+ return '' if File.directory?(file) || file.empty?
119
+
120
+ "--config-file #{file}"
121
+ end
122
+
123
+ def update_stack(stack, conf_file, dir = '')
124
+ ::Kitchen::Pulumi::ShellOut.run(
125
+ cmd: "up -y -r --show-config -s #{stack} #{dir} #{conf_file}",
126
+ logger: logger,
127
+ )
128
+ end
129
+
130
+ def evolve_stack(stack, dir = '')
131
+ config_stack_evolution.each do |evolution|
132
+ conf_file = config_file(evolution.fetch(:config_file, ''))
133
+ new_stack_confs = evolution.fetch(:config, {})
134
+ new_stack_secrets = evolution.fetch(:secrets, {})
135
+
136
+ configure(new_stack_confs, stack, conf_file, dir)
137
+ configure(new_stack_secrets, stack, conf_file, dir, is_secret: true)
138
+ update_stack(stack, conf_file, dir)
139
+ end
140
+ end
141
+
142
+ def stack_inputs(&block)
143
+ ::Kitchen::Pulumi::Command::Input.run(
144
+ directory: config_directory,
145
+ stack: config_stack,
146
+ conf_file: config_file,
147
+ logger: logger,
148
+ &block
149
+ )
150
+
151
+ self
152
+ rescue ::Kitchen::Pulumi::Error => e
153
+ raise ::Kitchen::ActionFailed, e.message
154
+ end
155
+
156
+ def stack_outputs(&block)
157
+ ::Kitchen::Pulumi::Command::Output.run(
158
+ directory: config_directory,
159
+ stack: config_stack,
160
+ logger: logger,
161
+ &block
162
+ )
163
+
164
+ self
165
+ rescue ::Kitchen::Pulumi::Error => e
166
+ raise ::Kitchen::ActionFailed, e.message
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen'
4
+ require 'kitchen/provisioner/base'
5
+ require 'kitchen/pulumi/configurable'
6
+
7
+ module Kitchen
8
+ module Provisioner
9
+ # Driver class whose call method is invoked when users
10
+ # run kitchen converge
11
+ class Pulumi < ::Kitchen::Provisioner::Base
12
+ kitchen_provisioner_api_version 2
13
+
14
+ include ::Kitchen::Pulumi::Configurable
15
+
16
+ # Runs stack updates via the instance driver
17
+ def call(state)
18
+ instance.driver.update(state)
19
+ rescue ::Kitchen::Pulumi::Error => e
20
+ raise(::Kitchen::ActionFailed, e.message)
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Global kitchen module
4
+ module Kitchen
5
+ # Namespace for Kitchen-Pulumi logic
6
+ module Pulumi
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen/pulumi'
4
+
5
+ module Kitchen
6
+ module Pulumi
7
+ # The namespace for Pulumi commands.
8
+ module Command
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'kitchen'
5
+ require 'kitchen/pulumi/command'
6
+ require 'kitchen/pulumi/error'
7
+ require 'kitchen/pulumi/shell_out'
8
+
9
+ module Kitchen
10
+ module Pulumi
11
+ module Command
12
+ # Class used to fetch resolved stack inputs via '$ pulumi config --json'
13
+ module Input
14
+ class << self
15
+ def run(directory:, stack:, conf_file:, logger:)
16
+ cmd = "config -C #{directory} -s #{stack} #{conf_file} -j"
17
+
18
+ ::Kitchen::Pulumi::ShellOut.run(cmd: cmd, logger: logger) do |stdout:|
19
+ yield inputs: ::Kitchen::Util.stringified_hash(
20
+ ::JSON.parse(stdout),
21
+ )
22
+ end
23
+ rescue ::JSON::ParserError => e
24
+ raise(
25
+ ::Kitchen::Pulumi::Error,
26
+ "Parsing resolved stack config as JSON failed: #{e.message}",
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+ require 'kitchen'
5
+ require 'kitchen/pulumi/command'
6
+ require 'kitchen/pulumi/error'
7
+ require 'kitchen/pulumi/shell_out'
8
+
9
+ module Kitchen
10
+ module Pulumi
11
+ module Command
12
+ # Class used to fetch stack outputs via '$ pulumi stack output --json'
13
+ module Output
14
+ class << self
15
+ def run(directory:, stack:, logger:)
16
+ cmd = "stack -C #{directory} -s #{stack} output -j"
17
+
18
+ ::Kitchen::Pulumi::ShellOut.run(cmd: cmd, logger: logger) do |stdout:|
19
+ yield outputs: ::Kitchen::Util.stringified_hash(
20
+ ::JSON.parse(stdout),
21
+ )
22
+ end
23
+ rescue ::JSON::ParserError => e
24
+ raise(
25
+ ::Kitchen::Pulumi::Error,
26
+ "Parsing Pulumi stack output as JSON failed: #{e.message}",
27
+ )
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen/pulumi'
4
+
5
+ module Kitchen
6
+ module Pulumi
7
+ # Namespace for config attributes that are set by the user in
8
+ # .kitchen.yml and used within Test Kitchen plugins that include them.
9
+ module ConfigAttribute
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen/pulumi'
4
+ require 'kitchen/pulumi/config_schemas/string'
5
+ require 'kitchen/pulumi/config_attribute_cacher'
6
+ require 'kitchen/pulumi/config_attribute_definer'
7
+
8
+ module Kitchen
9
+ module Pulumi
10
+ module ConfigAttribute
11
+ # Attribute used to specify the Pulumi backend to use.
12
+ # It contains the URL to the backend, local or remote
13
+ module Backend
14
+ def self.included(plugin_class)
15
+ definer = ConfigAttributeDefiner.new(
16
+ attribute: self,
17
+ schema: ConfigSchemas::String,
18
+ )
19
+ definer.define(plugin_class: plugin_class)
20
+ end
21
+
22
+ def self.to_sym
23
+ :backend
24
+ end
25
+
26
+ extend ConfigAttributeCacher
27
+
28
+ def config_backend_default_value
29
+ ''
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen'
4
+ require 'kitchen/pulumi'
5
+ require 'kitchen/pulumi/config_schemas/boolean'
6
+ require 'kitchen/pulumi/config_attribute_cacher'
7
+ require 'kitchen/pulumi/config_attribute_definer'
8
+
9
+ module Kitchen
10
+ module Pulumi
11
+ module ConfigAttribute
12
+ # Attribute to toggle colored output from systems invoked by the plugin
13
+ module Color
14
+ def self.included(plugin_class)
15
+ definer = ConfigAttributeDefiner.new(
16
+ attribute: self,
17
+ schema: ConfigSchemas::Boolean,
18
+ )
19
+ definer.define(plugin_class: plugin_class)
20
+ end
21
+
22
+ def self.to_sym
23
+ :color
24
+ end
25
+
26
+ extend ConfigAttributeCacher
27
+
28
+ def config_color_default_value
29
+ ::Kitchen.tty?
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen/pulumi/config_attribute'
4
+ require 'kitchen/pulumi/config_schemas/stack_settings_hash'
5
+ require 'kitchen/pulumi/config_attribute_cacher'
6
+ require 'kitchen/pulumi/config_attribute_definer'
7
+
8
+ module Kitchen
9
+ module Pulumi
10
+ module ConfigAttribute
11
+ # Module used for the 'config' instance var on an
12
+ # instance driver. The driver will set the Pulumi stack
13
+ # configs for each of the namespaces provided.
14
+ module Config
15
+ def self.included(plugin)
16
+ definer = ConfigAttributeDefiner.new(
17
+ attribute: self,
18
+ schema: ConfigSchemas::StackSettingsHash,
19
+ )
20
+ definer.define(plugin_class: plugin)
21
+ end
22
+
23
+ def self.to_sym
24
+ :config
25
+ end
26
+
27
+ extend ConfigAttributeCacher
28
+
29
+ def config_config_default_value
30
+ {}
31
+ end
32
+ end
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'kitchen/pulumi'
4
+ require 'kitchen/pulumi/config_schemas/string'
5
+ require 'kitchen/pulumi/config_attribute_cacher'
6
+ require 'kitchen/pulumi/file_path_config_attribute_definer'
7
+
8
+ module Kitchen
9
+ module Pulumi
10
+ module ConfigAttribute
11
+ # Attribute used to specify the config_file containing a project's
12
+ # stack configuration
13
+ module ConfigFile
14
+ def self.included(plugin_class)
15
+ definer = FilePathConfigAttributeDefiner.new(
16
+ attribute: self,
17
+ schema: ConfigSchemas::String,
18
+ )
19
+ definer.define(plugin_class: plugin_class)
20
+ end
21
+
22
+ def self.to_sym
23
+ :config_file
24
+ end
25
+
26
+ extend ConfigAttributeCacher
27
+
28
+ def config_config_file_default_value
29
+ ''
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end