ncc-api 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 21ef6133b98ada6201561ea8663c154440c67466
4
+ data.tar.gz: 471fa9289f03247944859d225e3e4c2c0b10f1f5
5
+ SHA512:
6
+ metadata.gz: eb895ca7b2f897899ef0082a5ef3d7f705fdb42524ef66a66bdfc0da1004b9d3ffd1125a92e59f3abce60c63f0310d9325528f0005cf3fc53d0a4cf8a10272d5
7
+ data.tar.gz: aafb44f8fa87becc08dd41dc1975598e55ef49f96c6fe34acef56d19d560b2d335515b9f7deb5fc8309b872405b01a23f1f5adb3185dd657057ee7148180fb96
data/bin/ncc-api ADDED
@@ -0,0 +1,62 @@
1
+ #!/bin/bash
2
+ # /* Copyright 2013 Proofpoint, Inc. All rights reserved.
3
+ # Copyright 2014 Evernote Corporation. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # */
17
+
18
+
19
+ app_path="${1:-$(dirname $0)/..}"
20
+ launchwith="${2:-rackup}"
21
+ rack_environment="${3:-development}"
22
+
23
+ for f in etc/ncc-api.ru lib/ncc.rb
24
+ do
25
+ if [ ! -f "$app_path/$f" ]
26
+ then
27
+ echo "Required file $app_path/$f not found" >&2
28
+ exit 1
29
+ fi
30
+ done
31
+
32
+ export NCCAPI_HOME="$app_path"
33
+
34
+ if [ "$launchwith" = rackup ]
35
+ then
36
+ # Rackup-based launch (default)
37
+ rackup="${RACKUP_PATH:-rackup}"
38
+
39
+ if [ ! -x "$rackup" ]
40
+ then
41
+ echo "Can't find rackup (no $rackup)" >&2
42
+ exit 2
43
+ fi
44
+
45
+ echo "$rackup" -p 9292 -I"$app_path/lib" -E "$rack_environment" "$app_path/etc/ncc-api.ru"
46
+ "$rackup" -p 9292 -I"$app_path/lib" -E "$rack_environment" "$app_path/etc/ncc-api.ru"
47
+ elif [ "$launchwith" = unicorn ]
48
+ then
49
+ unicorn="${UNICORN_PATH:-unicorn}"
50
+
51
+ if [ ! -x "$unicorn" ]
52
+ then
53
+ echo "Can't find unicorn (no $unicorn)" >&2
54
+ exit 2
55
+ fi
56
+ echo "$unicorn" -I"$app_path/lib" -D -E "$rack_environment" -c "$app_path/etc/unicorn.cfg" "$app_path/etc/ncc-api.ru"
57
+ "$unicorn" -I"$app_path/lib" -D -E "$rack_environment" -c "$app_path/etc/unicorn.cfg" "$app_path/etc/ncc-api.ru"
58
+ else
59
+ # TODO: Need to specify environment here
60
+ echo "Can't launch with $launchwith" >&2
61
+ exit 3
62
+ fi
data/lib/ncc/config.rb ADDED
@@ -0,0 +1,207 @@
1
+ #!ruby
2
+ # /* Copyright 2013 Proofpoint, Inc. All rights reserved.
3
+ # Copyright 2014 Evernote Corporation. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # */
17
+
18
+
19
+ require 'rubygems'
20
+ require 'json'
21
+
22
+ class NCC
23
+
24
+ end
25
+
26
+ class NCC::Config
27
+ include Enumerable
28
+
29
+ Infinite = +1.0/0.0 # Not really *math*, per se, but Lewis
30
+ # Carroll would have liked it
31
+ # -jbrinkley/20130403
32
+
33
+ attr_reader :mtime, :file
34
+
35
+ def initialize(source = ["/etc/ncc-api",
36
+ "#{ENV['NCCAPI_HOME']}/etc"], opt={})
37
+ @opt = opt
38
+ @file = { }
39
+ @mtime = nil
40
+ source = [source] unless source.respond_to? :select
41
+ @file = source.select { |f| File.exist? f }.first
42
+ unless @file
43
+ raise ArgumentError.new("Can't locate configuration in " +
44
+ "#{source.inspect}")
45
+ end
46
+ debug "Creating configuration from #{@file}"
47
+ update_config
48
+ end
49
+
50
+ def opt(optname)
51
+ if @opt.has_key? optname
52
+ @opt[optname]
53
+ else
54
+ nil
55
+ end
56
+ end
57
+
58
+ def update_config(tolerant=false)
59
+ debug "updating config"
60
+ if File.directory? @file
61
+ debug "#{@file} is a directory"
62
+ @data ||= { }
63
+ data = { }
64
+ Dir.open(@file) do |dirh|
65
+ @mtime = File.stat(@file).mtime
66
+ debug "storing mtime: #{@mtime}"
67
+ dirh.each do |entry|
68
+ debug "considering #{entry}"
69
+ next if entry[0] == "."[0]
70
+ if File.directory? File.join(@file, entry) or
71
+ m = /(.*)\.conf$/.match(entry)
72
+ debug "#{entry} is further configuration"
73
+ key = m.nil? ? entry.intern : m[1]
74
+ if @data.has_key? key
75
+ data[key] = @data[key]
76
+ else
77
+ data[key] =
78
+ NCC::Config.new(File.join(@file, entry),
79
+ @opt)
80
+ end
81
+ end
82
+ end
83
+ end
84
+ @data = data
85
+ else
86
+ debug "#{@file} is not a directory"
87
+ begin
88
+ File.open(@file, 'r') do |fh|
89
+ @mtime = fh.stat.mtime
90
+ @data = JSON.load(fh)
91
+ end
92
+ rescue Errno::ENOENT
93
+ @mtime = Time.now
94
+ @data = { }
95
+ rescue JSON::ParserError => err
96
+ do_warn "Error parsing JSON in #{@file}, not updating config"
97
+ end
98
+ end
99
+ end
100
+
101
+ def do_warn(msg)
102
+ if opt :logger
103
+ opt(:logger).warn msg
104
+ end
105
+ end
106
+
107
+ def debug(msg)
108
+ if opt(:logger) and opt(:logger).respond_to? :debug
109
+ opt(:logger).debug "#<#{me}>: #{msg}"
110
+ end
111
+ end
112
+
113
+ def me
114
+ "#{self.class}:#{@file}"
115
+ end
116
+
117
+ def to_s
118
+ "#<#{me} #{@data.inspect}>"
119
+ end
120
+
121
+ def to_hash(*keys)
122
+ update_config unless current?
123
+ if keys.length > 0
124
+ Hash[
125
+ @data.select do |k, v|
126
+ keys.include? k
127
+ end.map { |k, v| [k, value_of(v)] }
128
+ ]
129
+ else
130
+ Hash[
131
+ @data.map { |k, v| [k, value_of(v)] }
132
+ ]
133
+ end
134
+ end
135
+
136
+ def to_array(*keys)
137
+ update_config unless current?
138
+ if keys.length > 0
139
+ @data.select do |k, v|
140
+ keys.include? k
141
+ end.map { |k, v| value_of(v) }
142
+ else
143
+ @data.map { |k, v| value_of(v) }
144
+ end
145
+ end
146
+
147
+ def value_of(v)
148
+ if v.respond_to? :to_hash
149
+ v.to_hash
150
+ else
151
+ v
152
+ end
153
+ end
154
+
155
+ def to_json
156
+ self.to_hash.to_json
157
+ end
158
+
159
+ def current?
160
+ debug "checking currency (mtime=#{@mtime} " +
161
+ "file=#{File.exist?(@file) ? File.stat(@file).mtime : nil})"
162
+ case opt :staleness_threshold
163
+ when 0, nil
164
+ debug "staleness_threshold is 0 or nil, always checking"
165
+ File.exist? @file and @mtime >= File.stat(@file).mtime
166
+ when Infinite
167
+ true
168
+ else
169
+ Time.now <= (@mtime + opt(:staleness_threshold)) or
170
+ (File.exist? @file and @mtime >= File.stat(@file).mtime)
171
+ end
172
+ end
173
+
174
+ def [](key)
175
+ update_config unless current?
176
+ @data[key]
177
+ end
178
+
179
+ def []=(key, value)
180
+ update_config unless current?
181
+ @mtime = Time.now
182
+ @data[key] = value
183
+ end
184
+
185
+ def has_key?(key)
186
+ update_config unless current?
187
+ @data.has_key? key
188
+ end
189
+
190
+ def keys
191
+ update_config unless current?
192
+ @data.keys
193
+ end
194
+
195
+ def each
196
+ update_config unless current?
197
+ @data.each do |k, v|
198
+ yield k, v
199
+ end
200
+ end
201
+
202
+ def delete(k)
203
+ update_config unless current?
204
+ @data.delete(k)
205
+ end
206
+
207
+ end
@@ -0,0 +1,138 @@
1
+ #!ruby
2
+ # /* Copyright 2013 Proofpoint, Inc. All rights reserved.
3
+ # Copyright 2014 Evernote Corporation. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # */
17
+
18
+ class NCC::Connection::AWS < NCC::Connection
19
+
20
+ def translate_size(flavor)
21
+ generic_translate(:size, flavor).
22
+ merge({
23
+ 'ram' => flavor.ram,
24
+ 'disk' => flavor.disk,
25
+ 'cores' => flavor.cores,
26
+ 'description' => flavor.name
27
+ })
28
+ end
29
+
30
+ def translate_image(provider_image)
31
+ generic_translate(:image, provider_image).
32
+ merge({
33
+ 'description' => provider_image.description,
34
+ 'ramdisk_id' => provider_image.ramdisk_id,
35
+ 'kernel_id' => provider_image.kernel_id
36
+ })
37
+ end
38
+
39
+ def provider
40
+ 'aws'
41
+ end
42
+
43
+ def use_only_mapped(type)
44
+ case type
45
+ when :image
46
+ true
47
+ when :size
48
+ false
49
+ end
50
+ end
51
+
52
+ def connection_params
53
+ ['aws_access_key_id', 'aws_secret_access_key']
54
+ end
55
+
56
+ def instance_name(server)
57
+ if ! server.tags.nil? and server.tags.has_key? 'Name'
58
+ server.tags['Name']
59
+ else
60
+ nil
61
+ end
62
+ end
63
+
64
+ def instance_size(server)
65
+ map_from_raw_provider_id(:size, server.flavor_id)
66
+ end
67
+
68
+ def instance_image(server)
69
+ map_from_raw_provider_id(:image, server.image_id)
70
+ end
71
+
72
+ def instance_status(server)
73
+ map_to_status(server.state)
74
+ end
75
+
76
+ def instance_ip_address(server)
77
+ server.private_ip_address
78
+ end
79
+
80
+ def console_log(instance_id)
81
+ begin
82
+ @fog.get_console_output(instance_id).body
83
+ rescue Fog::Compute::AWS::NotFound
84
+ instance_not_found instance_id
85
+ rescue Exception => e
86
+ communication_error e.message
87
+ end
88
+ end
89
+
90
+ def provider_request_of(instance)
91
+ {
92
+ :name => instance.name,
93
+ :flavor_id => sizes(instance.size)['provider_id'],
94
+ :image_id => images(instance.image)['provider_id'],
95
+ :tags => { 'Name' => instance.name }
96
+ }.merge(instance.extra provider)
97
+ end
98
+
99
+ def map_to_status(aws_status)
100
+ case aws_status
101
+ when 'running'
102
+ 'active'
103
+ when 'pending'
104
+ 'build'
105
+ when 'terminated'
106
+ 'terminated'
107
+ when 'shutting-down'
108
+ 'shutting-down'
109
+ when 'stopping'
110
+ 'suspending'
111
+ when 'stopped'
112
+ 'suspend'
113
+ else
114
+ 'unknown'
115
+ end
116
+ end
117
+
118
+ def map_to_provider_status(abstract_status)
119
+ case abstract_status
120
+ when 'active', 'error', 'hard-reboot', 'reboot', 'provider-operation',
121
+ 'unknown', 'needs-verify'
122
+ 'running'
123
+ when 'build'
124
+ 'pending'
125
+ when 'terminated'
126
+ 'terminated'
127
+ when 'shutting-down'
128
+ 'shutting-down'
129
+ when 'suspending'
130
+ 'stopping'
131
+ when 'suspend'
132
+ 'stopped'
133
+ else
134
+ 'running'
135
+ end
136
+ end
137
+
138
+ end
@@ -0,0 +1,171 @@
1
+ #!ruby
2
+ # /* Copyright 2013 Proofpoint, Inc. All rights reserved.
3
+ # Copyright 2014 Evernote Corporation. All rights reserved.
4
+ #
5
+ # Licensed under the Apache License, Version 2.0 (the "License");
6
+ # you may not use this file except in compliance with the License.
7
+ # You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS,
13
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ # See the License for the specific language governing permissions and
15
+ # limitations under the License.
16
+ # */
17
+
18
+ class NCC::Connection::OpenStack < NCC::Connection
19
+
20
+ def size_id_field
21
+ :name
22
+ end
23
+
24
+ def image_id_field
25
+ :name
26
+ end
27
+
28
+ def translate_size(flavor)
29
+ generic_translate(:size, flavor).
30
+ merge({
31
+ 'ram' => flavor.ram,
32
+ 'cores' => flavor.vcpus,
33
+ 'description' => size_desc(flavor),
34
+ 'disk' => flavor.disk + flavor.ephemeral
35
+ })
36
+ end
37
+
38
+ def translate_image(pimage)
39
+ image = generic_translate(:image, pimage)
40
+ pimage.metadata.each do |metadatum|
41
+ if %(ramdisk_id kernel_id).include? metadatum.key
42
+ image[metadatum.key] = metadatum.value
43
+ end
44
+ end
45
+ image
46
+ end
47
+
48
+ def provider
49
+ 'openstack'
50
+ end
51
+
52
+ def size_desc(f)
53
+ (f.vcpus > 1 ? "#{f.vcpus}CPU " : "") +
54
+ "#{(f.ram / 1024).round}GB RAM #{f.disk + f.ephemeral}GB disk"
55
+ end
56
+
57
+ def connection_params
58
+ ['openstack_auth_url', 'openstack_username', 'openstack_api_key']
59
+ end
60
+
61
+ def map_to_status(provider_status)
62
+ case provider_status
63
+ when 'ACTIVE', 'PASSWORD', 'SHUTOFF'
64
+ 'active'
65
+ when 'BUILD'
66
+ 'build'
67
+ when 'DELETED'
68
+ 'terminated'
69
+ when 'ERROR'
70
+ 'error'
71
+ when 'HARD_REBOOT'
72
+ 'hard-reboot'
73
+ when 'REBOOT'
74
+ 'reboot'
75
+ when 'REBUILD', 'RESCUE', 'RESIZE', 'REVERT_RESIZE'
76
+ 'provider-operation'
77
+ when 'SUSPENDED'
78
+ 'suspend'
79
+ when 'UNKNOWN'
80
+ 'unknown'
81
+ when 'VERIFY_RESIZE'
82
+ 'needs-verify'
83
+ else
84
+ 'unknown'
85
+ end
86
+ end
87
+
88
+ def instance_image(server)
89
+ map_from_raw_provider_id(:image, server.image['id'])
90
+ end
91
+
92
+ def instance_size(server)
93
+ map_from_raw_provider_id(:size, server.flavor['id'])
94
+ end
95
+
96
+ def instance_status(server)
97
+ map_to_status(server.state)
98
+ end
99
+
100
+ def instance_ip_address(server)
101
+ instance_network_names = ['instance_net', 'instnace_net']
102
+ if !server.addresses.nil?
103
+ instance_network_names.each do |network_name|
104
+ if server.addresses.has_key? network_name
105
+ return server.addresses[network_name].first['addr']
106
+ end
107
+ end
108
+ end
109
+ return nil
110
+ end
111
+
112
+ def instance_host(server)
113
+ server.os_ext_srv_attr_host
114
+ end
115
+
116
+ def console_log(instance_id)
117
+ server = @fog.servers.get(instance_id)
118
+ if server.nil?
119
+ instance_not_found instance_id
120
+ else
121
+ begin
122
+ server.console.body
123
+ rescue Exception => e
124
+ communication_error e.message
125
+ end
126
+ end
127
+ end
128
+
129
+ def provider_request_of(instance)
130
+ {
131
+ :name => instance.name,
132
+ :flavor_ref => sizes(instance.size)['provider_id'],
133
+ :image_ref => images(instance.image)['provider_id'],
134
+ }.merge(instance.extra provider)
135
+ end
136
+
137
+ def reboot(instance_id)
138
+ server = @fog.servers.get(instance_id)
139
+ if server.nil?
140
+ instance_not_found instance_id
141
+ else
142
+ server.reboot 'HARD'
143
+ end
144
+ end
145
+
146
+ def map_to_provider_status(abstract_status)
147
+ case abstract_status
148
+ when 'active', 'provider-operation', 'shutting-down', 'suspending'
149
+ 'ACTIVE'
150
+ when 'build'
151
+ 'BUILD'
152
+ when 'terminated'
153
+ 'DELETED'
154
+ when 'error'
155
+ 'ERROR'
156
+ when 'hard-reboot'
157
+ 'HARD_REBOOT'
158
+ when 'reboot'
159
+ 'REBOOT'
160
+ when 'suspend'
161
+ 'SUSPENDED'
162
+ when 'unknown'
163
+ 'UNKNOWN'
164
+ when 'needs-verify'
165
+ 'VERIFY_RESIZE'
166
+ else
167
+ 'UNKNOWN'
168
+ end
169
+ end
170
+
171
+ end