kytoon 1.0.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.
- data/.document +5 -0
- data/Gemfile +15 -0
- data/Gemfile.lock +29 -0
- data/LICENSE.txt +20 -0
- data/README.rdoc +81 -0
- data/Rakefile +35 -0
- data/VERSION +1 -0
- data/config/server_group_vpc.json +14 -0
- data/config/server_group_xen.json +24 -0
- data/lib/kytoon.rb +8 -0
- data/lib/kytoon/providers/cloud_servers_vpc.rb +6 -0
- data/lib/kytoon/providers/cloud_servers_vpc/client.rb +197 -0
- data/lib/kytoon/providers/cloud_servers_vpc/connection.rb +148 -0
- data/lib/kytoon/providers/cloud_servers_vpc/server.rb +121 -0
- data/lib/kytoon/providers/cloud_servers_vpc/server_group.rb +401 -0
- data/lib/kytoon/providers/cloud_servers_vpc/ssh_public_key.rb +29 -0
- data/lib/kytoon/providers/cloud_servers_vpc/vpn_network_interface.rb +33 -0
- data/lib/kytoon/providers/xenserver.rb +1 -0
- data/lib/kytoon/providers/xenserver/server_group.rb +371 -0
- data/lib/kytoon/server_group.rb +46 -0
- data/lib/kytoon/ssh_util.rb +23 -0
- data/lib/kytoon/util.rb +118 -0
- data/lib/kytoon/version.rb +8 -0
- data/lib/kytoon/vpn/vpn_connection.rb +46 -0
- data/lib/kytoon/vpn/vpn_network_manager.rb +237 -0
- data/lib/kytoon/vpn/vpn_openvpn.rb +112 -0
- data/lib/kytoon/xml_util.rb +15 -0
- data/rake/kytoon.rake +115 -0
- data/test/client_test.rb +111 -0
- data/test/helper.rb +18 -0
- data/test/server_group_test.rb +253 -0
- data/test/server_test.rb +69 -0
- data/test/ssh_util_test.rb +22 -0
- data/test/test_helper.rb +194 -0
- data/test/test_kytoon.rb +7 -0
- data/test/util_test.rb +23 -0
- data/test/vpn_network_manager_test.rb +40 -0
- metadata +247 -0
@@ -0,0 +1,29 @@
|
|
1
|
+
module Kytoon
|
2
|
+
|
3
|
+
module Providers
|
4
|
+
|
5
|
+
module CloudServersVPC
|
6
|
+
|
7
|
+
class SshPublicKey
|
8
|
+
|
9
|
+
attr_accessor :id
|
10
|
+
attr_accessor :description
|
11
|
+
attr_accessor :public_key
|
12
|
+
attr_accessor :server_group_id
|
13
|
+
|
14
|
+
def initialize(options={})
|
15
|
+
|
16
|
+
@id=options[:id]
|
17
|
+
@description=options[:description]
|
18
|
+
@public_key=options[:public_key]
|
19
|
+
@server_group_id=options[:server_group_id]
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Kytoon
|
2
|
+
|
3
|
+
module Providers
|
4
|
+
|
5
|
+
module CloudServersVPC
|
6
|
+
|
7
|
+
class VpnNetworkInterface
|
8
|
+
|
9
|
+
attr_accessor :id
|
10
|
+
attr_accessor :vpn_ip_addr
|
11
|
+
attr_accessor :ptp_ip_addr
|
12
|
+
attr_accessor :client_key
|
13
|
+
attr_accessor :client_cert
|
14
|
+
attr_accessor :ca_cert
|
15
|
+
|
16
|
+
def initialize(options={})
|
17
|
+
|
18
|
+
@id=options[:id].to_i
|
19
|
+
@vpn_ip_addr=options[:vpn_ip_addr]
|
20
|
+
@ptp_ip_addr=options[:ptp_ip_addr]
|
21
|
+
@client_key=options[:client_key]
|
22
|
+
@client_cert=options[:client_cert]
|
23
|
+
@ca_cert=options[:ca_cert]
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'kytoon/providers/xenserver/server_group'
|
@@ -0,0 +1,371 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'builder'
|
3
|
+
require 'fileutils'
|
4
|
+
require 'rexml/document'
|
5
|
+
require 'kytoon/util'
|
6
|
+
require 'base64'
|
7
|
+
|
8
|
+
module Kytoon
|
9
|
+
|
10
|
+
module Providers
|
11
|
+
|
12
|
+
module Xenserver
|
13
|
+
# All in one XenServer server group provider.
|
14
|
+
#
|
15
|
+
# Required setup:
|
16
|
+
# 1) add your ssh key to the XenServer box.
|
17
|
+
#
|
18
|
+
# 2) Pre-download any .xva images you'd like to use. These images *must*
|
19
|
+
# have the OpenStack guest agent installed (including Xen Guest Tools).
|
20
|
+
#
|
21
|
+
# 3) Generate an ssh keypair on your XenServer host.
|
22
|
+
#
|
23
|
+
# 4) Add an ip to the private Xen bridge you'd like to use for instances.
|
24
|
+
# This IP should match the range you'd like to use in your server group
|
25
|
+
# config file. Example:
|
26
|
+
# ip addr add 192.168.0.1/24 brd 192.168.0.255 scope global dev xenbr1
|
27
|
+
#
|
28
|
+
class ServerGroup
|
29
|
+
|
30
|
+
@@data_dir=File.join(KYTOON_PROJECT, "tmp", "xenserver")
|
31
|
+
|
32
|
+
def self.data_dir
|
33
|
+
@@data_dir
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.data_dir=(dir)
|
37
|
+
@@data_dir=dir
|
38
|
+
end
|
39
|
+
|
40
|
+
CONFIG_FILE = KYTOON_PROJECT + File::SEPARATOR + "config" + File::SEPARATOR + "server_group.json"
|
41
|
+
|
42
|
+
attr_accessor :id
|
43
|
+
attr_accessor :name
|
44
|
+
attr_accessor :gateway_ip
|
45
|
+
attr_accessor :netmask
|
46
|
+
attr_accessor :gateway
|
47
|
+
attr_accessor :broadcast
|
48
|
+
attr_accessor :network_type
|
49
|
+
attr_accessor :bridge
|
50
|
+
attr_accessor :public_ip_bridge
|
51
|
+
attr_accessor :dns_nameserver
|
52
|
+
|
53
|
+
def initialize(options={})
|
54
|
+
@id = options[:id] || Time.now.to_i
|
55
|
+
@name = options[:name]
|
56
|
+
@netmask = options[:netmask]
|
57
|
+
@gateway = options[:gateway]
|
58
|
+
@broadcast = options[:broadcast]
|
59
|
+
@network_type = options[:network_type]
|
60
|
+
@bridge = options[:bridge]
|
61
|
+
@public_ip_bridge = options[:public_ip_bridge]
|
62
|
+
@dns_nameserver = options[:dns_nameserver]
|
63
|
+
@gateway_ip = options[:gateway_ip]
|
64
|
+
@gateway_ip = ENV['GATEWAY_IP'] if @gateway_ip.nil?
|
65
|
+
raise "Please specify a GATEWAY_IP" if @gateway_ip.nil?
|
66
|
+
|
67
|
+
@servers=[]
|
68
|
+
end
|
69
|
+
|
70
|
+
def server(name)
|
71
|
+
@servers.select {|s| s['hostname'] == name}[0] if @servers.size > 0
|
72
|
+
end
|
73
|
+
|
74
|
+
def servers
|
75
|
+
@servers
|
76
|
+
end
|
77
|
+
|
78
|
+
def gateway_ip
|
79
|
+
@gateway_ip
|
80
|
+
end
|
81
|
+
|
82
|
+
# generate a Server Group XML from server_group.json
|
83
|
+
def self.from_json(json)
|
84
|
+
|
85
|
+
json_hash=JSON.parse(json)
|
86
|
+
|
87
|
+
sg=ServerGroup.new(
|
88
|
+
:id => json_hash["id"],
|
89
|
+
:name => json_hash["name"],
|
90
|
+
:netmask => json_hash['netmask'],
|
91
|
+
:gateway => json_hash['gateway'],
|
92
|
+
:gateway_ip => json_hash['gateway_ip'],
|
93
|
+
:broadcast => json_hash['broadcast'],
|
94
|
+
:dns_nameserver => json_hash['dns_nameserver'],
|
95
|
+
:network_type => json_hash['network_type'],
|
96
|
+
:public_ip_bridge => json_hash['public_ip_bridge'],
|
97
|
+
:bridge => json_hash['bridge']
|
98
|
+
)
|
99
|
+
json_hash["servers"].each do |server_hash|
|
100
|
+
sg.servers << {
|
101
|
+
'hostname' => server_hash['hostname'],
|
102
|
+
'ip_address' => server_hash['ip_address'],
|
103
|
+
'mac' => server_hash['mac'],
|
104
|
+
'image_path' => server_hash['image_path']
|
105
|
+
}
|
106
|
+
end
|
107
|
+
return sg
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def pretty_print
|
112
|
+
|
113
|
+
puts "Group ID: #{@id}"
|
114
|
+
puts "name: #{@name}"
|
115
|
+
puts "Servers:"
|
116
|
+
servers.each do |server|
|
117
|
+
puts "\tname: #{server['hostname']}"
|
118
|
+
puts "\t--"
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
122
|
+
|
123
|
+
def server_names
|
124
|
+
|
125
|
+
names=[]
|
126
|
+
|
127
|
+
servers.each do |server|
|
128
|
+
if block_given? then
|
129
|
+
yield server['hostname']
|
130
|
+
else
|
131
|
+
names << server['hostname']
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
names
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
def cache_to_disk
|
140
|
+
|
141
|
+
sg_hash = {
|
142
|
+
'id' => @id,
|
143
|
+
'name' => @name,
|
144
|
+
'netmask' => @netmask,
|
145
|
+
'gateway' => @gateway,
|
146
|
+
'gateway_ip' => @gateway_ip,
|
147
|
+
'broadcast' => @broadcast,
|
148
|
+
'dns_nameserver' => @dns_nameserver,
|
149
|
+
'network_type' => @network_type,
|
150
|
+
'public_ip_bridge' => @public_ip_bridge,
|
151
|
+
'bridge' => @bridge,
|
152
|
+
'servers' => []
|
153
|
+
}
|
154
|
+
@servers.each do |server|
|
155
|
+
sg_hash['servers'] << {'hostname' => server['hostname'], 'ip_address' => server['ip_address'], 'image_path' => server['image_path'], 'mac' => server['mac']}
|
156
|
+
end
|
157
|
+
|
158
|
+
FileUtils.mkdir_p(@@data_dir)
|
159
|
+
File.open(File.join(@@data_dir, "#{@id}.json"), 'w') do |f|
|
160
|
+
f.chmod(0600)
|
161
|
+
f.write(sg_hash.to_json)
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def delete
|
166
|
+
ServerGroup.cleanup_instances(@gateway_ip)
|
167
|
+
out_file=File.join(@@data_dir, "#{@id}.json")
|
168
|
+
File.delete(out_file) if File.exists?(out_file)
|
169
|
+
end
|
170
|
+
|
171
|
+
def self.create(sg)
|
172
|
+
sg.cache_to_disk
|
173
|
+
init_host(sg)
|
174
|
+
status, host_ssh_public_key = Kytoon::Util.remote_exec(%{
|
175
|
+
if [ -f /root/.ssh/id_rsa.pub ]; then
|
176
|
+
cat /root/.ssh/id_rsa.pub
|
177
|
+
elif [ -f /root/.ssh/id_dsa.pub ]; then
|
178
|
+
cat /root/.ssh/id_dsa.pub
|
179
|
+
else
|
180
|
+
exit 1
|
181
|
+
fi
|
182
|
+
}, sg.gateway_ip)
|
183
|
+
sg.servers.each do |server|
|
184
|
+
create_instance(sg.gateway_ip, server['image_path'], server['hostname'], server['mac'], sg.bridge, host_ssh_public_key)
|
185
|
+
network_type = sg.network_type
|
186
|
+
if network_type == 'static' then
|
187
|
+
configure_static_networking(sg.gateway_ip, server['hostname'], server['ip_address'], sg.netmask, sg.gateway, sg.broadcast, server['mac'], sg.dns_nameserver)
|
188
|
+
else
|
189
|
+
raise "Unsupported network type '#{sg.network_type}'"
|
190
|
+
end
|
191
|
+
end
|
192
|
+
sg
|
193
|
+
end
|
194
|
+
|
195
|
+
def self.get(options={})
|
196
|
+
id = options[:id]
|
197
|
+
if id.nil? then
|
198
|
+
group=ServerGroup.most_recent
|
199
|
+
raise "No server group files exist." if group.nil?
|
200
|
+
id=group.id
|
201
|
+
end
|
202
|
+
|
203
|
+
out_file=File.join(@@data_dir, "#{id}.json")
|
204
|
+
raise "No server group files exist." if not File.exists?(out_file)
|
205
|
+
ServerGroup.from_json(IO.read(out_file))
|
206
|
+
end
|
207
|
+
|
208
|
+
def self.index(options={})
|
209
|
+
|
210
|
+
server_groups=[]
|
211
|
+
Dir[File.join(ServerGroup.data_dir, '*.json')].each do |file|
|
212
|
+
server_groups << ServerGroup.from_json(IO.read(file))
|
213
|
+
end
|
214
|
+
server_groups
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
def self.most_recent
|
219
|
+
server_groups=[]
|
220
|
+
Dir[File.join(@@data_dir, "*.json")].each do |file|
|
221
|
+
server_groups << ServerGroup.from_json(IO.read(file))
|
222
|
+
end
|
223
|
+
if server_groups.size > 0 then
|
224
|
+
server_groups.sort { |a,b| b.id <=> a.id }[0]
|
225
|
+
else
|
226
|
+
nil
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.init_host(sg)
|
231
|
+
|
232
|
+
hosts_file_data = "127.0.0.1\tlocalhost localhost.localdomain\n"
|
233
|
+
sg.servers.each do |server|
|
234
|
+
hosts_file_data += "#{server['ip_address']}\t#{server['hostname']}\n"
|
235
|
+
end
|
236
|
+
|
237
|
+
Kytoon::Util.remote_exec(%{
|
238
|
+
cat > /etc/hosts <<-EOF_CAT
|
239
|
+
#{hosts_file_data}
|
240
|
+
EOF_CAT
|
241
|
+
# FIXME... probably a bit insecure but most people are probably using
|
242
|
+
# boxes behind another firewall anyway.
|
243
|
+
iptables -F
|
244
|
+
iptables -P INPUT ACCEPT
|
245
|
+
iptables -P FORWARD ACCEPT
|
246
|
+
iptables -P OUTPUT ACCEPT
|
247
|
+
iptables -t nat -A POSTROUTING -o #{sg.public_ip_bridge} -j MASQUERADE
|
248
|
+
echo 1 > /proc/sys/net/ipv4/ip_forward
|
249
|
+
}, sg.gateway_ip)
|
250
|
+
end
|
251
|
+
|
252
|
+
def self.create_instance(gw_ip, image_path, hostname, mac, xen_bridge='xenbr1', ssh_public_key=nil)
|
253
|
+
file_data = Base64.encode64("/root/.ssh/authorized_keys,#{ssh_public_key}")
|
254
|
+
|
255
|
+
Kytoon::Util.remote_exec(%{
|
256
|
+
UUID=$(xe vm-import filename=#{image_path})
|
257
|
+
xe vm-param-set name-label=#{hostname} uuid=$UUID
|
258
|
+
NETWORK_UUID=$(xe network-list bridge=#{xen_bridge} | grep -P "^uuid" | cut -f2 -d: | cut -f2 -d" ")
|
259
|
+
xe vif-destroy uuid=$VIF_UUID &> /dev/null
|
260
|
+
for VIF_UUID in $(xe vif-list vm-uuid=$UUID | grep uuid | sed -e 's|.*: ||'); do
|
261
|
+
echo "Destroying Xen VIF uuid: $VIF_UUID"
|
262
|
+
xe vif-destroy uuid=$VIF_UUID &> /dev/null
|
263
|
+
done
|
264
|
+
xe vif-create vm-uuid=$UUID mac=#{mac} network-uuid=$NETWORK_UUID device=0 &> /dev/null
|
265
|
+
xe vm-start uuid=$UUID &> /dev/null
|
266
|
+
|
267
|
+
# inject ssh from host
|
268
|
+
DOMID=$(xe vm-param-get uuid=$UUID param-name="dom-id")
|
269
|
+
xenstore-rm -s /local/domain/$DOMID/data/guest/ssh_key 2> /dev/null
|
270
|
+
xenstore-write -s /local/domain/$DOMID/data/host/ssh_key '{"name": "injectfile", "value": "#{file_data}"}'
|
271
|
+
until [ -n "$INJECT_RETVAL" ]; do
|
272
|
+
INJECT_RETVAL=$(xenstore-read -s /local/domain/$DOMID/data/guest/ssh_key 2> /dev/null)
|
273
|
+
done
|
274
|
+
xenstore-rm -s /local/domain/$DOMID/data/host/ssh_key
|
275
|
+
|
276
|
+
}, gw_ip) do |ok, out|
|
277
|
+
if not ok
|
278
|
+
puts out
|
279
|
+
raise "Failed to create instance #{hostname}."
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def self.cleanup_instances(gw_ip)
|
285
|
+
Kytoon::Util.remote_exec(%{
|
286
|
+
rpm -ev openstack-xen-plugins &> /dev/null
|
287
|
+
yum clean all &> /dev/null
|
288
|
+
|
289
|
+
for UUID in $(xe vm-list is-control-domain=false | grep uuid | sed -e 's|.*: ||'); do
|
290
|
+
echo "Destroying Xen instance uuid: $UUID"
|
291
|
+
xe vm-shutdown uuid=$UUID
|
292
|
+
xe vm-destroy uuid=$UUID
|
293
|
+
done
|
294
|
+
|
295
|
+
for UUID in $(xe vdi-list read-only=false | grep "^uuid" | sed -e 's|.*: ||'); do
|
296
|
+
echo "Destroying VDI uuid: $UUID"
|
297
|
+
xe vdi-destroy uuid=$UUID
|
298
|
+
done
|
299
|
+
|
300
|
+
for UUID in $(xe vif-list | grep uuid | sed -e 's|.*: ||'); do
|
301
|
+
echo "Destroying Xen VIF uuid: $UUID"
|
302
|
+
xe vif-destroy uuid=$UUID
|
303
|
+
done
|
304
|
+
|
305
|
+
}, gw_ip) do |ok, out|
|
306
|
+
if not ok
|
307
|
+
puts out
|
308
|
+
raise "Failed to cleanup instances."
|
309
|
+
end
|
310
|
+
end
|
311
|
+
end
|
312
|
+
|
313
|
+
def self.configure_static_networking(gw_ip, hostname, ip_address, netmask, gateway, broadcast, mac, dns_nameserver)
|
314
|
+
|
315
|
+
# networking
|
316
|
+
network_info = {
|
317
|
+
"label" => "public",
|
318
|
+
"broadcast" => broadcast,
|
319
|
+
"ips" => [{
|
320
|
+
"ip" => ip_address,
|
321
|
+
"netmask" => netmask,
|
322
|
+
"enabled" => "1"}],
|
323
|
+
"mac" => mac,
|
324
|
+
"dns" => [dns_nameserver],
|
325
|
+
"gateway" => gateway
|
326
|
+
}
|
327
|
+
|
328
|
+
Kytoon::Util.remote_exec(%{
|
329
|
+
UUID=$(xe vm-list name-label=#{hostname} | grep uuid | sed -e 's|.*: ||')
|
330
|
+
DOMID=$(xe vm-param-get uuid=$UUID param-name="dom-id")
|
331
|
+
xenstore-write -s /local/domain/$DOMID/vm-data/hostname '#{hostname}'
|
332
|
+
xenstore-write -s /local/domain/$DOMID/vm-data/networking/123_nw_info '#{network_info.to_json}'
|
333
|
+
|
334
|
+
xenstore-write -s /local/domain/$DOMID/data/host/123_reset_nw '{"name": "resetnetwork", "value": ""}'
|
335
|
+
xenstore-rm -s /local/domain/$DOMID/data/guest/123_reset_nw 2> /dev/null
|
336
|
+
until [ -n "$NW_RETVAL" ]; do
|
337
|
+
NW_RETVAL=$(xenstore-read -s /local/domain/$DOMID/data/guest/123_reset_nw 2> /dev/null)
|
338
|
+
done
|
339
|
+
xenstore-rm -s /local/domain/$DOMID/data/host/123_reset_nw
|
340
|
+
xe vm-reboot uuid=$UUID &> /dev/null
|
341
|
+
COUNT=0
|
342
|
+
until ping -c 1 #{hostname} &> /dev/null; do
|
343
|
+
COUNT=$(( $COUNT + 1 ))
|
344
|
+
[ $COUNT -eq 10 ] && break
|
345
|
+
done
|
346
|
+
until ssh -o ConnectTimeout=1 #{hostname} &> /dev/null; do
|
347
|
+
COUNT=$(( $COUNT + 1 ))
|
348
|
+
[ $COUNT -eq 20 ] && break
|
349
|
+
sleep 1
|
350
|
+
done
|
351
|
+
ssh #{hostname} bash <<-EOF_SSH_BASH
|
352
|
+
hostname #{hostname}
|
353
|
+
EOF_SSH_BASH
|
354
|
+
scp /etc/hosts #{hostname}:/etc/hosts
|
355
|
+
}, gw_ip) do |ok, out|
|
356
|
+
puts out
|
357
|
+
if not ok
|
358
|
+
puts out
|
359
|
+
raise "Failed to setup static networking for #{hostname}."
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
end
|
364
|
+
|
365
|
+
end
|
366
|
+
|
367
|
+
end
|
368
|
+
|
369
|
+
end
|
370
|
+
|
371
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'kytoon/providers/cloud_servers_vpc'
|
2
|
+
require 'kytoon/providers/xenserver'
|
3
|
+
|
4
|
+
class ServerGroup
|
5
|
+
|
6
|
+
@@group_class = nil
|
7
|
+
|
8
|
+
# called to init the configured group class we will use
|
9
|
+
def self.init
|
10
|
+
return if not @@group_class.nil?
|
11
|
+
configs = Util.load_configs
|
12
|
+
group_type = ENV['GROUP_TYPE'] || configs['group_type']
|
13
|
+
if group_type == "cloud_server_vpc" then
|
14
|
+
@@group_class = Kytoon::Providers::CloudServersVPC::ServerGroup
|
15
|
+
elsif group_type == "xenserver" then
|
16
|
+
@@group_class = Kytoon::Providers::Xenserver::ServerGroup
|
17
|
+
else
|
18
|
+
raise "Invalid 'group_type' specified in config file."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.index(options)
|
23
|
+
@@group_class.index(options)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.create
|
27
|
+
json_config_file=ENV['SERVER_GROUP_JSON']
|
28
|
+
if json_config_file.nil? then
|
29
|
+
json_config_file = @@group_class::CONFIG_FILE
|
30
|
+
end
|
31
|
+
sg = @@group_class.from_json(IO.read(json_config_file))
|
32
|
+
@@group_class.create(sg)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.get
|
36
|
+
id = ENV['GROUP_ID']
|
37
|
+
@@group_class.get(:id => id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.delete
|
41
|
+
id = ENV['GROUP_ID']
|
42
|
+
sg = @@group_class.get(:id => id)
|
43
|
+
sg.delete
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|