simplygenius-atmos 0.7.1 → 0.8.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,116 +0,0 @@
|
|
1
|
-
require_relative '../../../atmos'
|
2
|
-
require 'aws-sdk-ecs'
|
3
|
-
require 'aws-sdk-ecr'
|
4
|
-
require 'open3'
|
5
|
-
|
6
|
-
module Atmos
|
7
|
-
module Providers
|
8
|
-
module Aws
|
9
|
-
|
10
|
-
class ContainerManager
|
11
|
-
include GemLogger::LoggerSupport
|
12
|
-
|
13
|
-
def initialize(provider)
|
14
|
-
@provider = provider
|
15
|
-
end
|
16
|
-
|
17
|
-
def push(ecs_name, local_image,
|
18
|
-
ecr_repo: ecs_name, revision: nil)
|
19
|
-
|
20
|
-
revision = Time.now.strftime('%Y%m%d%H%M%S') unless revision.present?
|
21
|
-
result = {}
|
22
|
-
|
23
|
-
ecr = ::Aws::ECR::Client.new
|
24
|
-
resp = nil
|
25
|
-
|
26
|
-
resp = ecr.get_authorization_token
|
27
|
-
auth_data = resp.authorization_data.first
|
28
|
-
token = auth_data.authorization_token
|
29
|
-
endpoint = auth_data.proxy_endpoint
|
30
|
-
user, password = Base64.decode64(token).split(':')
|
31
|
-
|
32
|
-
# docker login into the ECR repo for the current account so that we can pull/push to it
|
33
|
-
run("docker", "login", "-u", user, "-p", password, endpoint)#, stdin_data: token)
|
34
|
-
|
35
|
-
image="#{ecs_name}:latest"
|
36
|
-
ecs_image="#{endpoint.sub(/https?:\/\//, '')}/#{ecr_repo}"
|
37
|
-
|
38
|
-
tags = ['latest', revision]
|
39
|
-
logger.info "Tagging local image '#{local_image}' with #{tags}"
|
40
|
-
tags.each {|t| run("docker", "tag", local_image, "#{ecs_image}:#{t}") }
|
41
|
-
|
42
|
-
logger.info "Pushing tagged image to ECR repo"
|
43
|
-
tags.each {|t| run("docker", "push", "#{ecs_image}:#{t}") }
|
44
|
-
|
45
|
-
result[:remote_image] = "#{ecs_image}:#{revision}"
|
46
|
-
return result
|
47
|
-
end
|
48
|
-
|
49
|
-
def deploy_task(task, remote_image)
|
50
|
-
result = {}
|
51
|
-
|
52
|
-
ecs = ::Aws::ECS::Client.new
|
53
|
-
resp = nil
|
54
|
-
|
55
|
-
resp = ecs.list_task_definitions(family_prefix: task, sort: 'DESC')
|
56
|
-
latest_defn_arn = resp.task_definition_arns.first
|
57
|
-
|
58
|
-
logger.info "Latest task definition: #{latest_defn_arn}"
|
59
|
-
|
60
|
-
resp = ecs.describe_task_definition(task_definition: latest_defn_arn)
|
61
|
-
latest_defn = resp.task_definition
|
62
|
-
|
63
|
-
new_defn = latest_defn.to_h
|
64
|
-
[:revision, :status, :task_definition_arn,
|
65
|
-
:requires_attributes, :compatibilities].each do |attr|
|
66
|
-
new_defn.delete(attr)
|
67
|
-
end
|
68
|
-
new_defn[:container_definitions].each {|c| c[:image] = remote_image}
|
69
|
-
|
70
|
-
resp = ecs.register_task_definition(**new_defn)
|
71
|
-
result[:task_definition] = resp.task_definition.task_definition_arn
|
72
|
-
|
73
|
-
logger.info "Updated task=#{task} to #{result[:task_definition]} with image #{remote_image}"
|
74
|
-
|
75
|
-
return result
|
76
|
-
end
|
77
|
-
|
78
|
-
def deploy_service(cluster, service, remote_image)
|
79
|
-
result = {}
|
80
|
-
|
81
|
-
ecs = ::Aws::ECS::Client.new
|
82
|
-
resp = nil
|
83
|
-
|
84
|
-
# Get current task definition name from service
|
85
|
-
resp = ecs.describe_services(cluster: cluster, services: [service])
|
86
|
-
current_defn_arn = resp.services.first.task_definition
|
87
|
-
defn_name = current_defn_arn.split("/").last.split(":").first
|
88
|
-
|
89
|
-
logger.info "Current task definition (name=#{defn_name}): #{current_defn_arn}"
|
90
|
-
result = deploy_task(defn_name, remote_image)
|
91
|
-
new_taskdef = result[:task_definition]
|
92
|
-
|
93
|
-
logger.info "Updating service with new task definition: #{new_taskdef}"
|
94
|
-
|
95
|
-
resp = ecs.update_service(cluster: cluster, service: service, task_definition: new_taskdef)
|
96
|
-
|
97
|
-
logger.info "Updated service=#{service} on cluster=#{cluster} to #{new_taskdef} with image #{remote_image}"
|
98
|
-
|
99
|
-
return result
|
100
|
-
end
|
101
|
-
|
102
|
-
private
|
103
|
-
|
104
|
-
def run(*args, **opts)
|
105
|
-
logger.debug("Running: #{args}")
|
106
|
-
stdout, status = Open3.capture2e(ENV, *args, **opts)
|
107
|
-
logger.debug(stdout)
|
108
|
-
raise "Failed to run #{args}: #{stdout}" unless status.success?
|
109
|
-
return stdout
|
110
|
-
end
|
111
|
-
|
112
|
-
end
|
113
|
-
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,51 +0,0 @@
|
|
1
|
-
require_relative '../../../atmos'
|
2
|
-
|
3
|
-
Dir.glob(File.join(__dir__, '*.rb')) do |f|
|
4
|
-
require_relative "#{File.basename(f).sub(/\.rb$/, "")}"
|
5
|
-
end
|
6
|
-
|
7
|
-
module Atmos
|
8
|
-
module Providers
|
9
|
-
module Aws
|
10
|
-
|
11
|
-
class Provider
|
12
|
-
include GemLogger::LoggerSupport
|
13
|
-
|
14
|
-
def initialize(name)
|
15
|
-
@name = name
|
16
|
-
end
|
17
|
-
|
18
|
-
def auth_manager
|
19
|
-
@auth_manager ||= begin
|
20
|
-
Atmos::Providers::Aws::AuthManager.new(self)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def user_manager
|
25
|
-
@user_manager ||= begin
|
26
|
-
Atmos::Providers::Aws::UserManager.new(self)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def account_manager
|
31
|
-
@account_manager ||= begin
|
32
|
-
Atmos::Providers::Aws::AccountManager.new(self)
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def secret_manager
|
37
|
-
@secret_manager ||= begin
|
38
|
-
Atmos::Providers::Aws::S3SecretManager.new(self)
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
def container_manager
|
43
|
-
@container_manager ||= begin
|
44
|
-
Atmos::Providers::Aws::ContainerManager.new(self)
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
@@ -1,49 +0,0 @@
|
|
1
|
-
require_relative '../../../atmos'
|
2
|
-
require 'aws-sdk-s3'
|
3
|
-
|
4
|
-
module Atmos
|
5
|
-
module Providers
|
6
|
-
module Aws
|
7
|
-
|
8
|
-
class S3SecretManager
|
9
|
-
include GemLogger::LoggerSupport
|
10
|
-
|
11
|
-
def initialize(provider)
|
12
|
-
@provider = provider
|
13
|
-
logger.debug("Secrets config is: #{Atmos.config[:secret]}")
|
14
|
-
@bucket_name = Atmos.config[:secret][:bucket]
|
15
|
-
@encrypt = Atmos.config[:secret][:encrypt]
|
16
|
-
end
|
17
|
-
|
18
|
-
def set(key, value)
|
19
|
-
opts = {}
|
20
|
-
opts[:server_side_encryption] = "AES256" if @encrypt
|
21
|
-
bucket.object(key).put(body: value, **opts)
|
22
|
-
end
|
23
|
-
|
24
|
-
def get(key)
|
25
|
-
bucket.object(key).get.body.read
|
26
|
-
end
|
27
|
-
|
28
|
-
def delete(key)
|
29
|
-
bucket.object(key).delete
|
30
|
-
end
|
31
|
-
|
32
|
-
def to_h
|
33
|
-
Hash[bucket.objects.collect {|o|
|
34
|
-
[o.key, o.get.body.read]
|
35
|
-
}]
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def bucket
|
41
|
-
raise ArgumentError.new("The s3 secret bucket is not set") unless @bucket_name
|
42
|
-
@bucket ||= ::Aws::S3::Bucket.new(@bucket_name)
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
@@ -1,211 +0,0 @@
|
|
1
|
-
require_relative '../../../atmos'
|
2
|
-
require_relative '../../../atmos/otp'
|
3
|
-
require 'aws-sdk-iam'
|
4
|
-
require 'securerandom'
|
5
|
-
|
6
|
-
module Atmos
|
7
|
-
module Providers
|
8
|
-
module Aws
|
9
|
-
|
10
|
-
class UserManager
|
11
|
-
include GemLogger::LoggerSupport
|
12
|
-
include FileUtils
|
13
|
-
|
14
|
-
def initialize(provider)
|
15
|
-
@provider = provider
|
16
|
-
end
|
17
|
-
|
18
|
-
def create_user(user_name)
|
19
|
-
result = {}
|
20
|
-
client = ::Aws::IAM::Client.new
|
21
|
-
resource = ::Aws::IAM::Resource.new
|
22
|
-
|
23
|
-
user = resource.user(user_name)
|
24
|
-
|
25
|
-
if user.exists?
|
26
|
-
logger.info "User '#{user_name}' already exists"
|
27
|
-
else
|
28
|
-
logger.info "Creating new user '#{user_name}'"
|
29
|
-
user = resource.create_user(user_name: user_name)
|
30
|
-
client.wait_until(:user_exists, user_name: user_name)
|
31
|
-
logger.debug "User created, user_name=#{user_name}"
|
32
|
-
end
|
33
|
-
|
34
|
-
result[:user_name] = user_name
|
35
|
-
|
36
|
-
return result
|
37
|
-
end
|
38
|
-
|
39
|
-
def set_groups(user_name, groups, force: false)
|
40
|
-
result = {}
|
41
|
-
resource = ::Aws::IAM::Resource.new
|
42
|
-
|
43
|
-
user = resource.user(user_name)
|
44
|
-
|
45
|
-
existing_groups = user.groups.collect(&:name)
|
46
|
-
groups_to_add = groups - existing_groups
|
47
|
-
groups_to_remove = existing_groups - groups
|
48
|
-
|
49
|
-
result[:groups] = existing_groups
|
50
|
-
|
51
|
-
groups_to_add.each do |group|
|
52
|
-
logger.debug "Adding group: #{group}"
|
53
|
-
user.add_group(group_name: group)
|
54
|
-
result[:groups] << group
|
55
|
-
end
|
56
|
-
|
57
|
-
if force
|
58
|
-
groups_to_remove.each do |group|
|
59
|
-
logger.debug "Removing group: #{group}"
|
60
|
-
user.remove_group(group_name: group)
|
61
|
-
result[:groups].delete(group)
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
logger.info "User associated with groups=#{result[:groups]}"
|
66
|
-
|
67
|
-
return result
|
68
|
-
end
|
69
|
-
|
70
|
-
def enable_login(user_name, force: false)
|
71
|
-
result = {}
|
72
|
-
resource = ::Aws::IAM::Resource.new
|
73
|
-
|
74
|
-
user = resource.user(user_name)
|
75
|
-
|
76
|
-
password = ""
|
77
|
-
classes = [/[a-z]/, /[A-Z]/, /[0-9]/, /[!@#$%^&*()_+\-=\[\]{}|']/]
|
78
|
-
while ! classes.all? {|c| password =~ c }
|
79
|
-
password = SecureRandom.base64(15)
|
80
|
-
end
|
81
|
-
|
82
|
-
exists = false
|
83
|
-
begin
|
84
|
-
user.login_profile.create_date
|
85
|
-
exists = true
|
86
|
-
rescue ::Aws::IAM::Errors::NoSuchEntity
|
87
|
-
exists = false
|
88
|
-
end
|
89
|
-
|
90
|
-
if exists
|
91
|
-
logger.info "User login already exists"
|
92
|
-
if force
|
93
|
-
user.login_profile.update(password: password, password_reset_required: true)
|
94
|
-
result[:password] = password
|
95
|
-
logger.info "Updated user login with password=#{password}"
|
96
|
-
end
|
97
|
-
else
|
98
|
-
user.create_login_profile(password: password, password_reset_required: true)
|
99
|
-
result[:password] = password
|
100
|
-
logger.info "User login enabled with password=#{password}"
|
101
|
-
end
|
102
|
-
|
103
|
-
return result
|
104
|
-
end
|
105
|
-
|
106
|
-
def enable_mfa(user_name, force: false)
|
107
|
-
result = {}
|
108
|
-
client = ::Aws::IAM::Client.new
|
109
|
-
resource = ::Aws::IAM::Resource.new
|
110
|
-
|
111
|
-
user = resource.user(user_name)
|
112
|
-
|
113
|
-
if user.mfa_devices.first
|
114
|
-
logger.info "User mfa devices already exist"
|
115
|
-
if force
|
116
|
-
logger.info "Deleting old mfa devices"
|
117
|
-
user.mfa_devices.each do |dev|
|
118
|
-
dev.disassociate
|
119
|
-
client.delete_virtual_mfa_device(serial_number: dev.serial_number)
|
120
|
-
Atmos::Otp.instance.remove(user_name)
|
121
|
-
end
|
122
|
-
else
|
123
|
-
return result
|
124
|
-
end
|
125
|
-
end
|
126
|
-
|
127
|
-
resp = client.create_virtual_mfa_device(
|
128
|
-
virtual_mfa_device_name: user_name
|
129
|
-
)
|
130
|
-
|
131
|
-
serial = resp.virtual_mfa_device.serial_number
|
132
|
-
seed = resp.virtual_mfa_device.base_32_string_seed
|
133
|
-
|
134
|
-
Atmos::Otp.instance.add(user_name, seed)
|
135
|
-
code1 = Atmos::Otp.instance.generate(user_name)
|
136
|
-
interval = (30 - (Time.now.to_i % 30)) + 1
|
137
|
-
logger.info "Waiting for #{interval}s to generate second otp key for enablement"
|
138
|
-
sleep interval
|
139
|
-
code2 = Atmos::Otp.instance.generate(user_name)
|
140
|
-
raise "MFA codes should not be the same" if code1 == code2
|
141
|
-
|
142
|
-
resp = client.enable_mfa_device({
|
143
|
-
user_name: user_name,
|
144
|
-
serial_number: serial,
|
145
|
-
authentication_code_1: code1,
|
146
|
-
authentication_code_2: code2,
|
147
|
-
})
|
148
|
-
|
149
|
-
result[:mfa_secret] = seed
|
150
|
-
|
151
|
-
return result
|
152
|
-
end
|
153
|
-
|
154
|
-
def enable_access_keys(user_name, force: false)
|
155
|
-
result = {}
|
156
|
-
resource = ::Aws::IAM::Resource.new
|
157
|
-
|
158
|
-
user = resource.user(user_name)
|
159
|
-
|
160
|
-
if user.access_keys.first
|
161
|
-
logger.info "User access keys already exist"
|
162
|
-
if force
|
163
|
-
logger.info "Deleting old access keys"
|
164
|
-
user.access_keys.each do |key|
|
165
|
-
key.delete
|
166
|
-
end
|
167
|
-
else
|
168
|
-
return result
|
169
|
-
end
|
170
|
-
end
|
171
|
-
|
172
|
-
# TODO: auto add to ~/.aws/credentials and config
|
173
|
-
key_pair = user.create_access_key_pair
|
174
|
-
result[:key] = key_pair.access_key_id
|
175
|
-
result[:secret] = key_pair.secret
|
176
|
-
logger.debug "User keys generated key=#{key_pair.access_key_id}, secret=#{key_pair.secret}"
|
177
|
-
|
178
|
-
return result
|
179
|
-
end
|
180
|
-
|
181
|
-
def set_public_key(user_name, public_key, force: false)
|
182
|
-
result = {}
|
183
|
-
client = ::Aws::IAM::Client.new
|
184
|
-
resource = ::Aws::IAM::Resource.new
|
185
|
-
|
186
|
-
user = resource.user(user_name)
|
187
|
-
keys = client.list_ssh_public_keys(user_name: user_name).ssh_public_keys
|
188
|
-
if keys.size > 0
|
189
|
-
logger.info "User ssh public keys already exist"
|
190
|
-
if force
|
191
|
-
logger.info "Deleting old ssh public keys"
|
192
|
-
keys.each do |key|
|
193
|
-
client.delete_ssh_public_key(user_name: user_name,
|
194
|
-
ssh_public_key_id: key.ssh_public_key_id)
|
195
|
-
end
|
196
|
-
else
|
197
|
-
return result
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
|
-
client.upload_ssh_public_key(user_name: user_name, ssh_public_key_body: public_key)
|
202
|
-
logger.debug "User public key assigned: #{public_key}"
|
203
|
-
|
204
|
-
return result
|
205
|
-
end
|
206
|
-
|
207
|
-
end
|
208
|
-
|
209
|
-
end
|
210
|
-
end
|
211
|
-
end
|
data/lib/atmos/settings_hash.rb
DELETED
@@ -1,90 +0,0 @@
|
|
1
|
-
require 'hashie'
|
2
|
-
|
3
|
-
module Atmos
|
4
|
-
|
5
|
-
class SettingsHash < Hashie::Mash
|
6
|
-
include GemLogger::LoggerSupport
|
7
|
-
include Hashie::Extensions::DeepMerge
|
8
|
-
include Hashie::Extensions::DeepFetch
|
9
|
-
disable_warnings
|
10
|
-
|
11
|
-
PATH_PATTERN = /[\.\[\]]/
|
12
|
-
|
13
|
-
def notation_get(key)
|
14
|
-
path = key.to_s.split(PATH_PATTERN).compact
|
15
|
-
path = path.collect {|p| p =~ /^\d+$/ ? p.to_i : p }
|
16
|
-
result = nil
|
17
|
-
|
18
|
-
begin
|
19
|
-
result = deep_fetch(*path)
|
20
|
-
rescue Hashie::Extensions::DeepFetch::UndefinedPathError => e
|
21
|
-
logger.debug("Settings missing value for key='#{key}'")
|
22
|
-
end
|
23
|
-
|
24
|
-
return result
|
25
|
-
end
|
26
|
-
|
27
|
-
def notation_put(key, value, additive: true)
|
28
|
-
path = key.to_s.split(PATH_PATTERN).compact
|
29
|
-
path = path.collect {|p| p =~ /^\d+$/ ? p.to_i : p }
|
30
|
-
current_level = self
|
31
|
-
path.each_with_index do |p, i|
|
32
|
-
|
33
|
-
if i == path.size - 1
|
34
|
-
if additive && current_level[p].is_a?(Array)
|
35
|
-
current_level[p] = current_level[p] | Array(value)
|
36
|
-
else
|
37
|
-
current_level[p] = value
|
38
|
-
end
|
39
|
-
else
|
40
|
-
if current_level[p].nil?
|
41
|
-
if path[i+1].is_a?(Integer)
|
42
|
-
current_level[p] = []
|
43
|
-
else
|
44
|
-
current_level[p] = {}
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
current_level = current_level[p]
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def self.add_config(yml_file, key, value, additive: true)
|
54
|
-
orig_config_with_comments = File.read(yml_file)
|
55
|
-
|
56
|
-
comment_places = {}
|
57
|
-
comment_lines = []
|
58
|
-
orig_config_with_comments.each_line do |line|
|
59
|
-
line.gsub!(/\s+$/, "\n")
|
60
|
-
if line =~ /^\s*(#.*)?$/
|
61
|
-
comment_lines << line
|
62
|
-
else
|
63
|
-
if comment_lines.present?
|
64
|
-
comment_places[line.chomp] = comment_lines
|
65
|
-
comment_lines = []
|
66
|
-
end
|
67
|
-
end
|
68
|
-
end
|
69
|
-
comment_places["<EOF>"] = comment_lines
|
70
|
-
|
71
|
-
orig_config = SettingsHash.new((YAML.load_file(yml_file) rescue {}))
|
72
|
-
orig_config.notation_put(key, value, additive: additive)
|
73
|
-
new_config_no_comments = YAML.dump(orig_config.to_hash)
|
74
|
-
new_config_no_comments.sub!(/\A---\n/, "")
|
75
|
-
|
76
|
-
new_yml = ""
|
77
|
-
new_config_no_comments.each_line do |line|
|
78
|
-
line.gsub!(/\s+$/, "\n")
|
79
|
-
cline = comment_places.keys.find {|k| line =~ /^#{k}/ }
|
80
|
-
comments = comment_places[cline]
|
81
|
-
comments.each {|comment| new_yml << comment } if comments
|
82
|
-
new_yml << line
|
83
|
-
end
|
84
|
-
comment_places["<EOF>"].each {|comment| new_yml << comment }
|
85
|
-
|
86
|
-
return new_yml
|
87
|
-
end
|
88
|
-
|
89
|
-
end
|
90
|
-
end
|