kitchen-pulumi 0.1.0.pre.beta

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.
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