simplygenius-atmos 0.7.1 → 0.8.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.
Files changed (87) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/exe/atmos +2 -2
  4. data/lib/{atmos.rb → simplygenius/atmos.rb} +9 -7
  5. data/lib/simplygenius/atmos/cli.rb +116 -0
  6. data/lib/simplygenius/atmos/commands/account.rb +69 -0
  7. data/lib/simplygenius/atmos/commands/apply.rb +24 -0
  8. data/lib/simplygenius/atmos/commands/auth_exec.rb +34 -0
  9. data/lib/simplygenius/atmos/commands/base_command.rb +16 -0
  10. data/lib/simplygenius/atmos/commands/bootstrap.rb +76 -0
  11. data/lib/simplygenius/atmos/commands/container.rb +62 -0
  12. data/lib/simplygenius/atmos/commands/destroy.rb +22 -0
  13. data/lib/simplygenius/atmos/commands/generate.rb +187 -0
  14. data/lib/simplygenius/atmos/commands/init.rb +22 -0
  15. data/lib/simplygenius/atmos/commands/new.rb +22 -0
  16. data/lib/simplygenius/atmos/commands/otp.rb +58 -0
  17. data/lib/simplygenius/atmos/commands/plan.rb +24 -0
  18. data/lib/simplygenius/atmos/commands/secret.rb +91 -0
  19. data/lib/simplygenius/atmos/commands/terraform.rb +56 -0
  20. data/lib/simplygenius/atmos/commands/user.rb +78 -0
  21. data/lib/simplygenius/atmos/config.rb +279 -0
  22. data/lib/simplygenius/atmos/exceptions.rb +13 -0
  23. data/lib/simplygenius/atmos/generator.rb +232 -0
  24. data/lib/simplygenius/atmos/ipc.rb +136 -0
  25. data/lib/simplygenius/atmos/ipc_actions/notify.rb +31 -0
  26. data/lib/simplygenius/atmos/ipc_actions/ping.rb +23 -0
  27. data/lib/simplygenius/atmos/logging.rb +164 -0
  28. data/lib/simplygenius/atmos/otp.rb +62 -0
  29. data/lib/simplygenius/atmos/plugin.rb +27 -0
  30. data/lib/simplygenius/atmos/plugin_manager.rb +120 -0
  31. data/lib/simplygenius/atmos/plugins/output_filter.rb +29 -0
  32. data/lib/simplygenius/atmos/plugins/prompt_notify.rb +21 -0
  33. data/lib/simplygenius/atmos/provider_factory.rb +23 -0
  34. data/lib/simplygenius/atmos/providers/aws/account_manager.rb +83 -0
  35. data/lib/simplygenius/atmos/providers/aws/auth_manager.rb +220 -0
  36. data/lib/simplygenius/atmos/providers/aws/container_manager.rb +118 -0
  37. data/lib/simplygenius/atmos/providers/aws/provider.rb +53 -0
  38. data/lib/simplygenius/atmos/providers/aws/s3_secret_manager.rb +51 -0
  39. data/lib/simplygenius/atmos/providers/aws/user_manager.rb +213 -0
  40. data/lib/simplygenius/atmos/settings_hash.rb +93 -0
  41. data/lib/simplygenius/atmos/source_path.rb +186 -0
  42. data/lib/simplygenius/atmos/template.rb +117 -0
  43. data/lib/simplygenius/atmos/terraform_executor.rb +297 -0
  44. data/lib/simplygenius/atmos/ui.rb +173 -0
  45. data/lib/simplygenius/atmos/utils.rb +54 -0
  46. data/lib/simplygenius/atmos/version.rb +5 -0
  47. data/templates/new/config/atmos.yml +21 -13
  48. data/templates/new/config/atmos/recipes.yml +16 -0
  49. data/templates/new/config/atmos/runtime.yml +9 -0
  50. metadata +46 -40
  51. data/lib/atmos/cli.rb +0 -105
  52. data/lib/atmos/commands/account.rb +0 -65
  53. data/lib/atmos/commands/apply.rb +0 -20
  54. data/lib/atmos/commands/auth_exec.rb +0 -29
  55. data/lib/atmos/commands/base_command.rb +0 -12
  56. data/lib/atmos/commands/bootstrap.rb +0 -72
  57. data/lib/atmos/commands/container.rb +0 -58
  58. data/lib/atmos/commands/destroy.rb +0 -18
  59. data/lib/atmos/commands/generate.rb +0 -90
  60. data/lib/atmos/commands/init.rb +0 -18
  61. data/lib/atmos/commands/new.rb +0 -18
  62. data/lib/atmos/commands/otp.rb +0 -54
  63. data/lib/atmos/commands/plan.rb +0 -20
  64. data/lib/atmos/commands/secret.rb +0 -87
  65. data/lib/atmos/commands/terraform.rb +0 -52
  66. data/lib/atmos/commands/user.rb +0 -74
  67. data/lib/atmos/config.rb +0 -208
  68. data/lib/atmos/exceptions.rb +0 -9
  69. data/lib/atmos/generator.rb +0 -199
  70. data/lib/atmos/generator_factory.rb +0 -93
  71. data/lib/atmos/ipc.rb +0 -132
  72. data/lib/atmos/ipc_actions/notify.rb +0 -27
  73. data/lib/atmos/ipc_actions/ping.rb +0 -19
  74. data/lib/atmos/logging.rb +0 -160
  75. data/lib/atmos/otp.rb +0 -61
  76. data/lib/atmos/provider_factory.rb +0 -19
  77. data/lib/atmos/providers/aws/account_manager.rb +0 -82
  78. data/lib/atmos/providers/aws/auth_manager.rb +0 -208
  79. data/lib/atmos/providers/aws/container_manager.rb +0 -116
  80. data/lib/atmos/providers/aws/provider.rb +0 -51
  81. data/lib/atmos/providers/aws/s3_secret_manager.rb +0 -49
  82. data/lib/atmos/providers/aws/user_manager.rb +0 -211
  83. data/lib/atmos/settings_hash.rb +0 -90
  84. data/lib/atmos/terraform_executor.rb +0 -267
  85. data/lib/atmos/ui.rb +0 -159
  86. data/lib/atmos/utils.rb +0 -50
  87. data/lib/atmos/version.rb +0 -3
