gclouder 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +104 -0
- data/bin/gclouder +7 -0
- data/lib/gclouder/config/arguments.rb +35 -0
- data/lib/gclouder/config/cli_args.rb +77 -0
- data/lib/gclouder/config/cluster.rb +66 -0
- data/lib/gclouder/config/defaults.rb +35 -0
- data/lib/gclouder/config/files/project.rb +24 -0
- data/lib/gclouder/config/project.rb +34 -0
- data/lib/gclouder/config/resource_representations.rb +31 -0
- data/lib/gclouder/config_loader.rb +25 -0
- data/lib/gclouder/config_section.rb +26 -0
- data/lib/gclouder/dependencies.rb +11 -0
- data/lib/gclouder/gcloud.rb +39 -0
- data/lib/gclouder/gsutil.rb +25 -0
- data/lib/gclouder/header.rb +9 -0
- data/lib/gclouder/helpers.rb +77 -0
- data/lib/gclouder/logging.rb +181 -0
- data/lib/gclouder/mappings/argument.rb +31 -0
- data/lib/gclouder/mappings/file.rb +31 -0
- data/lib/gclouder/mappings/property.rb +31 -0
- data/lib/gclouder/mappings/resource_representation.rb +31 -0
- data/lib/gclouder/monkey_patches/array.rb +19 -0
- data/lib/gclouder/monkey_patches/boolean.rb +12 -0
- data/lib/gclouder/monkey_patches/hash.rb +44 -0
- data/lib/gclouder/monkey_patches/ipaddr.rb +10 -0
- data/lib/gclouder/monkey_patches/string.rb +30 -0
- data/lib/gclouder/resource.rb +63 -0
- data/lib/gclouder/resource_cleaner.rb +58 -0
- data/lib/gclouder/resources/compute/addresses.rb +108 -0
- data/lib/gclouder/resources/compute/bgp-vpns.rb +220 -0
- data/lib/gclouder/resources/compute/disks.rb +99 -0
- data/lib/gclouder/resources/compute/firewall_rules.rb +82 -0
- data/lib/gclouder/resources/compute/instances.rb +147 -0
- data/lib/gclouder/resources/compute/networks/subnets.rb +104 -0
- data/lib/gclouder/resources/compute/networks.rb +110 -0
- data/lib/gclouder/resources/compute/project_info/ssh_keys.rb +171 -0
- data/lib/gclouder/resources/compute/routers.rb +83 -0
- data/lib/gclouder/resources/compute/vpns.rb +199 -0
- data/lib/gclouder/resources/container/clusters.rb +257 -0
- data/lib/gclouder/resources/container/node_pools.rb +193 -0
- data/lib/gclouder/resources/dns.rb +390 -0
- data/lib/gclouder/resources/logging/sinks.rb +98 -0
- data/lib/gclouder/resources/project/iam_policy_binding.rb +293 -0
- data/lib/gclouder/resources/project.rb +85 -0
- data/lib/gclouder/resources/project_id.rb +71 -0
- data/lib/gclouder/resources/pubsub/subscriptions.rb +100 -0
- data/lib/gclouder/resources/pubsub/topics.rb +95 -0
- data/lib/gclouder/resources/storagebuckets.rb +103 -0
- data/lib/gclouder/resources/validate/global.rb +27 -0
- data/lib/gclouder/resources/validate/local.rb +68 -0
- data/lib/gclouder/resources/validate/region.rb +28 -0
- data/lib/gclouder/resources/validate/remote.rb +78 -0
- data/lib/gclouder/resources.rb +148 -0
- data/lib/gclouder/shell.rb +71 -0
- data/lib/gclouder/version.rb +5 -0
- data/lib/gclouder.rb +278 -0
- metadata +102 -0
@@ -0,0 +1,181 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "stringio"
|
4
|
+
require "logger"
|
5
|
+
|
6
|
+
module GClouder
|
7
|
+
module Logging
|
8
|
+
class << self
|
9
|
+
attr_accessor :appenders
|
10
|
+
end
|
11
|
+
|
12
|
+
@@good ||= 0
|
13
|
+
@@bad ||= 0
|
14
|
+
@@add ||= 0
|
15
|
+
@@change ||= 0
|
16
|
+
@@remove ||= 0
|
17
|
+
@@warning ||= 0
|
18
|
+
|
19
|
+
def self.loggers
|
20
|
+
@loggers ||= setup
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.included(klass)
|
24
|
+
klass.extend Logging
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.setup
|
28
|
+
appenders.map do |appender|
|
29
|
+
appender[:appender].formatter = appender[:format]
|
30
|
+
appender[:appender].level = Logger::DEBUG
|
31
|
+
appender[:appender]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.log(message, level: :info, indent: 0, heading: false, title: false)
|
36
|
+
loggers.each do |log|
|
37
|
+
message = case message
|
38
|
+
when "" || nil
|
39
|
+
[ "" ]
|
40
|
+
when String
|
41
|
+
message.split("\n")
|
42
|
+
when Array
|
43
|
+
message
|
44
|
+
else
|
45
|
+
fatal "unknown message type: #{message.class}"
|
46
|
+
end
|
47
|
+
|
48
|
+
message = [ "", "" ] + message if title
|
49
|
+
message = [ "" ] + message if heading
|
50
|
+
|
51
|
+
if title
|
52
|
+
prefix = " " * 1
|
53
|
+
else
|
54
|
+
prefix = " " * indent
|
55
|
+
end
|
56
|
+
|
57
|
+
message.each { |line| log.send(level, prefix + line) }
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.appenders
|
62
|
+
@appenders ||= [Appenders.stdout, Appenders.file]
|
63
|
+
end
|
64
|
+
|
65
|
+
module Appenders
|
66
|
+
def self.stdout
|
67
|
+
{
|
68
|
+
appender: ::Logger.new(STDOUT),
|
69
|
+
format: proc { |_, _, _, message| "#{message}\n" }
|
70
|
+
}
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.file
|
74
|
+
{
|
75
|
+
appender: ::Logger.new(File.join(File.dirname(__FILE__), "../../log.txt")),
|
76
|
+
format: proc { |severity, datetime, _, message| "#{severity} - #{datetime}: #{message}\n" }
|
77
|
+
}
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.stringio(obj = StringIO.new)
|
81
|
+
{
|
82
|
+
appender: ::Logger.new(StringIO.new),
|
83
|
+
format: proc { |severity, datetime, _, message| "#{severity} - #{datetime}: #{message}\n" }
|
84
|
+
}
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def debug(message = "")
|
89
|
+
Logging.log message, level: :debug
|
90
|
+
end
|
91
|
+
|
92
|
+
def info(message = "", indent: 0, heading: false, title: false)
|
93
|
+
Logging.log message, level: :info, indent: indent, heading: heading, title: title
|
94
|
+
end
|
95
|
+
|
96
|
+
def warn(message = "", heading: false)
|
97
|
+
Logging.log message, level: :warn, heading: heading
|
98
|
+
end
|
99
|
+
|
100
|
+
def error(message = "", heading: false)
|
101
|
+
Logging.log message, level: :error, heading: heading
|
102
|
+
end
|
103
|
+
|
104
|
+
def fatal(message = "", status: 1, heading: false)
|
105
|
+
Logging.log "\n#{message}", level: :fatal, heading: heading
|
106
|
+
exit status
|
107
|
+
end
|
108
|
+
|
109
|
+
def resource_state(message, indent: 0, heading: false, level: :info)
|
110
|
+
Logging.log "#{' ' * indent}#{message}", level: level, heading: heading
|
111
|
+
end
|
112
|
+
|
113
|
+
def good(message, indent: 3, heading: false)
|
114
|
+
@@good += 1
|
115
|
+
resource_state("#{Symbols.tick} #{message}", indent: indent, heading: heading)
|
116
|
+
end
|
117
|
+
|
118
|
+
def bad(message, indent: 3, heading: false)
|
119
|
+
@@bad += 1
|
120
|
+
resource_state("#{Symbols.x} #{message}", indent: indent, heading: heading)
|
121
|
+
end
|
122
|
+
|
123
|
+
def add(message, indent: 3, heading: false)
|
124
|
+
@@add += 1
|
125
|
+
resource_state("#{Symbols.plus} #{message}", indent: indent, heading: heading)
|
126
|
+
end
|
127
|
+
|
128
|
+
def change(message, indent: 3, heading: false)
|
129
|
+
@@change += 1
|
130
|
+
resource_state("#{Symbols.o} #{message}", indent: indent, heading: heading)
|
131
|
+
end
|
132
|
+
|
133
|
+
def remove(message, indent: 3, heading: false)
|
134
|
+
@@remove += 1
|
135
|
+
resource_state("#{Symbols.minus} #{message}", indent: indent, heading: heading)
|
136
|
+
end
|
137
|
+
|
138
|
+
def warning(message, indent: 3, heading: false)
|
139
|
+
@@warning += 1
|
140
|
+
resource_state("#{Symbols.bang} #{message}", indent: indent, heading: heading)
|
141
|
+
end
|
142
|
+
|
143
|
+
module Symbols
|
144
|
+
def self.tick
|
145
|
+
"✓".green
|
146
|
+
end
|
147
|
+
|
148
|
+
def self.x
|
149
|
+
"✗".red
|
150
|
+
end
|
151
|
+
|
152
|
+
def self.plus
|
153
|
+
"+".blue
|
154
|
+
end
|
155
|
+
|
156
|
+
def self.o
|
157
|
+
"o".yellow
|
158
|
+
end
|
159
|
+
|
160
|
+
def self.minus
|
161
|
+
"-".red
|
162
|
+
end
|
163
|
+
|
164
|
+
def self.bang
|
165
|
+
"!".yellow
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
def self.report
|
170
|
+
Logging.log "\n\n [report]"
|
171
|
+
Logging.log " "
|
172
|
+
Logging.log " #{Symbols.tick} - #{@@good}"
|
173
|
+
Logging.log " #{Symbols.bang} - #{@@warning}"
|
174
|
+
Logging.log " #{Symbols.x} - #{@@bad}"
|
175
|
+
Logging.log " "
|
176
|
+
Logging.log " #{Symbols.plus} - #{@@add}"
|
177
|
+
Logging.log " #{Symbols.o} - #{@@change}"
|
178
|
+
Logging.log " #{Symbols.minus} - #{@@remove}"
|
179
|
+
end
|
180
|
+
end
|
181
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module GClouder
|
6
|
+
module Mappings
|
7
|
+
module Argument
|
8
|
+
include GClouder::Logging
|
9
|
+
|
10
|
+
def self.mappings
|
11
|
+
GClouder::ConfigLoader.load("../../assets/mappings/argument")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load
|
15
|
+
mappings
|
16
|
+
end
|
17
|
+
|
18
|
+
def mappings
|
19
|
+
Argument.mappings
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(klass)
|
23
|
+
klass.extend Argument
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.section(section)
|
27
|
+
GClouder::ConfigSection.find(section, mappings)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module GClouder
|
6
|
+
module Mappings
|
7
|
+
module File
|
8
|
+
include GClouder::Logging
|
9
|
+
|
10
|
+
def self.mappings
|
11
|
+
GClouder::ConfigLoader.load("../../assets/mappings/file")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load
|
15
|
+
mappings
|
16
|
+
end
|
17
|
+
|
18
|
+
def file
|
19
|
+
File.mappings
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(klass)
|
23
|
+
klass.extend File
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.section(section)
|
27
|
+
GClouder::ConfigSection.find(section, mappings)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module GClouder
|
6
|
+
module Mappings
|
7
|
+
module Property
|
8
|
+
include GClouder::Logging
|
9
|
+
|
10
|
+
def self.mappings
|
11
|
+
YAML.load_file(::File.join(::File.dirname(__FILE__), "../../../assets/mappings/property.yml"))
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load
|
15
|
+
mappings
|
16
|
+
end
|
17
|
+
|
18
|
+
def mappings
|
19
|
+
Property.mappings
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(klass)
|
23
|
+
klass.extend Property
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.section(section)
|
27
|
+
GClouder::ConfigSection.find(section, mappings)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "yaml"
|
4
|
+
|
5
|
+
module GClouder
|
6
|
+
module Mappings
|
7
|
+
module ResourceRepresentation
|
8
|
+
include GClouder::Logging
|
9
|
+
|
10
|
+
def self.mappings
|
11
|
+
GClouder::ConfigLoader.load("../../assets/resource_representations")
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.load
|
15
|
+
mappings
|
16
|
+
end
|
17
|
+
|
18
|
+
def resource_representation
|
19
|
+
ResourceRepresentation.mappings
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.included(klass)
|
23
|
+
klass.extend ResourceRepresentation
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.section(section)
|
27
|
+
GClouder::ConfigSection.find(section, mappings)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class Array
|
4
|
+
def clean
|
5
|
+
uniq.delete_if(&:nil?)
|
6
|
+
end
|
7
|
+
|
8
|
+
def to_snake_keys
|
9
|
+
each_with_index do |v, i|
|
10
|
+
self[i] = v.to_snake_keys if v.is_a?(Hash)
|
11
|
+
end
|
12
|
+
self
|
13
|
+
end
|
14
|
+
|
15
|
+
def fetch_with_default(key, name, default)
|
16
|
+
results = find { |e| e[key] == name }
|
17
|
+
results || default
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# sourced from: https://github.com/futurechimp/plissken/blob/master/lib/plissken/ext/hash/to_snake_keys.rb
|
5
|
+
def to_snake_keys(value = self)
|
6
|
+
case value
|
7
|
+
when Array
|
8
|
+
value.map { |v| to_snake_keys(v) }
|
9
|
+
when Hash
|
10
|
+
snake_hash(value)
|
11
|
+
else
|
12
|
+
value
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def snake_hash(value)
|
19
|
+
Hash[value.map { |k, v| [underscore_key(k), to_snake_keys(v)] }]
|
20
|
+
end
|
21
|
+
|
22
|
+
def underscore_key(k)
|
23
|
+
if k.is_a? Symbol
|
24
|
+
underscore(k.to_s)
|
25
|
+
elsif k.is_a? String
|
26
|
+
underscore(k)
|
27
|
+
else
|
28
|
+
k
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def underscore(string)
|
33
|
+
string.gsub(/::/, '/')
|
34
|
+
.gsub(/([A-Z]+)([A-Z][a-z])/, '\1_\2')
|
35
|
+
.gsub(/([a-z\d])([A-Z])/, '\1_\2')
|
36
|
+
.tr('-', '_')
|
37
|
+
.downcase
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class DeepMergeHash < Hash
|
42
|
+
include Hashie::Extensions::MergeInitializer
|
43
|
+
include Hashie::Extensions::DeepMerge
|
44
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
class String
|
4
|
+
include GClouder::Shell
|
5
|
+
|
6
|
+
def snakecase
|
7
|
+
self.gsub(/::/, '/').
|
8
|
+
gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
|
9
|
+
gsub(/([a-z\d])([A-Z])/,'\1_\2').
|
10
|
+
tr("-", "_").
|
11
|
+
downcase
|
12
|
+
end
|
13
|
+
|
14
|
+
def mixedcase
|
15
|
+
self.split('_').collect(&:capitalize).join.sub(/^[A-Z]/, &:downcase)
|
16
|
+
end
|
17
|
+
|
18
|
+
def truncate(length = 32)
|
19
|
+
raise 'Pleasant: Length should be greater than 3' unless length > 3
|
20
|
+
|
21
|
+
truncated_string = self.to_s
|
22
|
+
|
23
|
+
if truncated_string.length > length
|
24
|
+
truncated_string = truncated_string[0...(length - 3)]
|
25
|
+
truncated_string += "..."
|
26
|
+
end
|
27
|
+
|
28
|
+
truncated_string
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module GClouder
|
4
|
+
module Resource
|
5
|
+
include GClouder::GCloud
|
6
|
+
include GClouder::Config::CLIArgs
|
7
|
+
include GClouder::Logging
|
8
|
+
|
9
|
+
def self.feedback(action, resource, name, extra_info: nil, indent: 3, silent: false)
|
10
|
+
return if silent
|
11
|
+
send action, "#{name} #{extra_info}", indent: indent
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.resource?(resource, name, args = nil, filter_key: "name", filter: "#{filter_key} ~ ^#{name}$", project_id: nil, silent: false, extra_info: nil, indent: 3)
|
15
|
+
exists = \
|
16
|
+
gcloud("#{resource} list --filter '#{filter}' #{args} | jq '. | length'", force: true, silent: silent, project_id: project_id)
|
17
|
+
|
18
|
+
if exists
|
19
|
+
feedback("good", resource, name, extra_info: extra_info, indent: indent, silent: silent)
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
|
23
|
+
false
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.describe(resource, name, args = nil, force: true, failure: true, silent: false, project_id: nil)
|
27
|
+
return if resource?(resource, name, silent: silent, project_id: project_id)
|
28
|
+
gcloud "#{resource} describe #{name} #{args}", force: force, failure: failure, silent: silent, project_id: project_id
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.ensure(resource, name, args = nil, project_id: nil, extra_info: nil, silent: false, indent: 3, filter_key: "name")
|
32
|
+
return if resource?(resource, name, project_id: project_id, extra_info: extra_info, silent: silent, indent: indent, filter_key: filter_key)
|
33
|
+
feedback("add", resource, name, extra_info: extra_info, indent: indent, silent: silent)
|
34
|
+
gcloud "#{resource} create #{name} #{args}", project_id: project_id, silent: silent
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.purge(resource, name, args = nil, project_id: nil, silent: false, indent: 3)
|
38
|
+
return unless resource?(resource, name, project_id: project_id, silent: true, indent: indent)
|
39
|
+
extra_info = "[skipped] (--purge not specified)" unless cli_args[:purge]
|
40
|
+
feedback("remove", resource, name, extra_info: extra_info, indent: indent, silent: silent)
|
41
|
+
gcloud "#{resource} delete #{name} #{args}", project_id: project_id if cli_args[:purge]
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.list(resource, args = nil, snake_case: false, project_id: nil)
|
45
|
+
list = gcloud "#{resource} list #{args}", force: true, project_id: project_id
|
46
|
+
snake_case ? list.to_snake_keys : list
|
47
|
+
end
|
48
|
+
|
49
|
+
module Find
|
50
|
+
include GClouder::GCloud
|
51
|
+
|
52
|
+
def self.zone(resource, name, region, project_id: nil)
|
53
|
+
zones = %w(b c d).map { |zone| region + "-" + zone }
|
54
|
+
|
55
|
+
zones.each do |zone|
|
56
|
+
return zone if gcloud "#{resource} describe #{name} --zone=#{zone}", force: true, failure: false, silent: true, project_id: project_id
|
57
|
+
end
|
58
|
+
|
59
|
+
false
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module GClouder
|
4
|
+
module Resource
|
5
|
+
module Cleaner
|
6
|
+
def self.included(klass)
|
7
|
+
klass.extend Cleaner
|
8
|
+
end
|
9
|
+
|
10
|
+
def clean
|
11
|
+
return if undefined.empty?
|
12
|
+
|
13
|
+
header :clean
|
14
|
+
|
15
|
+
undefined.each do |namespace, resources|
|
16
|
+
info namespace, indent: 2, heading: true
|
17
|
+
info
|
18
|
+
resources.each do |resource|
|
19
|
+
message = resource['name']
|
20
|
+
message += " (not defined locally)"
|
21
|
+
warning message
|
22
|
+
# FIXME: enable purge on --purge flag..
|
23
|
+
#Resource.symlink.send(:purge, namespace, resource)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
module Default
|
30
|
+
def self.cleaner
|
31
|
+
Proc.new do |resources, resource|
|
32
|
+
resources.map do |r|
|
33
|
+
r['name'] == resource
|
34
|
+
end.include?(true)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def cleaner
|
40
|
+
(self.const_defined?(:Cleaner) && self::Cleaner.respond_to?(:custom)) ? self::Cleaner.custom : Default.cleaner
|
41
|
+
end
|
42
|
+
|
43
|
+
def undefined
|
44
|
+
self::Remote.list.each_with_object({}) do |(namespace, resources), collection|
|
45
|
+
resources.each do |resource|
|
46
|
+
namespace_resources = self::Local.list[namespace]
|
47
|
+
|
48
|
+
# accept PROC for custom matching of undefined resources
|
49
|
+
next if namespace_resources && cleaner.call(namespace_resources, resource["name"])
|
50
|
+
|
51
|
+
collection[namespace] ||= []
|
52
|
+
collection[namespace] << resource
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
module GClouder
|
4
|
+
module Resources
|
5
|
+
module Compute
|
6
|
+
module Addresses
|
7
|
+
include GClouder::GCloud
|
8
|
+
include GClouder::Logging
|
9
|
+
include GClouder::Resource::Cleaner
|
10
|
+
|
11
|
+
def self.header(stage = :ensure)
|
12
|
+
info "[#{stage}] compute / addresses", title: true
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.ensure
|
16
|
+
return if Local.list.empty?
|
17
|
+
header
|
18
|
+
|
19
|
+
if Local.list.key?("global")
|
20
|
+
info "global", indent: 2, heading: true
|
21
|
+
info
|
22
|
+
Local.list["global"].each { |address| Address.ensure(address["name"], "--global") }
|
23
|
+
end
|
24
|
+
|
25
|
+
Local.list.each do |region, addresses|
|
26
|
+
next if region == "global"
|
27
|
+
next unless addresses
|
28
|
+
|
29
|
+
info region, indent: 2, heading: true
|
30
|
+
info
|
31
|
+
addresses.each do |address|
|
32
|
+
Address.ensure(address["name"], "--region #{region}")
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.check
|
38
|
+
return if Remote.list.empty?
|
39
|
+
return if Local.list.empty?
|
40
|
+
header :check
|
41
|
+
Resources::Validate::Remote.instances(Local.list, Remote.list)
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.validate
|
45
|
+
return if Local.list.empty?
|
46
|
+
header :validate
|
47
|
+
Local.validate
|
48
|
+
end
|
49
|
+
|
50
|
+
module Local
|
51
|
+
include GClouder::Config::Project
|
52
|
+
|
53
|
+
def self.list
|
54
|
+
addresses = global.merge regional
|
55
|
+
addresses.delete_if { |_k, v| v.empty? }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.global
|
59
|
+
Resources::Global.instances(path: ["addresses"])
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.section
|
63
|
+
%w(compute addresses)
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.validate
|
67
|
+
Resources::Validate::Region.instances(
|
68
|
+
list,
|
69
|
+
required_keys: GClouder::Config::Arguments.required(section),
|
70
|
+
permitted_keys: GClouder::Config::Arguments.permitted(section)
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.regional
|
75
|
+
resources = Resources::Region.instances(path: ["addresses"])
|
76
|
+
|
77
|
+
# get_instances_from_region assumes all keys have configs.. this normalizes
|
78
|
+
# the data to match self.global
|
79
|
+
resources.each { |k, v| resources[k] = v.to_a.flatten.delete_if(&:nil?) }
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
module Remote
|
84
|
+
def self.list
|
85
|
+
Resources::Remote.instances(
|
86
|
+
path: ["compute", "addresses"]
|
87
|
+
)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
module Address
|
92
|
+
def self.ensure(name, args)
|
93
|
+
GClouder::Resource.ensure :"compute addresses", name, args
|
94
|
+
end
|
95
|
+
|
96
|
+
def self.purge(namespace, name, args = nil)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
module Resource
|
101
|
+
def self.symlink
|
102
|
+
Module.const_get "#{self.name.delete(/::Resource$/)}::Address"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|