dyntool 0.0.2
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/lib/dyntool.rb +769 -0
- metadata +62 -0
data/lib/dyntool.rb
ADDED
@@ -0,0 +1,769 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
require 'rubygems'
|
3
|
+
require 'net/https'
|
4
|
+
require 'uri'
|
5
|
+
require 'json'
|
6
|
+
require 'ipaddr'
|
7
|
+
require 'highline/import'
|
8
|
+
### class for loading and retrieving configuration from dyn.yml
|
9
|
+
class LoadConfig
|
10
|
+
def SetConfFile=( confFile )
|
11
|
+
@confFile = confFile
|
12
|
+
end
|
13
|
+
def GetHandler
|
14
|
+
@conf = YAML.load_file(@confFile)
|
15
|
+
end
|
16
|
+
def GetDcs
|
17
|
+
@dcs = @conf['sites']['names']
|
18
|
+
end
|
19
|
+
def GetRegions
|
20
|
+
@regions = @conf['regions']['names']
|
21
|
+
end
|
22
|
+
def GetIPs(provider)
|
23
|
+
@ips = @conf['providers'][provider]
|
24
|
+
end
|
25
|
+
def GetProviders
|
26
|
+
@providers = @conf['providers']['names']
|
27
|
+
end
|
28
|
+
def GetDcProviders(dc)
|
29
|
+
@dcproviders = @conf['sites'][dc]
|
30
|
+
end
|
31
|
+
def GetProvierIP(provider)
|
32
|
+
@providerip = @conf['providers'][provider]
|
33
|
+
end
|
34
|
+
def GetCountries(region)
|
35
|
+
@countries = @conf['regions'][region]
|
36
|
+
end
|
37
|
+
def GetDcsEnabled(region)
|
38
|
+
@dcs = @conf['enable'][region]
|
39
|
+
end
|
40
|
+
def GetIpLabel(ip)
|
41
|
+
@iplabel = @conf['ips'][ip]['label']
|
42
|
+
end
|
43
|
+
def GetIpWeight(ip,region)
|
44
|
+
@weight = @conf['ips'][ip]['weight'][region]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
## Getting authentication creds from users
|
48
|
+
class Authentication
|
49
|
+
# Getting creds from user to authenticate upon dyn
|
50
|
+
def AuthUser()
|
51
|
+
@creds = []
|
52
|
+
@username = ask("Enter your username: ") { |q| q.echo = true }
|
53
|
+
@password = ask("Enter your password: ") { |q| q.echo = "*" }
|
54
|
+
@creds << @username
|
55
|
+
@creds << @password
|
56
|
+
return(@creds)
|
57
|
+
end
|
58
|
+
# check if dyn.yaml configuration is same as commited in svn
|
59
|
+
def SvnChk()
|
60
|
+
@svn_chk=`svn stat dyn.yaml`
|
61
|
+
if @svn_chk != ""
|
62
|
+
puts "Your dyn.yaml is not identical to the svn copy, or not exist."
|
63
|
+
puts "Run \"svn up\" before using this tool"
|
64
|
+
exit 2
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
### class for validating command line parameters and direct to relevant action
|
69
|
+
class Parameters
|
70
|
+
def SetArgs=( argv )
|
71
|
+
@ARGV = argv
|
72
|
+
@sconf = LoadConfig.new()
|
73
|
+
@sconf.SetConfFile = "dyn.yml"
|
74
|
+
@sconf.GetHandler
|
75
|
+
end
|
76
|
+
# Opening Session to dyn using creds from the command line
|
77
|
+
def OpenTheSession(customer,user,password)
|
78
|
+
puts "opening a session to DYN"
|
79
|
+
@session = Restcall.new()
|
80
|
+
@session.OpenSession(customer,user,password)
|
81
|
+
end
|
82
|
+
# closing dyn session
|
83
|
+
def CloseTheSession()
|
84
|
+
puts "Closing DYN session"
|
85
|
+
@session.CloseSession()
|
86
|
+
end
|
87
|
+
# Routing the validation upon the relevant operation
|
88
|
+
def Parameters(type)
|
89
|
+
@operate = OperateDyn.new()
|
90
|
+
@params = case type
|
91
|
+
when "main_operation" then @operations = [ "add", "del", "shift", "generate", "get", "change", "revert" ]
|
92
|
+
when "add" then ValidateAdd()
|
93
|
+
when "change" then ValidateChange()
|
94
|
+
when "del" then ValidateDel()
|
95
|
+
when "shift" then ValidateShift()
|
96
|
+
when "generate" then ValidateGenerate()
|
97
|
+
when "get" then ValidateGet()
|
98
|
+
when "revert" then ValidateRevert()
|
99
|
+
end
|
100
|
+
end
|
101
|
+
# validating revert to current yml configuration
|
102
|
+
def ValidateRevert()
|
103
|
+
@services = @session.GetServices()
|
104
|
+
ValidateServiceExist(@services,@ARGV[2])
|
105
|
+
CompareGeo(@ARGV[2])
|
106
|
+
AskUser()
|
107
|
+
ValidateZone(@ARGV[1])
|
108
|
+
@operate.SetOperation("RevertGeo")
|
109
|
+
@operate.SetSession(@session)
|
110
|
+
@operate.SetArgs(@ARGV[1],@ARGV[2])
|
111
|
+
|
112
|
+
end
|
113
|
+
# Get approval from user to revert/shift after reviewing the changes
|
114
|
+
def AskUser()
|
115
|
+
HighLine.track_eof = false
|
116
|
+
@answer = ask("Are you sure you want to revert? (yes) ") { |q| q.echo = true }
|
117
|
+
if @answer != "yes"
|
118
|
+
exit 2
|
119
|
+
end
|
120
|
+
end
|
121
|
+
# Checking if the parameter is valid, if not return usage
|
122
|
+
def ValidateParams(arg)
|
123
|
+
if ! @operations.include? arg
|
124
|
+
DisplayUsage()
|
125
|
+
else
|
126
|
+
@valid = arg
|
127
|
+
end
|
128
|
+
end
|
129
|
+
# Validating the get operation, and setting the relevant arguments in OperateDyn object
|
130
|
+
def ValidateGet()
|
131
|
+
case @ARGV[1]
|
132
|
+
when "services" then @operate.SetOperation("GetServices")
|
133
|
+
@operate.SetSession(@session)
|
134
|
+
when "node" then @operate.SetOperation("GetNodeService")
|
135
|
+
@operate.SetArgs(@ARGV[2])
|
136
|
+
@operate.SetSession(@session)
|
137
|
+
when "cname" then ValidateZone(@ARGV[2])
|
138
|
+
ValidateFqdn(@ARGV[2],@ARGV[3],"true")
|
139
|
+
@operate.SetOperation("GetCnameService")
|
140
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3])
|
141
|
+
@operate.SetSession(@session)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
# Check type of record to add, the zone exist, then upon type, check arguments and set the required add operation
|
145
|
+
def ValidateAdd
|
146
|
+
ValidateType(@ARGV[1])
|
147
|
+
ValidateZone(@ARGV[2])
|
148
|
+
case @ARGV[1]
|
149
|
+
when "a" then ValidateFqdn(@ARGV[2],@ARGV[3],"false")
|
150
|
+
ValidateIP(@ARGV[4])
|
151
|
+
@operate.SetOperation("AddARecord")
|
152
|
+
@operate.SetSession(@session)
|
153
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3],@ARGV[4])
|
154
|
+
when "cname" then ValidateFqdn(@ARGV[2],@ARGV[3],"true")
|
155
|
+
ValidateFqdn(@ARGV[2],@ARGV[4],"false")
|
156
|
+
@operate.SetOperation("AddCnameRecord")
|
157
|
+
@operate.SetSession(@session)
|
158
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3],@ARGV[4])
|
159
|
+
when "txt" then ValidateFqdn(@ARGV[2],@ARGV[3],"true")
|
160
|
+
@operate.SetOperation("AddTxtRecord")
|
161
|
+
@operate.SetSession(@session)
|
162
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3],@ARGV[4])
|
163
|
+
end
|
164
|
+
end
|
165
|
+
def ValidateChange
|
166
|
+
ValidateType(@ARGV[1])
|
167
|
+
ValidateZone(@ARGV[2])
|
168
|
+
case @ARGV[1]
|
169
|
+
when "cname" then ValidateFqdn(@ARGV[2],@ARGV[3],"true")
|
170
|
+
ValidateFqdn(@ARGV[2],@ARGV[4],"true")
|
171
|
+
@operate.SetOperation("ChangeCnameRecord")
|
172
|
+
@operate.SetSession(@session)
|
173
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3],@ARGV[4])
|
174
|
+
end
|
175
|
+
end
|
176
|
+
# Validating the delete arguments: zone and fqdn exist, in case of service that the service exist
|
177
|
+
def ValidateDel
|
178
|
+
case @ARGV[1]
|
179
|
+
when "node" then ValidateZone(@ARGV[2])
|
180
|
+
ValidateFqdn(@ARGV[2],@ARGV[3],"true")
|
181
|
+
@operate.SetOperation("DeleteNode")
|
182
|
+
@operate.SetSession(@session)
|
183
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3])
|
184
|
+
when "service" then ValidateZone(@ARGV[3])
|
185
|
+
@services = @session.GetServices()
|
186
|
+
ValidateServiceExist(@services,@ARGV[2])
|
187
|
+
@operate.SetOperation("DeleteService")
|
188
|
+
@operate.SetSession(@session)
|
189
|
+
@operate.SetArgs(@ARGV[2],@ARGV[3])
|
190
|
+
end
|
191
|
+
end
|
192
|
+
def ValidateShift
|
193
|
+
@sdcs = @sconf.GetDcs
|
194
|
+
@sproviders = @sconf
|
195
|
+
@services = @session.GetServices()
|
196
|
+
ValidateServiceExist(@services,@ARGV[1])
|
197
|
+
ValidateZone(@ARGV[2])
|
198
|
+
@resource = ValidateShiftArgs(@ARGV[3],@ARGV[6],@ARGV[4])
|
199
|
+
case @resource
|
200
|
+
when "dc" then @dcs = GetArgsDcs(@ARGV[5],@sdcs)
|
201
|
+
@dcs_list = @dcs.join("-")
|
202
|
+
@operate.SetOperation("ShiftTraffic")
|
203
|
+
@operate.SetSession(@session)
|
204
|
+
@operate.SetArgs(@ARGV[1],@ARGV[4],@ARGV[5],@dcs_list,@ARGV[2])
|
205
|
+
when "provider" then ValidateProvider(@ARGV[5],@ARGV[7])
|
206
|
+
@operate.SetOperation("ShiftTraffic")
|
207
|
+
@operate.SetSession(@session)
|
208
|
+
@operate.SetArgs(@ARGV[1],@ARGV[4],@ARGV[5],@ARGV[7],@ARGV[2])
|
209
|
+
end
|
210
|
+
end
|
211
|
+
# Get dcs list from arguments
|
212
|
+
def GetArgsDcs(from,sdcs)
|
213
|
+
@c = 0
|
214
|
+
@dcs = []
|
215
|
+
@sdcs = sdcs
|
216
|
+
@ARGV.each do |arg|
|
217
|
+
@c += 1
|
218
|
+
if (@c > 7)
|
219
|
+
if (! @sdcs.include? "#{arg}")
|
220
|
+
abort("The dcs is not in the configuration dcs list")
|
221
|
+
else
|
222
|
+
@dcs << "#{arg}"
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
if @dcs.include? "#{from}"
|
227
|
+
abort("destination dc/s cant include source dc")
|
228
|
+
end
|
229
|
+
if @dcs.empty?
|
230
|
+
abort("List of dcs cant be empty")
|
231
|
+
end
|
232
|
+
return (@dcs)
|
233
|
+
end
|
234
|
+
# checking arguments for shift traffic
|
235
|
+
def ValidateShiftArgs(from,to,resource)
|
236
|
+
if (("#{from}" != "from") || ("#{to}" != "to") || (("#{resource}" != "dc") && ("#{resource}" != "provider")))
|
237
|
+
DisplayUsage()
|
238
|
+
else
|
239
|
+
return("#{resource}")
|
240
|
+
end
|
241
|
+
end
|
242
|
+
# check that service given as argument exist in dyn
|
243
|
+
def ValidateServiceExist(services,geo)
|
244
|
+
@services = services
|
245
|
+
if ! @services.include? "#{geo}"
|
246
|
+
abort("The geo services list does not include the geo entered")
|
247
|
+
end
|
248
|
+
end
|
249
|
+
def ValidateGenerate
|
250
|
+
ValidateServiceFormat(@ARGV[1])
|
251
|
+
ValidateZone(@ARGV[2])
|
252
|
+
ValidateFqdn(@ARGV[2],@ARGV[3],"false")
|
253
|
+
@operate.SetOperation("GenerateGeoNode")
|
254
|
+
@operate.SetSession(@session)
|
255
|
+
@operate.SetArgs(@ARGV[1],@ARGV[2],@ARGV[3])
|
256
|
+
end
|
257
|
+
def ValidateServiceFormat(service)
|
258
|
+
@service = service
|
259
|
+
if ! (@service.match /geo[0][1-9]|geo[1-4][0-9]/)
|
260
|
+
puts "service name must match geo(01-49) structure"
|
261
|
+
DisplayUsage()
|
262
|
+
end
|
263
|
+
end
|
264
|
+
def ValidateZone(zone)
|
265
|
+
puts "Validating zone: " + zone
|
266
|
+
@session.CheckZone(zone)
|
267
|
+
end
|
268
|
+
def ValidateFqdn(zone,node,state)
|
269
|
+
puts "Validating the host: " + node + " in zone: " + zone
|
270
|
+
@session.CheckNodes(zone,node,state)
|
271
|
+
end
|
272
|
+
# checking that ip is in a valid format
|
273
|
+
def ValidateIP(ip)
|
274
|
+
puts "Validating the IP address: " + ip
|
275
|
+
if (IPAddr.new(ip) rescue nil).nil?
|
276
|
+
puts "IP Address is not valid"
|
277
|
+
DisplayUsage()
|
278
|
+
end
|
279
|
+
end
|
280
|
+
# validate that site exist in yaml
|
281
|
+
def ValidateDC(site)
|
282
|
+
if ! @conf.GetDcs.include? site
|
283
|
+
puts "The DC does not exist"
|
284
|
+
DisplayUsage()
|
285
|
+
end
|
286
|
+
end
|
287
|
+
# validate that provider given as argument actually exist in yaml
|
288
|
+
def ValidateProvider(srcprovider,dstprovider)
|
289
|
+
@providers = @sconf.GetProviders
|
290
|
+
@dcsrc = srcprovider.split('_')
|
291
|
+
@dcdst = dstprovider.split('_')
|
292
|
+
if ((! @providers.include? srcprovider) || (! @providers.include? dstprovider))
|
293
|
+
abort("The Provider does not exist")
|
294
|
+
end
|
295
|
+
if (srcprovider == dstprovider)
|
296
|
+
abort("Source providers cant be same as destination provider")
|
297
|
+
end
|
298
|
+
if (@dcsrc[1] != @dcdst[1])
|
299
|
+
abort("Cant shift traffic between providers in different dcs")
|
300
|
+
end
|
301
|
+
end
|
302
|
+
# check that record type is in the allow list
|
303
|
+
def ValidateType(type)
|
304
|
+
@types = [ "a", "cname", "txt" ]
|
305
|
+
if ! @types.include? type
|
306
|
+
puts "Not a valid record type"
|
307
|
+
DisplayUsage()
|
308
|
+
end
|
309
|
+
end
|
310
|
+
# display script usage
|
311
|
+
def DisplayUsage
|
312
|
+
puts "Usage of dynamo.rb cmd"
|
313
|
+
puts "**********************"
|
314
|
+
puts "**********************"
|
315
|
+
puts "(add)"
|
316
|
+
puts "********************"
|
317
|
+
puts "- a zone fqdn(a) ip , example: dynamo.rb add a example.com mynode.example.com 11.12.13.14"
|
318
|
+
puts "- cname zone fqdn(a) fqdn(cname) , example: dynamo.rb add cname example.com mynode.example.com mycnamenode.example.com"
|
319
|
+
puts "- txt zone fqdn(a) \"some text\" , example: dynamo.rb add txt example.com mynode.example.com \"this is some text\""
|
320
|
+
puts "(del)"
|
321
|
+
puts "********************"
|
322
|
+
puts "- del zone node fqdn(node) - node can be a,cname,txt,geonode,etc , example: dynamo.rb del node example.com mynode.example.com"
|
323
|
+
puts "- del service geoservice zone, example: dynamo.rb del service geo17 example.com"
|
324
|
+
puts "(change)"
|
325
|
+
puts "********************"
|
326
|
+
puts "- change cname zone cname newfqdn, example: dynamo.rb change cname example.com mycnamenode.example.com test19.example.com"
|
327
|
+
puts "(generate)"
|
328
|
+
puts "geo service from yaml"
|
329
|
+
puts "********************"
|
330
|
+
puts "- generate geoservice zone geonode, example: dynamo.rb generate geo11 example.com test11.example.com"
|
331
|
+
puts "(shift)"
|
332
|
+
puts "********************"
|
333
|
+
puts " - shift geoservice zone from dc/provider to dc/dcs/provider(in same dc)"
|
334
|
+
puts "example1(shift traffic from chidc1 to nydc1): dynamo.rb shift geo11 example.com from dc chidc1 to nydc1"
|
335
|
+
puts "example1(shift traffic from chidc1 to nydc1 and ladc1): dynamo.rb shift geo11 example.com from dc chidc1 to nydc1 ladc1"
|
336
|
+
puts "example3(shift traffic from amc_chi to inap_chi): dynamo.rb shift geo15 example.com from provider amc_chi to inap_chi"
|
337
|
+
puts "(revert)"
|
338
|
+
puts "go back to state of yaml configuration"
|
339
|
+
puts "*******************"
|
340
|
+
puts "- revert zone geoservice, example: dynamo.rb revert example.com geo15"
|
341
|
+
puts "(get)"
|
342
|
+
puts " - get services (get all geo services), example: dynamo.rb get services"
|
343
|
+
puts " - get node geonode, example: dynamo.rb get node test1.example.com"
|
344
|
+
puts " - get cname zone cname, example: dynamo.rb get cname example.com mycnamenode.example.com"
|
345
|
+
exit(2)
|
346
|
+
end
|
347
|
+
# compare service geo data of current state vs yaml file
|
348
|
+
def CompareGeo(service)
|
349
|
+
@current_data = @session.GetGeoData(service)
|
350
|
+
@current_groups = []
|
351
|
+
@yaml_groups = []
|
352
|
+
@yaml_total_groups = []
|
353
|
+
@current_total_groups = []
|
354
|
+
@current_data['data']['groups'].each do |group|
|
355
|
+
@current_groups << group['name']
|
356
|
+
end
|
357
|
+
@yaml_groups = @sconf.GetRegions
|
358
|
+
@current_total_groups = @current_groups - @yaml_groups
|
359
|
+
@yaml_total_groups = @yaml_groups - @current_groups
|
360
|
+
if (! @yaml_total_groups.empty?)
|
361
|
+
puts "Diffrence in regions list:"
|
362
|
+
puts "+Yaml #{@yaml_total_groups}"
|
363
|
+
end
|
364
|
+
if (! @current_total_groups.empty?)
|
365
|
+
puts "Diffrence in regions list:"
|
366
|
+
puts "+Current #{@current_total_groups}"
|
367
|
+
end
|
368
|
+
@current_data['data']['groups'].each do |region|
|
369
|
+
@yaml_ips = []
|
370
|
+
@current_ips = []
|
371
|
+
@yaml_total_ips = []
|
372
|
+
@current_total_ips = []
|
373
|
+
@name = region['name']
|
374
|
+
region['rdata']['a_rdata'].each do |rdata|
|
375
|
+
@current_ips << rdata['address']
|
376
|
+
end
|
377
|
+
@sconf.GetDcsEnabled(@name).each do |dc|
|
378
|
+
@providers = @sconf.GetDcProviders(dc)
|
379
|
+
@providers.each do |provider|
|
380
|
+
@sconf.GetIPs(provider).each do |ips|
|
381
|
+
ips.each do |ip|
|
382
|
+
@yaml_ips << ip
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
386
|
+
end
|
387
|
+
@current_total_ips = @current_ips - @yaml_ips
|
388
|
+
@yaml_total_ips = @yaml_ips - @current_ips
|
389
|
+
if ! @yaml_total_ips.empty?
|
390
|
+
PrintDiff(@name,@yaml_total_ips,"IP","Yaml")
|
391
|
+
end
|
392
|
+
if ! @current_total_ips.empty?
|
393
|
+
PrintDiff(@name,@current_total_ips,"IP","Current")
|
394
|
+
end
|
395
|
+
@yaml_countries = []
|
396
|
+
@current_countries = []
|
397
|
+
@yaml_total_countries = []
|
398
|
+
@current_total_countries = []
|
399
|
+
region['countries'].each do |country|
|
400
|
+
@current_countries << country
|
401
|
+
end
|
402
|
+
@sconf.GetCountries(@name).each do |country|
|
403
|
+
@yaml_countries << country
|
404
|
+
end
|
405
|
+
@yaml_total_countries = @yaml_countries - @current_countries
|
406
|
+
@current_total_countries = @current_countries - @yaml_countries
|
407
|
+
if ! @yaml_total_countries.empty?
|
408
|
+
PrintDiff(@name,@yaml_total_countries,"Countries","Yaml")
|
409
|
+
end
|
410
|
+
if ! @current_total_countries.empty?
|
411
|
+
PrintDiff(@name,@current_total_countries,"Countries","Current")
|
412
|
+
end
|
413
|
+
@current_weights = []
|
414
|
+
@yaml_weights = []
|
415
|
+
region['weight']['a_weight'].each do |weight|
|
416
|
+
@current_weights << weight
|
417
|
+
end
|
418
|
+
@i = 0
|
419
|
+
@yaml_ips.each do |ip|
|
420
|
+
@yaml_weights << @sconf.GetIpWeight(ip,@name)
|
421
|
+
end
|
422
|
+
@yaml_weights.each do |weight|
|
423
|
+
if weight.to_s != @current_weights[@i].to_s
|
424
|
+
puts "##############################################################################"
|
425
|
+
puts "There is weight difference in region #{@name}, IP: #{@yaml_ips[@i]}"
|
426
|
+
puts "Yaml weight is: #{weight}"
|
427
|
+
puts "Current weight is: #{@current_weights[@i]}"
|
428
|
+
puts "##############################################################################"
|
429
|
+
@i += 1
|
430
|
+
end
|
431
|
+
end
|
432
|
+
end
|
433
|
+
end
|
434
|
+
# gets region, list of differencesm, what is different and where and print it out
|
435
|
+
def PrintDiff(region,list,name,symbol)
|
436
|
+
puts "Diffrence in #{name} list:"
|
437
|
+
puts "Region #{region}:"
|
438
|
+
puts "+#{symbol} #{name}:"
|
439
|
+
list.each do |item|
|
440
|
+
puts "#{item}"
|
441
|
+
end
|
442
|
+
end
|
443
|
+
end
|
444
|
+
class OperateDyn
|
445
|
+
# set the relevant operation
|
446
|
+
def SetOperation(op)
|
447
|
+
@@op=op
|
448
|
+
end
|
449
|
+
# set the arguments
|
450
|
+
def SetArgs(*args)
|
451
|
+
@@args=args
|
452
|
+
end
|
453
|
+
# set the session to dyn
|
454
|
+
def SetSession(session)
|
455
|
+
@@session=session
|
456
|
+
end
|
457
|
+
# run the operation set by setoperation method in the validation phase
|
458
|
+
def RunOP
|
459
|
+
case(@@op)
|
460
|
+
when "AddARecord" then @@session.AddARecord(@@args[0],@@args[1],@@args[2])
|
461
|
+
when "DeleteNode" then @@session.DeleteNode(@@args[0],@@args[1])
|
462
|
+
when "DeleteService" then @@session.DeleteService(@@args[0],@@args[1])
|
463
|
+
when "AddCnameRecord" then @@session.AddCnameRecord(@@args[0],@@args[1],@@args[2],"post")
|
464
|
+
when "AddTxtRecord" then @@session.AddTxtRecord(@@args[0],@@args[1],@@args[2])
|
465
|
+
when "ChangeCnameRecord" then @@session.AddCnameRecord(@@args[0],@@args[1],@@args[2],"put")
|
466
|
+
when "GenerateGeoNode" then @record_data = BuildService(@@args[0],"","","")
|
467
|
+
@@session.GenerateGeoService(@@args[0],@@args[1],@record_data,"create")
|
468
|
+
@@session.GenerateGeoNode(@@args[0],@@args[1],@@args[2])
|
469
|
+
when "GetServices" then @services = @@session.GetServices()
|
470
|
+
puts "Here is the list of Geo services:"
|
471
|
+
puts @services
|
472
|
+
when "GetNodeService" then @services = @@session.GetServices()
|
473
|
+
GetGeoNodeService(@services,@@args[0])
|
474
|
+
when "GetCnameService" then @services = @@session.GetServices()
|
475
|
+
@geonode = @@session.GetCnameService(@@args[1],@@args[0])
|
476
|
+
GetGeoNodeService(@services,@geonode)
|
477
|
+
when "ShiftTraffic" then @record_data = BuildService(@@args[0],@@args[1],@@args[2],@@args[3])
|
478
|
+
@@session.GenerateGeoService(@@args[0],@@args[4],@record_data,"update")
|
479
|
+
when "RevertGeo" then @record_data = BuildService(@@args[0],"","","")
|
480
|
+
@@session.GenerateGeoService(@@args[1],@@args[0],@record_data,"update")
|
481
|
+
end
|
482
|
+
end
|
483
|
+
def GetOP
|
484
|
+
return(@@op)
|
485
|
+
end
|
486
|
+
def GetArgs
|
487
|
+
return(@@args)
|
488
|
+
end
|
489
|
+
def GetGeoNodeService(services,node)
|
490
|
+
@services = services
|
491
|
+
@services.each do |service|
|
492
|
+
puts "Checking If node #{node} is attached to service #{service}"
|
493
|
+
@result = @@session.CheckNodeService(service,node)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
# building the record_data hash for generating geo service in dyn API
|
497
|
+
def BuildService(service,flag,shiftfrom,shifto)
|
498
|
+
puts "Generating the geo service data"
|
499
|
+
@@conf = LoadConfig.new()
|
500
|
+
@@conf.SetConfFile = "dyn.yml"
|
501
|
+
@@conf.GetHandler
|
502
|
+
@regions = @@conf.GetRegions
|
503
|
+
@dcs = @@conf.GetDcs
|
504
|
+
@shiftfrom = []
|
505
|
+
@shifto = []
|
506
|
+
@shiftfrom << shiftfrom
|
507
|
+
@shifto = shifto.split("-")
|
508
|
+
@region_hash = []
|
509
|
+
@i = 0
|
510
|
+
@regions.each do |region|
|
511
|
+
@ips = []
|
512
|
+
@labels = []
|
513
|
+
@weights = []
|
514
|
+
@countries = @@conf.GetCountries(region)
|
515
|
+
@dcs = @@conf.GetDcsEnabled(region)
|
516
|
+
if (flag == "dc")
|
517
|
+
if @dcs.include? "#{shiftfrom}"
|
518
|
+
@dcs = @dcs - @shiftfrom
|
519
|
+
@dcs = @dcs + @shifto
|
520
|
+
end
|
521
|
+
end
|
522
|
+
@dcs.each do |dc|
|
523
|
+
@providers = @@conf.GetDcProviders(dc)
|
524
|
+
if (flag == "provider")
|
525
|
+
if @providers.include? "#{shiftfrom}"
|
526
|
+
@providers = @providers - @shiftfrom
|
527
|
+
@providers = @providers + @shifto
|
528
|
+
end
|
529
|
+
end
|
530
|
+
@providers.each do |provider|
|
531
|
+
@ips += @@conf.GetProvierIP(provider)
|
532
|
+
end
|
533
|
+
@ips = @ips.uniq
|
534
|
+
end
|
535
|
+
@ips_len = @ips.size
|
536
|
+
if @ips_len == 0
|
537
|
+
abort("The region #{region}, has empty ip list. aborting....")
|
538
|
+
end
|
539
|
+
@ips_hash = BuildIPs(@ips)
|
540
|
+
@i += 1
|
541
|
+
@ips.each do |ip|
|
542
|
+
@label = @@conf.GetIpLabel(ip)
|
543
|
+
@weight = @@conf.GetIpWeight(ip,region)
|
544
|
+
@labels << "#{@label}"
|
545
|
+
@weights << "#{@weight}"
|
546
|
+
end
|
547
|
+
@labels = @labels.uniq
|
548
|
+
@region_hash[@i] = { :name => "#{region}", :label => { :a_label => @labels}, :weight => { :a_weight => @weights }, :serve_count => { :a_serve_count => @ips_len }, :countries => @countries, :rdata => @ips_hash }
|
549
|
+
end
|
550
|
+
@record_data = { :name => "#{service}", :groups => [ @region_hash[1],@region_hash[2],@region_hash[3],@region_hash[4],@region_hash[5],@region_hash[6],@region_hash[7],@region_hash[8],@region_hash[9] ]}
|
551
|
+
return(@record_data)
|
552
|
+
end
|
553
|
+
# building the ip hash
|
554
|
+
def BuildIPs(ips)
|
555
|
+
@ips_hash = "{ :a_rdata => ["
|
556
|
+
ips.each do |ip|
|
557
|
+
@ips_hash << "{ :address => \"#{ip}\"},"
|
558
|
+
end
|
559
|
+
@ips_hash = @ips_hash.chop
|
560
|
+
@ips_hash << "]}"
|
561
|
+
@ips_hash = eval(@ips_hash)
|
562
|
+
return(@ips_hash)
|
563
|
+
end
|
564
|
+
|
565
|
+
end
|
566
|
+
# contains restcalls to get and set data upon dyn API
|
567
|
+
class Restcall
|
568
|
+
# Open a session to syn Restful API
|
569
|
+
def OpenSession(customer,username,password)
|
570
|
+
# Set up our HTTP object with the required host and path
|
571
|
+
@url = URI.parse('https://api2.dynect.net/REST/Session/')
|
572
|
+
@headers = { "Content-Type" => 'application/json' }
|
573
|
+
@http = Net::HTTP.new(@url.host, @url.port)
|
574
|
+
@http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
575
|
+
@http.use_ssl = true
|
576
|
+
@session_data = { :customer_name => customer, :user_name => username, :password => password }
|
577
|
+
@resp, @data = @http.post(@url.path, @session_data.to_json, @headers)
|
578
|
+
@result = JSON.parse(@data)
|
579
|
+
if @result['status'] == 'success'
|
580
|
+
@auth_token = @result['data']['token']
|
581
|
+
else
|
582
|
+
puts "Command Failed:\n"
|
583
|
+
# the messages returned from a failed command are a list
|
584
|
+
@result['msgs'][0].each{|key, value| print key, " : ", value, "\n"}
|
585
|
+
exit(2)
|
586
|
+
end
|
587
|
+
return(@result)
|
588
|
+
end
|
589
|
+
# closing dyn session
|
590
|
+
def CloseSession
|
591
|
+
@url = URI.parse('https://api2.dynect.net/REST/Session/')
|
592
|
+
@resp, @data = @http.delete(@url.path, @headers)
|
593
|
+
end
|
594
|
+
# Check if the zone exist in dyn configuration
|
595
|
+
def CheckZone(zone)
|
596
|
+
@url = URI.parse("https://api2.dynect.net/REST/Zone/#{zone}/")
|
597
|
+
GetDyn()
|
598
|
+
if @result['status'] != "success"
|
599
|
+
abort("The zone name is invalid")
|
600
|
+
end
|
601
|
+
end
|
602
|
+
# Get List of nodes to compare with given node
|
603
|
+
def CheckNodes(zone,node,state)
|
604
|
+
@url = URI.parse("https://api2.dynect.net/REST/NodeList/#{zone}/")
|
605
|
+
GetDyn()
|
606
|
+
@nodes = []
|
607
|
+
@result['data'].each do |fqdn|
|
608
|
+
@nodes << fqdn
|
609
|
+
end
|
610
|
+
if state == "true"
|
611
|
+
if ! @nodes.include? node
|
612
|
+
abort("The node you entered does not exist")
|
613
|
+
end
|
614
|
+
elsif state == "false"
|
615
|
+
if @nodes.include? node
|
616
|
+
abort("The node you entered already exist")
|
617
|
+
end
|
618
|
+
end
|
619
|
+
end
|
620
|
+
def CheckARecord(zone,arecord)
|
621
|
+
@dynquery = URI.parse("https://api2.dynect.net/REST/ARecord/#{zone}/#{arecord}")
|
622
|
+
GetDyn()
|
623
|
+
end
|
624
|
+
def CheckCnameRecord(zone,cname)
|
625
|
+
@dynquery = URI.parse("https://api2.dynect.net/REST/CNAMERecord/#{zone}/#{cname}")
|
626
|
+
GetDyn()
|
627
|
+
end
|
628
|
+
# Adding new A record
|
629
|
+
def AddARecord(zone,arecord,ip)
|
630
|
+
@url = URI.parse("https://api2.dynect.net/REST/ARecord/#{zone}/#{arecord}")
|
631
|
+
@record_data = { :rdata => { :address => "#{ip}" }, :ttl => "0" }
|
632
|
+
PostDyn()
|
633
|
+
PublishDyn(zone)
|
634
|
+
end
|
635
|
+
# Generating or modifying Geo service
|
636
|
+
def GenerateGeoService(service,zone,record_data,flag)
|
637
|
+
@record_data = record_data
|
638
|
+
@url = URI.parse("https://api2.dynect.net/REST/Geo/#{service}/")
|
639
|
+
if flag == "create"
|
640
|
+
puts "Creating geo service"
|
641
|
+
PostDyn()
|
642
|
+
else
|
643
|
+
puts "Changing geo service"
|
644
|
+
PutDyn()
|
645
|
+
end
|
646
|
+
PublishDyn(zone)
|
647
|
+
end
|
648
|
+
# Generating geo node and attaching to service
|
649
|
+
def GenerateGeoNode(service,zone,geonode)
|
650
|
+
puts "Creating geo node"
|
651
|
+
@url = URI.parse("https://api2.dynect.net/REST/GeoNode/#{service}")
|
652
|
+
@record_data = { :fqdn => "#{geonode}", :zone => "#{zone}" }
|
653
|
+
PostDyn()
|
654
|
+
PublishDyn(zone)
|
655
|
+
end
|
656
|
+
# Adding Cname record
|
657
|
+
def AddCnameRecord(zone,cname,arecord,flag)
|
658
|
+
@url = URI.parse("https://api2.dynect.net/REST/CNAMERecord/#{zone}/#{cname}")
|
659
|
+
@record_data = { :rdata => { :cname => "#{arecord}" }, :ttl => "0" }
|
660
|
+
if (flag == "post")
|
661
|
+
puts "Adding cname record"
|
662
|
+
PostDyn()
|
663
|
+
elsif (flag == "put")
|
664
|
+
puts "Changing cname record"
|
665
|
+
PutDyn()
|
666
|
+
end
|
667
|
+
PublishDyn(zone)
|
668
|
+
end
|
669
|
+
# Adding txt record
|
670
|
+
def AddTxtRecord(zone,arecord,txt)
|
671
|
+
@url = URI.parse("https://api2.dynect.net/REST/TXTRecord/#{zone}/#{arecord}")
|
672
|
+
@record_data = { :rdata => { :txtdata => "#{txt}" }, :ttl => "0" }
|
673
|
+
PostDyn()
|
674
|
+
PublishDyn(zone)
|
675
|
+
end
|
676
|
+
# deleting node
|
677
|
+
def DeleteNode(zone,fqdn)
|
678
|
+
@url = URI.parse("https://api2.dynect.net/REST/Node/#{zone}/#{fqdn}")
|
679
|
+
DeleteDyn()
|
680
|
+
PublishDyn(zone)
|
681
|
+
end
|
682
|
+
# deleting service
|
683
|
+
def DeleteService(service,zone)
|
684
|
+
@url = URI.parse("https://api2.dynect.net/REST/Geo/#{service}/")
|
685
|
+
DeleteDyn()
|
686
|
+
PublishDyn(zone)
|
687
|
+
end
|
688
|
+
# get method to dyn
|
689
|
+
def GetDyn()
|
690
|
+
puts "Getting data from dyn"
|
691
|
+
@headers = { "Content-Type" => 'application/json', 'Auth-Token' => @auth_token }
|
692
|
+
@resp, @data = @http.get(@url.path, @headers)
|
693
|
+
@result = JSON.parse(@data)
|
694
|
+
return(@result)
|
695
|
+
end
|
696
|
+
# post method to dyn
|
697
|
+
def PostDyn()
|
698
|
+
@headers = { "Content-Type" => 'application/json', 'Auth-Token' => @auth_token }
|
699
|
+
@resp, @data = @http.post(@url.path, @record_data.to_json, @headers)
|
700
|
+
end
|
701
|
+
# put method to dyn
|
702
|
+
def PutDyn()
|
703
|
+
@headers = { "Content-Type" => 'application/json', 'Auth-Token' => @auth_token }
|
704
|
+
@resp, @data = @http.put(@url.path, @record_data.to_json, @headers)
|
705
|
+
end
|
706
|
+
def DeleteDyn()
|
707
|
+
@headers = { "Content-Type" => 'application/json', 'Auth-Token' => @auth_token }
|
708
|
+
@resp, @data = @http.delete(@url.path, @headers)
|
709
|
+
puts @data
|
710
|
+
end
|
711
|
+
# publishing data to dyn
|
712
|
+
def PublishDyn(zone)
|
713
|
+
puts "Publishing to Dyn"
|
714
|
+
@url = URI.parse("https://api2.dynect.net/REST/Zone/#{zone}/")
|
715
|
+
@publish_data = { "publish" => "true" }
|
716
|
+
@resp, @data = @http.put(@url.path, @publish_data.to_json, @headers)
|
717
|
+
@result = JSON.parse(@data)
|
718
|
+
puts @result['status']
|
719
|
+
end
|
720
|
+
# return list of geo service defined for the account
|
721
|
+
def GetServices()
|
722
|
+
puts "Getting the list of geo services"
|
723
|
+
@url = URI.parse("https://api2.dynect.net/REST/Geo/")
|
724
|
+
@result = GetDyn()
|
725
|
+
@services = @result['data']
|
726
|
+
@gservices = []
|
727
|
+
@services.each do |service|
|
728
|
+
@gservices << service.gsub(/\/REST\/Geo\/|\//,"")
|
729
|
+
end
|
730
|
+
return(@gservices)
|
731
|
+
end
|
732
|
+
def GetGeoData(service)
|
733
|
+
puts "Getting geo data"
|
734
|
+
@url = URI.parse("https://api2.dynect.net/REST/Geo/#{service}")
|
735
|
+
@result = GetDyn()
|
736
|
+
return(@result)
|
737
|
+
end
|
738
|
+
# checking to which gee service geo node is attached
|
739
|
+
def CheckNodeService(service,fqdn)
|
740
|
+
@url = URI.parse("https://api2.dynect.net/REST/Geo/#{service}")
|
741
|
+
@result = GetDyn()
|
742
|
+
@nodes = @result['data']['nodes']
|
743
|
+
@nodes.each do |node|
|
744
|
+
if (node['fqdn'] == "#{fqdn}")
|
745
|
+
puts "Yes!!!"
|
746
|
+
puts "here are all the nodes that linked to that service:"
|
747
|
+
PrintNodes(@nodes)
|
748
|
+
exit(0)
|
749
|
+
end
|
750
|
+
end
|
751
|
+
end
|
752
|
+
# Gets cname and zone and return the geo node that the cname point to
|
753
|
+
def GetCnameService(cname,zone)
|
754
|
+
@url = URI.parse("https://api2.dynect.net/REST/CNAMERecord/#{zone}/#{cname}/")
|
755
|
+
@result = GetDyn()
|
756
|
+
@cn_data = @result['data']
|
757
|
+
@cn_array = @cn_data[0].split("/")
|
758
|
+
@id = @cn_array.last
|
759
|
+
@url = URI.parse("https://api2.dynect.net/REST/CNAMERecord/#{zone}/#{cname}/#{@id}")
|
760
|
+
@result = GetDyn()
|
761
|
+
@geonode = @result['data']['rdata']['cname'].chomp('.')
|
762
|
+
return(@geonode)
|
763
|
+
end
|
764
|
+
def PrintNodes(nodes)
|
765
|
+
nodes.each do |node|
|
766
|
+
puts node['fqdn']
|
767
|
+
end
|
768
|
+
end
|
769
|
+
end
|
metadata
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dyntool
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 2
|
9
|
+
version: 0.0.2
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Ariel Moskovich
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2013-07-23 00:00:00 +03:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: Tool for manipulation dyn dns records
|
22
|
+
email: ariel@outbrain.com
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files: []
|
28
|
+
|
29
|
+
files:
|
30
|
+
- lib/dyntool.rb
|
31
|
+
has_rdoc: true
|
32
|
+
homepage: http://rubygems.org/gems/dyntool
|
33
|
+
licenses: []
|
34
|
+
|
35
|
+
post_install_message:
|
36
|
+
rdoc_options: []
|
37
|
+
|
38
|
+
require_paths:
|
39
|
+
- lib
|
40
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
41
|
+
requirements:
|
42
|
+
- - ">="
|
43
|
+
- !ruby/object:Gem::Version
|
44
|
+
segments:
|
45
|
+
- 0
|
46
|
+
version: "0"
|
47
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
48
|
+
requirements:
|
49
|
+
- - ">="
|
50
|
+
- !ruby/object:Gem::Version
|
51
|
+
segments:
|
52
|
+
- 0
|
53
|
+
version: "0"
|
54
|
+
requirements: []
|
55
|
+
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 1.3.6
|
58
|
+
signing_key:
|
59
|
+
specification_version: 3
|
60
|
+
summary: Dyn tools
|
61
|
+
test_files: []
|
62
|
+
|