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.
- checksums.yaml +4 -4
- data/README.md +4 -4
- data/exe/atmos +2 -2
- data/lib/{atmos.rb → simplygenius/atmos.rb} +9 -7
- data/lib/simplygenius/atmos/cli.rb +116 -0
- data/lib/simplygenius/atmos/commands/account.rb +69 -0
- data/lib/simplygenius/atmos/commands/apply.rb +24 -0
- data/lib/simplygenius/atmos/commands/auth_exec.rb +34 -0
- data/lib/simplygenius/atmos/commands/base_command.rb +16 -0
- data/lib/simplygenius/atmos/commands/bootstrap.rb +76 -0
- data/lib/simplygenius/atmos/commands/container.rb +62 -0
- data/lib/simplygenius/atmos/commands/destroy.rb +22 -0
- data/lib/simplygenius/atmos/commands/generate.rb +187 -0
- data/lib/simplygenius/atmos/commands/init.rb +22 -0
- data/lib/simplygenius/atmos/commands/new.rb +22 -0
- data/lib/simplygenius/atmos/commands/otp.rb +58 -0
- data/lib/simplygenius/atmos/commands/plan.rb +24 -0
- data/lib/simplygenius/atmos/commands/secret.rb +91 -0
- data/lib/simplygenius/atmos/commands/terraform.rb +56 -0
- data/lib/simplygenius/atmos/commands/user.rb +78 -0
- data/lib/simplygenius/atmos/config.rb +279 -0
- data/lib/simplygenius/atmos/exceptions.rb +13 -0
- data/lib/simplygenius/atmos/generator.rb +232 -0
- data/lib/simplygenius/atmos/ipc.rb +136 -0
- data/lib/simplygenius/atmos/ipc_actions/notify.rb +31 -0
- data/lib/simplygenius/atmos/ipc_actions/ping.rb +23 -0
- data/lib/simplygenius/atmos/logging.rb +164 -0
- data/lib/simplygenius/atmos/otp.rb +62 -0
- data/lib/simplygenius/atmos/plugin.rb +27 -0
- data/lib/simplygenius/atmos/plugin_manager.rb +120 -0
- data/lib/simplygenius/atmos/plugins/output_filter.rb +29 -0
- data/lib/simplygenius/atmos/plugins/prompt_notify.rb +21 -0
- data/lib/simplygenius/atmos/provider_factory.rb +23 -0
- data/lib/simplygenius/atmos/providers/aws/account_manager.rb +83 -0
- data/lib/simplygenius/atmos/providers/aws/auth_manager.rb +220 -0
- data/lib/simplygenius/atmos/providers/aws/container_manager.rb +118 -0
- data/lib/simplygenius/atmos/providers/aws/provider.rb +53 -0
- data/lib/simplygenius/atmos/providers/aws/s3_secret_manager.rb +51 -0
- data/lib/simplygenius/atmos/providers/aws/user_manager.rb +213 -0
- data/lib/simplygenius/atmos/settings_hash.rb +93 -0
- data/lib/simplygenius/atmos/source_path.rb +186 -0
- data/lib/simplygenius/atmos/template.rb +117 -0
- data/lib/simplygenius/atmos/terraform_executor.rb +297 -0
- data/lib/simplygenius/atmos/ui.rb +173 -0
- data/lib/simplygenius/atmos/utils.rb +54 -0
- data/lib/simplygenius/atmos/version.rb +5 -0
- data/templates/new/config/atmos.yml +21 -13
- data/templates/new/config/atmos/recipes.yml +16 -0
- data/templates/new/config/atmos/runtime.yml +9 -0
- metadata +46 -40
- data/lib/atmos/cli.rb +0 -105
- data/lib/atmos/commands/account.rb +0 -65
- data/lib/atmos/commands/apply.rb +0 -20
- data/lib/atmos/commands/auth_exec.rb +0 -29
- data/lib/atmos/commands/base_command.rb +0 -12
- data/lib/atmos/commands/bootstrap.rb +0 -72
- data/lib/atmos/commands/container.rb +0 -58
- data/lib/atmos/commands/destroy.rb +0 -18
- data/lib/atmos/commands/generate.rb +0 -90
- data/lib/atmos/commands/init.rb +0 -18
- data/lib/atmos/commands/new.rb +0 -18
- data/lib/atmos/commands/otp.rb +0 -54
- data/lib/atmos/commands/plan.rb +0 -20
- data/lib/atmos/commands/secret.rb +0 -87
- data/lib/atmos/commands/terraform.rb +0 -52
- data/lib/atmos/commands/user.rb +0 -74
- data/lib/atmos/config.rb +0 -208
- data/lib/atmos/exceptions.rb +0 -9
- data/lib/atmos/generator.rb +0 -199
- data/lib/atmos/generator_factory.rb +0 -93
- data/lib/atmos/ipc.rb +0 -132
- data/lib/atmos/ipc_actions/notify.rb +0 -27
- data/lib/atmos/ipc_actions/ping.rb +0 -19
- data/lib/atmos/logging.rb +0 -160
- data/lib/atmos/otp.rb +0 -61
- data/lib/atmos/provider_factory.rb +0 -19
- data/lib/atmos/providers/aws/account_manager.rb +0 -82
- data/lib/atmos/providers/aws/auth_manager.rb +0 -208
- data/lib/atmos/providers/aws/container_manager.rb +0 -116
- data/lib/atmos/providers/aws/provider.rb +0 -51
- data/lib/atmos/providers/aws/s3_secret_manager.rb +0 -49
- data/lib/atmos/providers/aws/user_manager.rb +0 -211
- data/lib/atmos/settings_hash.rb +0 -90
- data/lib/atmos/terraform_executor.rb +0 -267
- data/lib/atmos/ui.rb +0 -159
- data/lib/atmos/utils.rb +0 -50
- data/lib/atmos/version.rb +0 -3
@@ -0,0 +1,136 @@
|
|
1
|
+
require_relative '../atmos'
|
2
|
+
require 'fileutils'
|
3
|
+
require 'hashie'
|
4
|
+
|
5
|
+
module SimplyGenius
|
6
|
+
module Atmos
|
7
|
+
|
8
|
+
class Ipc
|
9
|
+
include GemLogger::LoggerSupport
|
10
|
+
|
11
|
+
def initialize(sock_dir=Dir.tmpdir)
|
12
|
+
@sock_dir = sock_dir
|
13
|
+
end
|
14
|
+
|
15
|
+
def listen(&block)
|
16
|
+
raise "Already listening" if @server
|
17
|
+
|
18
|
+
begin
|
19
|
+
@socket_path = File.join(@sock_dir, 'atmos-ipc')
|
20
|
+
FileUtils.rm_f(@socket_path)
|
21
|
+
@server = UNIXServer.open(@socket_path)
|
22
|
+
rescue ArgumentError => e
|
23
|
+
if e.message =~ /too long unix socket path/ && @sock_dir != Dir.tmpdir
|
24
|
+
logger.warn("Using tmp for ipc socket as path too long: #{@socket_path}")
|
25
|
+
@sock_dir = Dir.tmpdir
|
26
|
+
retry
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
begin
|
31
|
+
thread = Thread.new { run }
|
32
|
+
block.call(@socket_path)
|
33
|
+
ensure
|
34
|
+
@server.close
|
35
|
+
FileUtils.rm_f(@socket_path)
|
36
|
+
@server = nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def generate_client_script
|
41
|
+
script_file = File.join(@sock_dir, 'atmos_ipc.rb')
|
42
|
+
File.write(script_file, <<~EOF
|
43
|
+
#!/usr/bin/env ruby
|
44
|
+
require 'socket'
|
45
|
+
UNIXSocket.open('#{@socket_path}') {|c| c.puts(ARGV[0] || $stdin.read); puts c.gets }
|
46
|
+
EOF
|
47
|
+
)
|
48
|
+
FileUtils.chmod('+x', script_file)
|
49
|
+
return script_file
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def run
|
55
|
+
logger.debug("Starting ipc thread")
|
56
|
+
begin
|
57
|
+
while @server && sock = @server.accept
|
58
|
+
logger.debug("An ipc client connected")
|
59
|
+
line = sock.gets
|
60
|
+
logger.debug("Got ipc message: #{line.inspect}")
|
61
|
+
response = {}
|
62
|
+
|
63
|
+
begin
|
64
|
+
msg = JSON.parse(line)
|
65
|
+
msg = Hashie.symbolize_keys(msg)
|
66
|
+
|
67
|
+
# enabled by default if enabled is not set (e.g. from provisioner local-exec)
|
68
|
+
enabled = msg[:enabled].nil? ? true : ["true", "1"].include?(msg[:enabled].to_s)
|
69
|
+
|
70
|
+
if enabled
|
71
|
+
logger.debug("Dispatching IPC action")
|
72
|
+
response = dispatch(msg)
|
73
|
+
else
|
74
|
+
response[:message] = "IPC action is not enabled"
|
75
|
+
logger.debug(response[:error])
|
76
|
+
end
|
77
|
+
rescue => e
|
78
|
+
logger.log_exception(e, "Failed to parse ipc message")
|
79
|
+
response[:error] = "Failed to parse ipc message #{e.message}"
|
80
|
+
end
|
81
|
+
|
82
|
+
respond(sock, response)
|
83
|
+
sock.close
|
84
|
+
end
|
85
|
+
rescue IOError, EOFError, Errno::EBADF
|
86
|
+
nil
|
87
|
+
rescue Exception => e
|
88
|
+
logger.log_exception(e, "Ipc failure")
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def close
|
93
|
+
@server.close if @server rescue nil
|
94
|
+
end
|
95
|
+
|
96
|
+
def load_action(name)
|
97
|
+
action = nil
|
98
|
+
logger.debug("Loading ipc action: #{name}")
|
99
|
+
begin
|
100
|
+
require "simplygenius/atmos/ipc_actions/#{name}"
|
101
|
+
action = "SimplyGenius::Atmos::IpcActions::#{name.camelize}".constantize
|
102
|
+
logger.debug("Loaded ipc action #{name}")
|
103
|
+
rescue LoadError, NameError => e
|
104
|
+
logger.log_exception(e, "Failed to load ipc action")
|
105
|
+
end
|
106
|
+
return action
|
107
|
+
end
|
108
|
+
|
109
|
+
def dispatch(msg)
|
110
|
+
response = {}
|
111
|
+
action = load_action(msg[:action])
|
112
|
+
if action.nil?
|
113
|
+
response[:error] = "Unsupported ipc action: #{msg.to_hash.inspect}"
|
114
|
+
logger.warn(response[:error])
|
115
|
+
else
|
116
|
+
begin
|
117
|
+
response = action.new().execute(**msg)
|
118
|
+
rescue => e
|
119
|
+
response[:error] = "Failure while executing ipc action: #{e.message}"
|
120
|
+
logger.log_exception(e, "Failure while executing ipc action")
|
121
|
+
end
|
122
|
+
end
|
123
|
+
return response
|
124
|
+
end
|
125
|
+
|
126
|
+
def respond(sock, response)
|
127
|
+
msg = JSON.generate(response)
|
128
|
+
logger.debug("Sending ipc response: #{msg.inspect}")
|
129
|
+
sock.puts(msg)
|
130
|
+
sock.flush
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
end
|
136
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require_relative '../../atmos'
|
2
|
+
require_relative '../../atmos/ui'
|
3
|
+
|
4
|
+
module SimplyGenius
|
5
|
+
module Atmos
|
6
|
+
module IpcActions
|
7
|
+
|
8
|
+
class Notify
|
9
|
+
include GemLogger::LoggerSupport
|
10
|
+
include UI
|
11
|
+
|
12
|
+
def initialize()
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(**opts)
|
16
|
+
|
17
|
+
result = {
|
18
|
+
'stdout' => '',
|
19
|
+
'success' => ''
|
20
|
+
}
|
21
|
+
|
22
|
+
return result if Atmos.config["ipc.notify.disable"].to_s == "true"
|
23
|
+
return notify(**opts)
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require_relative '../../atmos'
|
2
|
+
require 'open3'
|
3
|
+
require 'os'
|
4
|
+
|
5
|
+
module SimplyGenius
|
6
|
+
module Atmos
|
7
|
+
module IpcActions
|
8
|
+
|
9
|
+
class Ping
|
10
|
+
include GemLogger::LoggerSupport
|
11
|
+
|
12
|
+
def initialize()
|
13
|
+
end
|
14
|
+
|
15
|
+
def execute(**opts)
|
16
|
+
return opts.merge(action: 'pong')
|
17
|
+
end
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,164 @@
|
|
1
|
+
require 'logging'
|
2
|
+
require 'gem_logger'
|
3
|
+
require 'rainbow'
|
4
|
+
require 'delegate'
|
5
|
+
|
6
|
+
module SimplyGenius
|
7
|
+
module Atmos
|
8
|
+
|
9
|
+
module Logging
|
10
|
+
|
11
|
+
module GemLoggerConcern
|
12
|
+
extend ActiveSupport::Concern
|
13
|
+
|
14
|
+
def logger
|
15
|
+
::Logging.logger[self.class]
|
16
|
+
end
|
17
|
+
|
18
|
+
module ClassMethods
|
19
|
+
def logger
|
20
|
+
::Logging.logger[self]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class CaptureStream < SimpleDelegator
|
26
|
+
|
27
|
+
def initialize(logger_name, appender, stream, color=nil)
|
28
|
+
super(stream)
|
29
|
+
@color = stream.tty? && color ? color : nil
|
30
|
+
@logger = ::Logging.logger[logger_name]
|
31
|
+
@logger.appenders = [appender]
|
32
|
+
@logger.additive = false
|
33
|
+
end
|
34
|
+
|
35
|
+
def strip_color(str)
|
36
|
+
str.gsub(/\e\[\d+m/, '')
|
37
|
+
end
|
38
|
+
|
39
|
+
def write(data)
|
40
|
+
@logger.info(strip_color(data))
|
41
|
+
if @color
|
42
|
+
count = 0
|
43
|
+
d = data.lines.each do |l|
|
44
|
+
cl = Kernel.send(:Rainbow, l).send(@color)
|
45
|
+
count += super(cl)
|
46
|
+
end
|
47
|
+
return count
|
48
|
+
else
|
49
|
+
return super(data)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.init_logger
|
55
|
+
return if @initialized
|
56
|
+
@initialized = true
|
57
|
+
|
58
|
+
::Logging.format_as :inspect
|
59
|
+
::Logging.backtrace true
|
60
|
+
|
61
|
+
::Logging.color_scheme(
|
62
|
+
'bright',
|
63
|
+
lines: {
|
64
|
+
debug: :green,
|
65
|
+
info: :default,
|
66
|
+
warn: :yellow,
|
67
|
+
error: :red,
|
68
|
+
fatal: [:white, :on_red]
|
69
|
+
},
|
70
|
+
date: :blue,
|
71
|
+
logger: :cyan,
|
72
|
+
message: :magenta
|
73
|
+
)
|
74
|
+
|
75
|
+
::Logging.logger.root.level = :info
|
76
|
+
GemLogger.configure do |config|
|
77
|
+
config.default_logger = ::Logging.logger.root
|
78
|
+
config.logger_concern = Logging::GemLoggerConcern
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
def self.testing
|
84
|
+
@t
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.testing=(t)
|
88
|
+
@t = t
|
89
|
+
end
|
90
|
+
|
91
|
+
def self.sio
|
92
|
+
::Logging.logger.root.appenders.find {|a| a.name == 'sio' }
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.contents
|
96
|
+
sio.try(:sio).try(:to_s)
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.clear
|
100
|
+
sio.try(:clear)
|
101
|
+
end
|
102
|
+
|
103
|
+
def self.setup_logging(debug, color, logfile)
|
104
|
+
init_logger
|
105
|
+
|
106
|
+
::Logging.logger.root.level = debug ? :debug : :info
|
107
|
+
appenders = []
|
108
|
+
detail_pattern = '[%d] %-5l %c{2} %m\n'
|
109
|
+
plain_pattern = '%m\n'
|
110
|
+
|
111
|
+
pattern_options = {
|
112
|
+
pattern: plain_pattern
|
113
|
+
}
|
114
|
+
if color
|
115
|
+
pattern_options[:color_scheme] = 'bright'
|
116
|
+
end
|
117
|
+
|
118
|
+
if self.testing
|
119
|
+
|
120
|
+
appender = ::Logging.appenders.string_io(
|
121
|
+
'sio',
|
122
|
+
layout: ::Logging.layouts.pattern(pattern_options)
|
123
|
+
)
|
124
|
+
appenders << appender
|
125
|
+
|
126
|
+
else
|
127
|
+
|
128
|
+
appender = ::Logging.appenders.stdout(
|
129
|
+
'stdout',
|
130
|
+
layout: ::Logging.layouts.pattern(pattern_options)
|
131
|
+
)
|
132
|
+
appenders << appender
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
# Do this after setting up stdout appender so we don't duplicate output
|
137
|
+
# to stdout with our capture
|
138
|
+
if logfile.present?
|
139
|
+
|
140
|
+
appender = ::Logging.appenders.file(
|
141
|
+
logfile,
|
142
|
+
truncate: true,
|
143
|
+
layout: ::Logging.layouts.pattern(pattern: detail_pattern)
|
144
|
+
)
|
145
|
+
appenders << appender
|
146
|
+
|
147
|
+
if ! $stdout.is_a? CaptureStream
|
148
|
+
$stdout = CaptureStream.new("stdout", appender, $stdout)
|
149
|
+
$stderr = CaptureStream.new("stderr", appender, $stderr, :red)
|
150
|
+
silence_warnings {
|
151
|
+
Object.const_set(:STDOUT, $stdout)
|
152
|
+
Object.const_set(:STDERR, $stderr)
|
153
|
+
}
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
|
158
|
+
::Logging.logger.root.appenders = appenders
|
159
|
+
end
|
160
|
+
|
161
|
+
end
|
162
|
+
|
163
|
+
end
|
164
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative '../atmos'
|
2
|
+
require 'singleton'
|
3
|
+
require 'rotp'
|
4
|
+
|
5
|
+
module SimplyGenius
|
6
|
+
module Atmos
|
7
|
+
|
8
|
+
class Otp
|
9
|
+
include Singleton
|
10
|
+
include GemLogger::LoggerSupport
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@secret_file = Atmos.config["otp.secret_file"] || "~/.atmos.yml"
|
14
|
+
@secret_file = File.expand_path(@secret_file)
|
15
|
+
yml_hash = YAML.load_file(@secret_file) rescue Hash.new
|
16
|
+
@secret_store = SettingsHash.new(yml_hash)
|
17
|
+
@secret_store[Atmos.config[:org]] ||= {}
|
18
|
+
@secret_store[Atmos.config[:org]][:otp] ||= {}
|
19
|
+
@scoped_secret_store = @secret_store[Atmos.config[:org]][:otp]
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(name, secret)
|
23
|
+
old = @scoped_secret_store[name]
|
24
|
+
logger.info "Replacing OTP secret #{name}=#{old}" if old
|
25
|
+
@scoped_secret_store[name] = secret
|
26
|
+
end
|
27
|
+
|
28
|
+
def remove(name)
|
29
|
+
old = @scoped_secret_store.delete(name)
|
30
|
+
@otp.try(:delete, name)
|
31
|
+
logger.info "Removed OTP secret #{name}=#{old}" if old
|
32
|
+
end
|
33
|
+
|
34
|
+
def save
|
35
|
+
File.write(@secret_file, YAML.dump(@secret_store.to_hash))
|
36
|
+
File.chmod(0600, @secret_file)
|
37
|
+
end
|
38
|
+
|
39
|
+
def generate(name)
|
40
|
+
otp(name).try(:now)
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def otp(name)
|
46
|
+
@otp ||= {}
|
47
|
+
@otp[name] ||= begin
|
48
|
+
secret = @scoped_secret_store[name]
|
49
|
+
totp = nil
|
50
|
+
if secret
|
51
|
+
totp = ROTP::TOTP.new(secret)
|
52
|
+
else
|
53
|
+
logger.debug "OTP secret does not exist for '#{name}'"
|
54
|
+
end
|
55
|
+
totp
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require_relative '../atmos'
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
|
4
|
+
Dir.glob(File.join(File.join(__dir__, 'plugins'), '*.rb')) do |f|
|
5
|
+
require_relative "plugins/#{File.basename(f).sub(/\.rb$/, "")}"
|
6
|
+
end
|
7
|
+
|
8
|
+
module SimplyGenius
|
9
|
+
module Atmos
|
10
|
+
|
11
|
+
class Plugin
|
12
|
+
include GemLogger::LoggerSupport
|
13
|
+
|
14
|
+
attr_reader :config
|
15
|
+
|
16
|
+
def initialize(config)
|
17
|
+
@config = config
|
18
|
+
end
|
19
|
+
|
20
|
+
def register_output_filter(type, clazz)
|
21
|
+
Atmos.config.plugin_manager.register_output_filter(type, clazz)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|