@@ -0,0 +1,22 @@
1
+ require_relative 'terraform'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Commands
6
+
7
+ class Destroy < Terraform
8
+
9
+ def self.description
10
+ "Runs terraform destroy"
11
+ end
12
+
13
+ def execute
14
+ @terraform_arguments.insert(0, "destroy")
15
+ super
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,187 @@
1
+ require_relative 'base_command'
2
+ require_relative '../../atmos/source_path'
3
+ require_relative '../../atmos/generator'
4
+ require_relative '../../atmos/utils'
5
+
6
+ module SimplyGenius
7
+ module Atmos
8
+ module Commands
9
+
10
+ # From https://github.com/rubber/rubber/blob/master/lib/rubber/commands/vulcanize.rb
11
+ class Generate < BaseCommand
12
+
13
+ def self.description
14
+ <<~EOF
15
+ Installs configuration templates used by atmos to create infrastructure
16
+ resources e.g.
17
+
18
+ atmos generate aws/vpc
19
+
20
+ use --list to get a list of the template names for a given sourceroot
21
+ EOF
22
+ end
23
+
24
+ option ["-f", "--force"],
25
+ :flag, "Overwrite files that already exist"
26
+ option ["-n", "--dryrun"],
27
+ :flag, "Run but do not make any changes"
28
+ option ["-q", "--quiet"],
29
+ :flag, "Supress status output"
30
+ option ["-s", "--skip"],
31
+ :flag, "Skip files that already exist"
32
+ option ["-d", "--[no-]dependencies"],
33
+ :flag, "Walk dependencies, or not", default: true
34
+ option ["-l", "--list"],
35
+ :flag, "list available templates"
36
+ option ["-u", "--update"],
37
+ :flag, "update all installed templates\n"
38
+ option ["-p", "--sourcepath"],
39
+ "PATH", "search for templates using given sourcepath",
40
+ multivalued: true
41
+ option ["-r", "--[no-]sourcepaths"],
42
+ :flag, "clear sourcepaths from template search\n", default: true
43
+ option ["-c", "--context"],
44
+ "CONTEXT", "provide context variables (dot notation)",
45
+ multivalued: true
46
+
47
+ parameter "TEMPLATE ...", "atmos template(s)", required: false
48
+
49
+ def execute
50
+ signal_usage_error "template name is required" if template_list.blank? && ! list? && !update?
51
+
52
+ sourcepath_list.each do |sp|
53
+ SourcePath.register(File.basename(sp), sp)
54
+ end
55
+
56
+ if sourcepaths?
57
+
58
+ # don't want to fail for new repo
59
+ if Atmos.config && Atmos.config.is_atmos_repo?
60
+ Atmos.config['template_sources'].try(:each) do |item|
61
+ SourcePath.register(item.name, item.location)
62
+ end
63
+ end
64
+
65
+ # Always search for templates against the bundled templates directory
66
+ SourcePath.register('bundled', File.expand_path('../../../../../templates', __FILE__))
67
+
68
+ end
69
+
70
+ if list?
71
+ logger.info "Valid templates are:"
72
+ SourcePath.registry.each do |spname, sp|
73
+ logger.info("\tSourcepath #{sp}")
74
+ filtered_names = sp.template_names.select do |name|
75
+ template_list.blank? || template_list.any? {|f| name =~ /#{f}/ }
76
+ end
77
+ filtered_names.each {|n| logger.info ("\t\t#{n}")}
78
+ end
79
+ else
80
+ g = Generator.new(force: force?,
81
+ pretend: dryrun?,
82
+ quiet: quiet?,
83
+ skip: skip?,
84
+ dependencies: dependencies?)
85
+
86
+ begin
87
+
88
+ context = SettingsHash.new
89
+ context_list.each do |c|
90
+ key, value = c.split('=', 2)
91
+ context.notation_put(key, value)
92
+ end
93
+
94
+ if update?
95
+ # this isn't 100% foolproof, but is a convenience that should help for most cases
96
+
97
+ filtered_templates = state[:visited_templates].select do |vt|
98
+ template_list.blank? || template_list.any? {|n| vt[:name] =~ /#{n}/ }
99
+ end
100
+
101
+ sps = filtered_templates.collect(&:source).uniq
102
+ sps.each do |src|
103
+ spname = src[:name]
104
+ sploc = src[:location]
105
+
106
+ existing_sp = SourcePath.registry[spname]
107
+ if existing_sp
108
+ if existing_sp.location != sploc
109
+ logger.warn("Saved sourcepath location differs from that in configuration")
110
+ logger.warn(" #{spname} -> saved=#{sploc} configured=#{existing_sp.location}")
111
+ logger.warn(" consider running with --no-sourcepaths")
112
+ end
113
+ else
114
+ sp = SourcePath.register(spname, sploc)
115
+ logger.warn("Saved state contains a source path missing from configuration: #{sp}")
116
+ end
117
+ end
118
+
119
+ filtered_templates.each do |vt|
120
+ name = vt[:name]
121
+ ctx = vt[:context]
122
+ spname = vt[:source][:name]
123
+ sp = SourcePath.registry[spname]
124
+ tmpl = sp.template(name)
125
+ tmpl.scoped_context.merge!(ctx) if ctx
126
+ tmpl.context.merge!(context)
127
+ g.apply_template(tmpl)
128
+ end
129
+ else
130
+ g.generate(*template_list, context: context)
131
+ end
132
+
133
+ save_state(g.visited_templates, template_list)
134
+
135
+ rescue ArgumentError => e
136
+ logger.error(e.message)
137
+ exit 1
138
+ end
139
+ end
140
+
141
+ end
142
+
143
+ def state_file
144
+ @state_file ||= Atmos.config["generate.state_file"]
145
+ end
146
+
147
+ def state
148
+ @state ||= begin
149
+ if state_file.present?
150
+ path = File.expand_path(state_file)
151
+ yml_hash = {}
152
+ if File.exist?(path)
153
+ yml_hash = YAML.load_file(path)
154
+ end
155
+ SettingsHash.new(yml_hash)
156
+ else
157
+ SettingsHash.new
158
+ end
159
+ end
160
+ end
161
+
162
+ def save_state(visited_templates, entrypoint_template_names)
163
+ if state_file.present?
164
+ visited_state = []
165
+ visited_templates.each do |tmpl|
166
+ visited_tmpl = tmpl.to_h
167
+ visited_tmpl[:context] = tmpl.scoped_context.to_h
168
+ visited_state << visited_tmpl
169
+ end
170
+
171
+ state[:visited_templates] ||= []
172
+ state[:visited_templates].concat(visited_state)
173
+ state[:visited_templates].sort! {|h1, h2| h1[:name] <=> h2[:name] }.uniq!
174
+
175
+ state[:entrypoint_templates] ||= []
176
+ state[:entrypoint_templates].concat(entrypoint_template_names)
177
+ state[:entrypoint_templates].sort!.uniq!
178
+
179
+ File.write(state_file, YAML.dump(state.to_hash))
180
+ end
181
+ end
182
+
183
+ end
184
+
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'terraform'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Commands
6
+
7
+ class Init < Terraform
8
+
9
+ def self.description
10
+ "Runs terraform init"
11
+ end
12
+
13
+ def execute
14
+ @terraform_arguments.insert(0, "init")
15
+ super
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ require_relative 'generate'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Commands
6
+
7
+ class New < Generate
8
+
9
+ def self.description
10
+ "Sets up a new atmos project in the current directory"
11
+ end
12
+
13
+ def execute
14
+ template_list << "new"
15
+ super
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,58 @@
1
+ require_relative 'base_command'
2
+ require_relative '../../atmos/otp'
3
+ require 'clipboard'
4
+
5
+ module SimplyGenius
6
+ module Atmos
7
+ module Commands
8
+
9
+ class Otp < BaseCommand
10
+
11
+ def self.description
12
+ "Generates an otp token for the given user"
13
+ end
14
+
15
+ option ["-s", "--secret"],
16
+ 'SECRET', "The otp secret\nWill save for future use"
17
+
18
+ option ["-c", "--clipboard"],
19
+ :flag,
20
+ <<~EOF
21
+ Automatically copy the token to the system
22
+ clipboard. For dependencies see:
23
+ https://github.com/janlelis/clipboard
24
+ EOF
25
+
26
+ parameter "NAME",
27
+ "The otp name (IAM username)"
28
+
29
+ def execute
30
+ code = nil
31
+ if secret
32
+ Atmos::Otp.instance.add(name, secret)
33
+ code = Atmos::Otp.instance.generate(name)
34
+ Atmos::Otp.instance.save
35
+ else
36
+ code = Atmos::Otp.instance.generate(name)
37
+ end
38
+
39
+ if code.nil?
40
+ signal_usage_error <<~EOF
41
+ No otp secret has been setup for #{name}
42
+ Use the -m flag to 'atmos user create' to create/activate one
43
+ or associate an existing secret with 'atmos otp -s <secret> <name>'
44
+ EOF
45
+ else
46
+ puts code
47
+ end
48
+
49
+ if clipboard?
50
+ Clipboard.copy(code)
51
+ end
52
+ end
53
+
54
+ end
55
+
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'terraform'
2
+
3
+ module SimplyGenius
4
+ module Atmos
5
+ module Commands
6
+
7
+ class Plan < Terraform
8
+
9
+ def self.description
10
+ "Runs terraform plan"
11
+ end
12
+
13
+ def execute
14
+ args = ["plan"]
15
+ args << "--get-modules" unless Atmos.config["disable_auto_modules"].to_s == "true"
16
+ @terraform_arguments.insert(0, *args)
17
+ super
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,91 @@
1
+ require_relative 'base_command'
2
+ require 'climate_control'
3
+
4
+ module SimplyGenius
5
+ module Atmos
6
+ module Commands
7
+
8
+ class Secret < BaseCommand
9
+
10
+ def self.description
11
+ "Manages application secrets"
12
+ end
13
+
14
+ subcommand "get", "Gets the secret value" do
15
+
16
+ parameter "KEY",
17
+ "The secret key"
18
+
19
+ def execute
20
+
21
+ Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
22
+ ClimateControl.modify(auth_env) do
23
+ value = Atmos.config.provider.secret_manager.get(key)
24
+ logger.info "Secret value for #{key}: #{value}"
25
+ end
26
+ end
27
+
28
+ end
29
+
30
+ end
31
+
32
+ subcommand "set", "Sets the secret value" do
33
+
34
+ parameter "KEY",
35
+ "The secret key"
36
+
37
+ parameter "VALUE",
38
+ "The secret value"
39
+
40
+ def execute
41
+
42
+ Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
43
+ ClimateControl.modify(auth_env) do
44
+ Atmos.config.provider.secret_manager.set(key, value)
45
+ logger.info "Secret set for #{key}"
46
+ end
47
+ end
48
+
49
+ end
50
+
51
+ end
52
+
53
+ subcommand "list", "Lists all secret keys" do
54
+
55
+ def execute
56
+
57
+ Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
58
+ ClimateControl.modify(auth_env) do
59
+ logger.info "Secret keys are:"
60
+ Atmos.config.provider.secret_manager.to_h.keys.each {|k| logger.info k}
61
+ end
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ subcommand "delete", "Deletes the secret key/value" do
69
+
70
+ parameter "KEY",
71
+ "The secret key"
72
+
73
+ def execute
74
+
75
+ Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
76
+ ClimateControl.modify(auth_env) do
77
+ value = Atmos.config.provider.secret_manager.get(key)
78
+ Atmos.config.provider.secret_manager.delete(key)
79
+ logger.info "Deleted secret: #{key}=#{value}"
80
+ end
81
+ end
82
+
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+
89
+ end
90
+ end
91
+ end
@@ -0,0 +1,56 @@
1
+ require_relative 'base_command'
2
+ require_relative '../../atmos/terraform_executor'
3
+
4
+ module SimplyGenius
5
+ module Atmos
6
+ module Commands
7
+
8
+ class Terraform < BaseCommand
9
+
10
+ def self.description
11
+ "Runs terraform"
12
+ end
13
+
14
+ # override so we can pass all options/flags/parameters directly to
15
+ # terraform instead of having clamp parse them
16
+ def parse(arguments)
17
+ @terraform_arguments = arguments
18
+ end
19
+
20
+ def execute
21
+
22
+ unless Atmos.config.is_atmos_repo?
23
+ signal_usage_error <<~EOF
24
+ Atmos can only run terraform from a location configured for atmos.
25
+ Have you run atmos init?"
26
+ EOF
27
+ end
28
+
29
+ Atmos.config.provider.auth_manager.authenticate(ENV) do |auth_env|
30
+ begin
31
+
32
+ # TODO: hack to allow apply/etc for bootstrap group
33
+ # Fix this once we allow more extensive recipe grouping
34
+ working_group = 'default'
35
+ @terraform_arguments.each_with_index do |a, i|
36
+ if a == "--group"
37
+ @terraform_arguments.delete_at(i)
38
+ working_group = @terraform_arguments.delete_at(i)
39
+ break
40
+ end
41
+ end
42
+
43
+ exe = TerraformExecutor.new(process_env: auth_env, working_group: working_group)
44
+ get_modules = @terraform_arguments.delete("--get-modules")
45
+ exe.run(*@terraform_arguments, get_modules: get_modules.present?)
46
+ rescue TerraformExecutor::ProcessFailed => e
47
+ logger.error(e.message)
48
+ end
49
+ end
50
+ end
51
+
52
+ end
53
+
54
+ end
55
+ end
56
+ end