cdncontrol 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,15 @@
1
+ ---
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2ZlOTNjMjAyYzc0ZDhlZmE3MTMzNDdkMjBmMzgyMmI2NzAyNGY0ZA==
5
+ data.tar.gz: !binary |-
6
+ NDc2OWY3OTk1YjJlM2E1NzM4ODA1NGUzMjM4ZGY1NTgwZDE1ODNjNw==
7
+ SHA512:
8
+ metadata.gz: !binary |-
9
+ Y2ZlYTRlOWJmNWMyOTFlMDY3YzhjYzhmYjAzMGExYTAyYmYwYWNjN2JiZDgz
10
+ MTQzY2U1N2E2MmM3NDI2NzViM2UxNjVjYjdjNmM4NjVmMmYyYjNiMGY4ZWYy
11
+ OTFjY2MzM2E4NWY3Y2I3NThjOWYyZDRiNmQyNzkwYTgyZjQwMTc=
12
+ data.tar.gz: !binary |-
13
+ MjYwN2U0OTM3MDdkZDlkMGNmZGY5ZTAyY2UzMzY0ZTZiMzkxZDM2MmY3YjVi
14
+ NzYxYTZmYzlhOWY2ZGQ2NWIyNDk2ZTdjNjQ5OGNlNTgyNmU2ZGYzOTU5Yzc1
15
+ Y2EwMTY2MzNkODg4MTdiZmU5YTk4ZjI4MDFlMjQ3NjZiNTg5MjY=
@@ -0,0 +1,4 @@
1
+ cdncontrol.conf
2
+ .idea
3
+ Gemfile.lock
4
+ *.gem
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source :rubygems
2
+
3
+ gemspec
@@ -0,0 +1,27 @@
1
+ CDNControl
2
+ ----------
3
+ * Author:: Jon Cowie (<jcowie@etsy.com>), Marcus Barczak (<mbarczak@etsy.com>), Avleen Vig (<avig@etsy.com>)
4
+ * Copyright:: Copyright (c) 2013 Etsy Inc
5
+ * License:: MIT
6
+
7
+ The MIT License
8
+
9
+ Copyright (c) 2004 Stan Salvador (stansalvador@hotmail.com), Philip Chan (pkc@cs.fit.edu)
10
+
11
+ Permission is hereby granted, free of charge, to any person obtaining a copy
12
+ of this software and associated documentation files (the "Software"), to deal
13
+ in the Software without restriction, including without limitation the rights
14
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15
+ copies of the Software, and to permit persons to whom the Software is
16
+ furnished to do so, subject to the following conditions:
17
+
18
+ The above copyright notice and this permission notice shall be included in
19
+ all copies or substantial portions of the Software.
20
+
21
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27
+ THE SOFTWARE.
@@ -0,0 +1,190 @@
1
+ CDNControl
2
+ ===========
3
+ CDNControl is a rubygem which provides an interface to Dyn's GSLB service. It's used by Etsy to control the balance of traffic between our CDN providers, and also to enable or disable individual CDNs.
4
+
5
+ Installation
6
+ ------------
7
+
8
+ ### Gem Install
9
+ `cdncontrol` is available on rubygems. Add the following to your `Gemfile`:
10
+
11
+ ```ruby
12
+ gem 'cdncontrol'
13
+ ```
14
+
15
+ or install the gem manually:
16
+
17
+ ```bash
18
+ gem install cdncontrol
19
+ ```
20
+
21
+ The gem installs the *cdncontrol* binary at ```/usr/bin/cdncontrol```
22
+ CDNControl Configuration
23
+ -------------------
24
+ CDNControl requires a configuration file in order to function, which needs to be in ```/usr/local/etc/cdncontrol.conf```
25
+
26
+
27
+ Below is a sample config file with all supported options included, followed by an explanation of each section.
28
+
29
+ ```yaml
30
+ organization: "myorganisation"
31
+ username: "username"
32
+ password: "password"
33
+ output_path: "/var/www"
34
+ cdncontrol_ui_hostname: "http://cdn.mydomain.com"
35
+
36
+
37
+ valid_providers:
38
+ - provider1
39
+ - provider2
40
+ - provider3
41
+
42
+ targets:
43
+ target1:
44
+ zone: myzone.com
45
+ nodes:
46
+ - 1.myzone.com
47
+ - 2.myzone.com
48
+ - 3.myzone.com
49
+ - 4.myzone.com
50
+ graph_url: "<your_graphite_cdn_metric_url>"
51
+ graph_color_key:
52
+ provider1: "#FF7400"
53
+ provider2: "#1240AB"
54
+ provider3: "#00CC00"
55
+ provider4: "#380470"
56
+
57
+ ```
58
+
59
+ #### Organization
60
+ The `organization` directive specifies the customer name you use when logging into the DynECT portal
61
+
62
+ ####Username
63
+ The `username` directive specifies the username to use when authenticating to the Dyn API.
64
+
65
+ ####Password
66
+ The `password` directive specifies the password to use when authenticating to the Dyn API.
67
+
68
+ ####Output Path
69
+ The `output_path` directive specifies where cdncontrol should dump JSON containing the CDN balances.
70
+
71
+ ####CDNControl UI Hostname (Optional)
72
+ The `cdncontrol_ui_hostname` directive specifies the hostname where the CDNControlUI web application can be reached, if you're using it.
73
+
74
+ ####Valid Providers
75
+ The `valid_providers` section specifies the valid CDN providers which may be configured with this tool. This corresponds to the names of the global pools you have configured on the Dyn GSLB platform.
76
+
77
+ ####Targets
78
+ The `targets` section of the config file lists the different site configurations you want to use cdncontrol to manage. The following are the parameters which can be used to configure a target (in this case, we're looking at the parameters of *target1* above:
79
+
80
+ * **zone**: This is the name used to configure the site in Dyn's GSLB platform. In the DynECT web interface, this is the top-level site from which all of your nodes are configured
81
+ * **nodes**: These are the nodes under the zone which are configured to use GSLB. For example, if your zone is *mydomain.com*, you might configure GSLB for *img0.mydomain.com* and *img1.mydomain.com*. These should all be specified here.
82
+ * **graph_url** (optional): If you're using the CDNControlUI web interface to this tool, this option lets you specify a graph_url to be displayed on the page for this target.
83
+ * **graph_color_key** (optional): If you're using the CDNControlUI web interface to this tool, this option lets you specify a color key to be displayed above the graph (to indicate which CDN is which color, for example).
84
+
85
+
86
+
87
+ CDNControl Usage
88
+ ================
89
+
90
+ ### Supported Options
91
+ ```
92
+ $> cdncontrol
93
+ Usage: cdncontrol [-tpwmcsav]
94
+ Please specify the command in one of the following formats:
95
+
96
+ cdncontrol -t TARGET --show
97
+ cdncontrol -t TARGET --write
98
+ cdncontrol -t TARGET -p PROVIDER -w WEIGHT
99
+ cdncontrol -t TARGET -p PROVIDER -m MODE
100
+
101
+ Specific options:
102
+ -t, --target The configuration to work on (one of <targets specified in your config file>)
103
+ -p, --provider Provider to modify (one of <providers specified in your config file>)
104
+ -w, --weight Weight of traffic to send to provider (value between 1 and 15)
105
+ -m, --mode Set the serve mode of the provider (one of always,obey,remove,no)
106
+ -c, --cname Target CNAME for new provider
107
+ -s, --show Show current provider ratios
108
+ -v, --verbose Show me in excrutiating detail what is happening
109
+ --write Dump all weights out to JSON files
110
+ ```
111
+
112
+ ### Viewing target details
113
+ ```
114
+ $> cdncontrol -t test --show
115
+
116
+ ** connecting to dynect API
117
+ ** fetching node details .......done!
118
+
119
+ NODE BALANCE
120
+ ============
121
+ img0.mydomain.com
122
+ provider1 weight = 15 | serve_mode = always | status = up | address = cdn.provider1.com.
123
+ provider2 weight = 15 | serve_mode = always | status = up | address = cdn.provider2.com.
124
+ provider3 weight = 15 | serve_mode = always | status = up | address = cdn.provider3.com.
125
+ ```
126
+
127
+ ### Writing target details as JSON
128
+ ```
129
+ $ cdncontrol -t test --write
130
+ ** connecting to dynect API
131
+ ** fetching node details .......done!
132
+ ** Updated details in /var/www/cdn_test.json
133
+ ```
134
+
135
+ ### Setting the weight of a target's provider
136
+ ```
137
+ $> cdncontrol -t test -p provider1 -w 5
138
+ ** connecting to dynect API
139
+ ** fetching node details .......done!
140
+
141
+ CURRENT LIVE WEIGHTS
142
+ ====================
143
+ img0.mydomain.com
144
+ provider1 weight = 15 | serve_mode = always | status = up | address = cdn.provider1.com.
145
+ provider2 weight = 15 | serve_mode = always | status = up | address = cdn.provider2.com.
146
+ provider3 weight = 15 | serve_mode = always | status = up | address = cdn.provider3.com.
147
+
148
+ You're about to modify the weight of provider1 to 5 are you sure (Y|N)? Y
149
+
150
+ ** setting weight = 5 on GSLBRegionPoolEntry/myorg-mydomain.com/img0.mydomain.com/global/cdn.provider1.com.
151
+
152
+ ** fetching node details .......done!
153
+
154
+ NODE WEIGHTS AFTER CHANGE
155
+ =========================
156
+ img0.mydomain.com
157
+ provider1 weight = 5 | serve_mode = always | status = up | address = cdn.provider1.com.
158
+ provider2 weight = 15 | serve_mode = always | status = up | address = cdn.provider2.com.
159
+ provider3 weight = 15 | serve_mode = always | status = up | address = cdn.provider3.com.
160
+
161
+ ** Updated details in /var/www/cdn_test.json
162
+ ```
163
+
164
+ ### Setting the mode of a target's provider
165
+ ```
166
+ cdncontrol -t test -p provider1 -m no
167
+ ** connecting to dynect API
168
+ ** fetching node details .......done!
169
+
170
+ CURRENT SERVE MODES AND WEIGHTS
171
+ ===============================
172
+ img0.mydomain.com
173
+ provider1 weight = 15 | serve_mode = always | status = up | address = cdn.provider1.com.
174
+ provider2 weight = 15 | serve_mode = always | status = up | address = cdn.provider2.com.
175
+ provider3 weight = 15 | serve_mode = always | status = up | address = cdn.provider3.com.
176
+
177
+ You're about to change the serving mode for provider1 to 'no' are you sure (Y|N)? Y
178
+
179
+ ** setting serve_mode = no on GSLBRegionPoolEntry/myorg-mydomain.com/img0.mydomain.com/global/cdn.provider1.com.
180
+ ** fetching node details .......done!
181
+
182
+ NODE SERVE MODES AFTER CHANGE
183
+ =============================
184
+ img0.mydomain.com
185
+ provider1 weight = 15 | serve_mode = no | status = up | address = cdn.provider1.com.
186
+ provider2 weight = 15 | serve_mode = always | status = up | address = cdn.provider2.com.
187
+ provider3 weight = 15 | serve_mode = always | status = up | address = cdn.provider3.com.
188
+
189
+ ** Updated details in /var/www/cdn_test.json
190
+ ```
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require 'bundler/gem_tasks'
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'choice'
4
+ require 'json'
5
+ require 'yaml'
6
+ require 'pp'
7
+ require 'cdncontrol/trafficmanager'
8
+
9
+ CONFIG = YAML.load_file("/usr/local/etc/cdncontrol.conf")
10
+
11
+ # TODO: this should be dynamic
12
+ VALID_PROVIDERS = CONFIG["valid_providers"]
13
+ VALID_MODES = CONFIG["valid_modes"] || [ "always", "obey", "remove", "no" ]
14
+ OUTPUT_PATH = CONFIG["output_path"] || "/tmp"
15
+ VALID_TARGETS = CONFIG["targets"].keys
16
+ options = { show: false, add: false, verbose: false }
17
+
18
+ Choice.options do
19
+ header "Please specify the command in one of the following formats:"
20
+ header ""
21
+ header "cdncontrol -t TARGET --show"
22
+ header "cdncontrol -t TARGET --write"
23
+ header "cdncontrol -t TARGET -p PROVIDER -w WEIGHT"
24
+ header "cdncontrol -t TARGET -p PROVIDER -m MODE"
25
+ header ""
26
+ header "Specific options:"
27
+
28
+ option :target, :required => false do
29
+ short '-t'
30
+ long '--target'
31
+ desc "The configuration to work on (one of #{VALID_TARGETS.join(",")})"
32
+ validate /^(#{VALID_TARGETS.join("|")})$/
33
+ end
34
+
35
+ option :provider, :required => false do
36
+ short '-p'
37
+ long '--provider'
38
+ desc "Provider to modify (one of #{VALID_PROVIDERS.join(",")})"
39
+ validate /^(#{VALID_PROVIDERS.join("|")})$/
40
+ end
41
+
42
+ option :weight, :required => false do
43
+ short '-w'
44
+ long '--weight'
45
+ desc 'Weight of traffic to send to provider (value between 1 and 15)'
46
+ validate /^([1-9]|1[0-5])$/
47
+ end
48
+
49
+ option :mode, :required => false do
50
+ short '-m'
51
+ long '--mode'
52
+ desc "Set the serve mode of the provider (one of #{VALID_MODES.join(",")})"
53
+ validate /^(#{VALID_MODES.join("|")})$/
54
+ end
55
+
56
+ option :show, :required => false do
57
+ short '-s'
58
+ long '--show'
59
+ desc 'Show current provider ratios'
60
+ end
61
+
62
+ option :verbose, :required => false do
63
+ short '-v'
64
+ long '--verbose'
65
+ desc 'Show me in excrutiating detail what is happening'
66
+ end
67
+
68
+
69
+ option :write, :required => false do
70
+ long '--write'
71
+ desc 'Dump all weights out to JSON files for the dashboard'
72
+ end
73
+ end
74
+
75
+ options[:provider] = Choice.choices[:provider] unless !Choice.choices[:provider]
76
+ options[:target] = Choice.choices[:target] unless !Choice.choices[:target]
77
+ options[:mode] = Choice.choices[:mode] unless !Choice.choices[:mode]
78
+ options[:weight] = Choice.choices[:weight] unless !Choice.choices[:weight]
79
+ options[:show] = Choice.choices[:show] unless !Choice.choices[:show]
80
+ options[:verbose] = Choice.choices[:verbose] unless !Choice.choices[:verbose]
81
+ options[:write] = Choice.choices[:write] unless !Choice.choices[:write]
82
+
83
+ unless (options.has_key?(:target) && options[:show]) ||
84
+ (options.has_key?(:target) && options.has_key?(:write)) ||
85
+ (options.has_key?(:target) && options.has_key?(:provider) && options.has_key?(:weight)) ||
86
+ (options.has_key?(:target) && options.has_key?(:provider) && options.has_key?(:mode))
87
+ Choice.help
88
+ end
89
+
90
+ # trap SIGINT and return a clean exit message rather than stack trace
91
+ Signal.trap('INT') {
92
+ printf "\nAborting!\n"
93
+ exit
94
+ }
95
+
96
+ ## action starts here
97
+
98
+ target = CONFIG['targets'][options[:target]]
99
+
100
+ tm = CDNControl::TrafficManager.new(CONFIG,target, options[:verbose])
101
+
102
+ if options[:show]
103
+ tm.show_balance
104
+ end
105
+
106
+ if options[:write]
107
+ tm.dump_weights(options[:target],OUTPUT_PATH)
108
+ end
109
+
110
+ if options.has_key?(:provider) && options.has_key?(:weight)
111
+ tm.show_balance("CURRENT LIVE WEIGHTS")
112
+ tm.set_weight(options[:provider], options[:weight])
113
+ tm.show_balance("NODE WEIGHTS AFTER CHANGE")
114
+ tm.dump_weights(options[:target],OUTPUT_PATH)
115
+
116
+ end
117
+
118
+ if options.has_key?(:provider) && options.has_key?(:mode)
119
+ tm.show_balance("CURRENT SERVE MODES AND WEIGHTS")
120
+ tm.set_serve_mode(options[:provider], options[:mode])
121
+ tm.show_balance("NODE SERVE MODES AFTER CHANGE")
122
+ tm.dump_weights(options[:target],OUTPUT_PATH)
123
+ end
124
+
125
+ # display a nag if configured
126
+ if options[:show] != true && CONFIG['targets'][options[:target]].has_key?('nag')
127
+ puts "** NOTE: #{CONFIG['targets'][options[:target]]['nag']}"
128
+ end
@@ -0,0 +1,26 @@
1
+ organization: "myorganisation"
2
+ username: "username"
3
+ password: "password"
4
+ output_path: "/var/www"
5
+ cdncontrol_ui_hostname: "http://cdn.mydomain.com"
6
+
7
+
8
+ valid_providers:
9
+ - provider1
10
+ - provider2
11
+ - provider3
12
+
13
+ targets:
14
+ target1:
15
+ zone: myzone.com
16
+ nodes:
17
+ - 1.myzone.com
18
+ - 2.myzone.com
19
+ - 3.myzone.com
20
+ - 4.myzone.com
21
+ graph_url: "<your_graphite_cdn_metric_url>"
22
+ graph_color_key:
23
+ provider1: "#FF7400"
24
+ provider2: "#1240AB"
25
+ provider3: "#00CC00"
26
+ provider4: "#380470"
@@ -0,0 +1,21 @@
1
+ $:.push File.expand_path('../lib', __FILE__)
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = 'cdn_control'
5
+ gem.version = '0.0.9'
6
+ gem.authors = ["Jon Cowie", "Marcus Barczak"]
7
+ gem.email = 'jonlives@gmail.com'
8
+ gem.homepage = 'https://github.com/etsy/cdncontrol'
9
+ gem.summary = "Tool for managing multiple CDN balances on Dyn's GSLB"
10
+ gem.description = "Tool for managing multiple CDN balances on Dyn's GSLB"
11
+
12
+ gem.files = `git ls-files`.split($\)
13
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
14
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
15
+ gem.name = "cdncontrol"
16
+ gem.require_paths = ["lib"]
17
+
18
+ gem.add_runtime_dependency 'dynect_rest', '>= 0.4.3'
19
+ gem.add_runtime_dependency 'choice'
20
+ gem.add_runtime_dependency 'app_conf'
21
+ end
@@ -0,0 +1,297 @@
1
+ require 'app_conf'
2
+ require 'json'
3
+ require 'dynect_rest'
4
+
5
+ module CDNControl
6
+ class TrafficManager
7
+
8
+ # The initialize method for the TrafficManager Class.
9
+ # Expects:
10
+ # config: Valid config in YAML format
11
+ # target: The target from the config which this instance is to be used with (String)
12
+ # verbose (optional): Whether or not to log verbosely (Boolean)
13
+ # Returns:
14
+ # nothing
15
+ def initialize(config,target, verbose=false)
16
+ @config=config
17
+ @zone = target['zone']
18
+ @nodes = target['nodes']
19
+ @verbose = verbose
20
+ @weights = Hash.new
21
+ @user = nil
22
+
23
+ if @config['eventinator_server']
24
+ require 'eventinator-client'
25
+ end
26
+
27
+ # connect to API
28
+ puts "** connecting to dynect API"
29
+ @dyn = DynectRest.new(@config['organization'], @config['username'], @config['password'], @zone)
30
+ @weights = fetch_weights
31
+ end
32
+
33
+ def eventinate(msg)
34
+ if @config['eventinator_server']
35
+ client = EventinatorClient.new @config['eventinator_server']
36
+
37
+ if !@user.nil?
38
+ user = @user
39
+ else
40
+ user = ENV['SUDO_USER'] || ENV['USER']
41
+ end
42
+
43
+ puts "User: #{user}"
44
+ payload = {
45
+ :status => msg,
46
+ :username => user,
47
+ :tag => "cdncontrol"
48
+ }
49
+
50
+ begin
51
+ client.create_oneshot(payload)
52
+ rescue
53
+ puts "** Couldn't reach the eventinator server, not eventinating"
54
+ end
55
+ end
56
+ end
57
+
58
+ # Mutator method for the @user global
59
+ # Expects:
60
+ # user: Username to set (String)
61
+ # Returns:
62
+ # nothing
63
+ def set_user(user)
64
+ @user = user
65
+ end
66
+
67
+ # Method to get a list of CDN providers from Dyn
68
+ # Expects:
69
+ # nothing
70
+ # Returns:
71
+ # Array of strings
72
+ def get_providers
73
+ @weights.map{|k,v|v.keys}.flatten.uniq
74
+ end
75
+
76
+ # Accessor method for the @weights global
77
+ # Expects:
78
+ # nothing
79
+ # Returns:
80
+ # Hash of {string,int}
81
+ def get_weights
82
+ @weights
83
+ end
84
+
85
+ # Get list of nodes configured for this target
86
+ # Expects:
87
+ # nothing
88
+ # Returns:
89
+ # Array of strings
90
+ def get_nodes
91
+ @weights.keys
92
+ end
93
+
94
+ # Method to get weights from Dyn's API
95
+ # Expects:
96
+ # nothing
97
+ # Returns:
98
+ # Hash of {string,int}
99
+ def fetch_weights
100
+ weights = {}
101
+
102
+ print "** fetching node details "
103
+ nodes_queue = Queue.new
104
+ @nodes.each do |node|
105
+ weights[node] = {}
106
+ nodes_queue << node
107
+ end
108
+
109
+ threads = []
110
+ nodes_queue.size.times do |i|
111
+ threads << Thread.new do
112
+ node = nodes_queue.pop
113
+ path = "GSLBRegionPoolEntry/#{@zone}/#{node}/global"
114
+
115
+ if @verbose
116
+ puts "** fetching #{path}"
117
+ else
118
+ print "."
119
+ end
120
+
121
+ # Make a thread-local connection to dyn, so that we open many
122
+ # connections at once.
123
+ dyn_conn = DynectRest.new('etsy', @config['username'], @config['password'], @zone)
124
+ pool = dyn_conn.get(path)
125
+
126
+ pool.each do |address|
127
+ address.gsub!("\/REST\/", "")
128
+
129
+ if @verbose
130
+ puts " ** fetching #{address}"
131
+ else
132
+ print "."
133
+ end
134
+
135
+ address_detail = dyn_conn.get(address)
136
+ label = address_detail['label']
137
+ weights[node][label] = address_detail
138
+ end
139
+ end
140
+ end
141
+ threads.each(&:join)
142
+ print "done!\n" unless @verbose
143
+
144
+ @weu
145
+ weights
146
+ end
147
+
148
+ # Method to show current balance
149
+ # Expects:
150
+ # nothing
151
+ # Returns:
152
+ # nothing (prints to screen)
153
+ def show_balance(header = "NODE BALANCE")
154
+
155
+ puts "\n#{header}"
156
+ puts "=" * header.length
157
+
158
+ @weights.each do |node,providers|
159
+ puts "#{node}"
160
+ providers.each do |label,detail|
161
+ printf " %-12s weight = %2d | serve_mode = %-8s | status = %-4s | address = %s\n",
162
+ label, detail['weight'], detail['serve_mode'], detail['status'], detail['address']
163
+ end
164
+ end
165
+
166
+ puts ""
167
+ end
168
+
169
+ # Method to set weight for a provider
170
+ # Expects:
171
+ # provider: Provider to set weight for (String)
172
+ # weight: Weight to set provider to (Int)
173
+ # safe: Whether or not to prompt to confirmation (Boolean, default to true)
174
+ # Returns:
175
+ # nothing
176
+ def set_weight(provider, weight, safe=true)
177
+ get_yn("You're about to modify the weight of #{provider} to #{weight} are you sure (Y|N)?") unless safe == false
178
+ # do it
179
+ @nodes.each do |node|
180
+ old_weight = @weights[node][provider]['weight']
181
+ address = @weights[node][provider]['address']
182
+
183
+ if weight == old_weight
184
+ puts "** node #{node} weight is already #{old_weight} no change made"
185
+ else
186
+ path = "GSLBRegionPoolEntry/#{@zone}/#{node}/global/#{address}"
187
+ puts "** setting weight = #{weight} on #{path}"
188
+ @dyn.put(path, { "weight" => weight })
189
+
190
+ eventinate("modified weight of #{provider} to #{weight} for '#{node}'")
191
+ end
192
+ end
193
+
194
+ puts ""
195
+
196
+ # fetch the updated values from dyn
197
+ @weights = fetch_weights
198
+ end
199
+
200
+ # Method to set mode for a provider
201
+ # Expects:
202
+ # provider: Provider to set weight for (String)
203
+ # mode: Mode to set provider to (String)
204
+ # safe: Whether or not to prompt to confirmation (Boolean, default to true)
205
+ # Returns:
206
+ # nothing
207
+ def set_serve_mode(provider, mode, safe=true)
208
+ get_yn("You're about to change the serving mode for #{provider} to '#{mode}' are you sure (Y|N)?") unless safe == false
209
+
210
+ # do it
211
+ @nodes.each do |node|
212
+ old_mode = @weights[node][provider]['serve_mode']
213
+ address = @weights[node][provider]['address']
214
+
215
+ if mode == old_mode
216
+ puts "** node #{node} serve mode is already set to '#{old_mode}'"
217
+ else
218
+ path = "GSLBRegionPoolEntry/#{@zone}/#{node}/global/#{address}"
219
+ puts "** setting serve_mode = #{mode} on #{path}"
220
+ @dyn.put(path, { "serve_mode" => mode })
221
+
222
+ eventinate("modified serve_mode of #{provider} from '#{old_mode}' to '#{mode}' on #{node}")
223
+ end
224
+ end
225
+
226
+ # fetch the updated values from dyn
227
+ @weights = fetch_weights
228
+ end
229
+
230
+ # Method to set dump current weights to JSON
231
+ # Expects:
232
+ # target: Target of which to dump weights (String)
233
+ # output_path: File path to dump JSON files to
234
+ # Returns:
235
+ # nothing
236
+ def dump_weights(target,output_path)
237
+ ## jankiest thing that will work development approach
238
+
239
+ summary = {}
240
+
241
+ # assetion here is every node in the target group has same weight (should be true)
242
+ key = @weights.keys.first
243
+ @weights[key].each do |provider, config|
244
+ enabled = config["serve_mode"] != "no" ? true : false
245
+ weight = config["weight"]
246
+ summary[provider] = { :enabled => enabled, :weight => weight }
247
+ end
248
+
249
+ total_weight = 0
250
+ # calculate percentages
251
+ summary.each do |provider,config|
252
+ if config[:enabled]
253
+ total_weight += config[:weight]
254
+ end
255
+ end
256
+
257
+ summary.each do |provider,config|
258
+ if config[:enabled]
259
+ pct = (config[:weight].to_f / total_weight) * 100
260
+ else
261
+ pct = 0
262
+ end
263
+ summary[provider][:pct] = pct
264
+ end
265
+
266
+ fn = "#{output_path}/cdn_#{target}.json"
267
+
268
+ begin
269
+ File.open(fn, 'w') {|f| f.write(summary.to_json) }
270
+ rescue Exception => e
271
+ puts "** WARNING: was unable to update JSON (#{e.message}), dashboards will be inconsistent"
272
+ else
273
+ puts "** Updated details in #{fn}"
274
+ end
275
+ end
276
+
277
+ # Helper method to get y/n response
278
+ # Expects:
279
+ # message: Message for y/n prompt (String)
280
+ # Returns:
281
+ # nothing
282
+ def get_yn(message)
283
+ while true
284
+ print "#{message} "
285
+ case STDIN.gets.strip
286
+ when 'N', 'n'
287
+ puts "Aborting!"
288
+ exit
289
+ when 'Y', 'y'
290
+ puts ""
291
+ break
292
+ end
293
+ end
294
+ end
295
+
296
+ end
297
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: cdncontrol
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.9
5
+ platform: ruby
6
+ authors:
7
+ - Jon Cowie
8
+ - Marcus Barczak
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2013-11-14 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: dynect_rest
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - ! '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 0.4.3
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ! '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 0.4.3
28
+ - !ruby/object:Gem::Dependency
29
+ name: choice
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - ! '>='
33
+ - !ruby/object:Gem::Version
34
+ version: '0'
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - ! '>='
40
+ - !ruby/object:Gem::Version
41
+ version: '0'
42
+ - !ruby/object:Gem::Dependency
43
+ name: app_conf
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - ! '>='
47
+ - !ruby/object:Gem::Version
48
+ version: '0'
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - ! '>='
54
+ - !ruby/object:Gem::Version
55
+ version: '0'
56
+ description: Tool for managing multiple CDN balances on Dyn's GSLB
57
+ email: jonlives@gmail.com
58
+ executables:
59
+ - cdncontrol
60
+ extensions: []
61
+ extra_rdoc_files: []
62
+ files:
63
+ - .gitignore
64
+ - Gemfile
65
+ - LICENSE.md
66
+ - README.md
67
+ - Rakefile
68
+ - bin/cdncontrol
69
+ - cdncontrol.conf.example
70
+ - cdncontrol.gemspec
71
+ - lib/cdncontrol/trafficmanager.rb
72
+ homepage: https://github.com/etsy/cdncontrol
73
+ licenses: []
74
+ metadata: {}
75
+ post_install_message:
76
+ rdoc_options: []
77
+ require_paths:
78
+ - lib
79
+ required_ruby_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ! '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ required_rubygems_version: !ruby/object:Gem::Requirement
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 2.1.10
92
+ signing_key:
93
+ specification_version: 4
94
+ summary: Tool for managing multiple CDN balances on Dyn's GSLB
95
+ test_files: []