Class: VMC::Client

Inherits:
Object show all
Defined in:
lib/vmc/client.rb

Defined Under Namespace

Classes: AuthError, BadResponse, BadTarget, HTTPException, NotFound, TargetError

Constant Summary collapse

VMC_HTTP_ERROR_CODES =

Error codes

[ 400, 500 ]
HTTP_TIMEOUT =
ENV['TIMEOUT'] ? ENV['TIMEOUT'].to_i : 10*60

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(target_url = VMC::DEFAULT_TARGET, auth_token = nil) ⇒ Client

Initialize new client to the target_uri with optional auth_token



41
42
43
44
45
46
# File 'lib/vmc/client.rb', line 41

def initialize(target_url=VMC::DEFAULT_TARGET, auth_token=nil)
  target_url = "https://#{target_url}" unless /^https?/ =~ target_url
  target_url = target_url.gsub(/\/+$/, '')
  @target = target_url
  @auth_token = auth_token
end

Instance Attribute Details

#auth_tokenObject (readonly)

Returns the value of attribute auth_token.



24
25
26
# File 'lib/vmc/client.rb', line 24

def auth_token
  @auth_token
end

#hostObject (readonly)

Returns the value of attribute host.



24
25
26
# File 'lib/vmc/client.rb', line 24

def host
  @host
end

#infraObject

Returns the value of attribute infra.



25
26
27
# File 'lib/vmc/client.rb', line 25

def infra
  @infra
end

#proxyObject

Returns the value of attribute proxy.



24
25
26
# File 'lib/vmc/client.rb', line 24

def proxy
  @proxy
end

#targetObject (readonly)

Returns the value of attribute target.



24
25
26
# File 'lib/vmc/client.rb', line 24

def target
  @target
end

#traceObject

Returns the value of attribute trace.



25
26
27
# File 'lib/vmc/client.rb', line 25

def trace
  @trace
end

#userObject (readonly)

Returns the value of attribute user.



24
25
26
# File 'lib/vmc/client.rb', line 24

def user
  @user
end

Class Method Details

.path(*path) ⇒ Object



370
371
372
373
374
# File 'lib/vmc/client.rb', line 370

def self.path(*path)
  path.flatten.collect { |x|
    URI.encode x.to_s, Regexp.new("[^#{URI::PATTERN::UNRESERVED}]")
  }.join("/")
end

.versionObject



20
21
22
# File 'lib/vmc/client.rb', line 20

def self.version
  VMC::VERSION
end

Instance Method Details

#add_user(user_email, password) ⇒ Object



359
360
361
# File 'lib/vmc/client.rb', line 359

def add_user(user_email, password)
  json_post(VMC::USERS_PATH, { :email => user_email, :password => password })
end

#app_crashes(name) ⇒ Object



148
149
150
151
# File 'lib/vmc/client.rb', line 148

def app_crashes(name)
  
  json_get(path(VMC::APPS_PATH, name, "crashes"))
end

#app_diff(name) ⇒ Object



158
159
160
161
# File 'lib/vmc/client.rb', line 158

def app_diff(name)
  
  json_get(path(VMC::APPS_PATH, name, "diff"))
end

#app_download(name, path) ⇒ Object



173
174
175
176
177
178
179
180
# File 'lib/vmc/client.rb', line 173

def app_download(name,path)
  
  url = path(VMC::APPS_PATH, name, "application")
  status, body, headers = http_get(url,'application/octet-stream')
  file = File.new(path,"wb")
  file.write(body)
  file.close
end

#app_files(name, path, instance = '0') ⇒ Object

List the directory or download the actual file indicated by the path.



165
166
167
168
169
170
171
# File 'lib/vmc/client.rb', line 165

def app_files(name, path, instance='0')
  
  path = path.gsub('//', '/')
  url = path(VMC::APPS_PATH, name, "instances", instance, "files", path)
  _, body, headers = http_get(url)
  body
end

#app_history(name) ⇒ Object



153
154
155
156
# File 'lib/vmc/client.rb', line 153

def app_history(name)
  
  json_get(path(VMC::APPS_PATH, name, "history"))
end

#app_info(name) ⇒ Object



119
120
121
122
# File 'lib/vmc/client.rb', line 119

def app_info(name)
  
  json_get(path(VMC::APPS_PATH, name))
end

#app_instances(name) ⇒ Object



143
144
145
146
# File 'lib/vmc/client.rb', line 143

def app_instances(name)
  
  json_get(path(VMC::APPS_PATH, name, "instances"))
end

#app_pull(name, dir) ⇒ Object



182
183
184
185
186
187
188
189
190
191
192
# File 'lib/vmc/client.rb', line 182

def app_pull(name, dir)
  
  url = path(VMC::APPS_PATH, name, "application")
  status, body, headers = http_get(url,'application/octet-stream')
  file = Tempfile.new(name)
  file.binmode
  file.write(body)
  file.close
  ::VMC::Cli::ZipUtil.unpack(file.path, dir)
  file.unlink
end

#app_stats(name) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/vmc/client.rb', line 129

def app_stats(name)
  
  stats_raw = json_get(path(VMC::APPS_PATH, name, "stats"))
  stats = []
  stats_raw.each_pair do |k, entry|
    # Skip entries with no stats
    next unless entry[:stats]
    entry[:instance] = k.to_s.to_i
    entry[:state] = entry[:state].to_sym if entry[:state]
    stats << entry
  end
  stats.sort { |a,b| a[:instance] - b[:instance] }
end

#app_update_info(name) ⇒ Object



124
125
126
127
# File 'lib/vmc/client.rb', line 124

def app_update_info(name)
  
  json_get(path(VMC::APPS_PATH, name, "update"))
end

#appsObject

Apps



76
77
78
79
# File 'lib/vmc/client.rb', line 76

def apps
  
  json_get(VMC::APPS_PATH)
end

#base_for_infra(name) ⇒ Object



390
391
392
393
# File 'lib/vmc/client.rb', line 390

def base_for_infra(name)
  info = infras.detect { |i| i[:infra] == name }
  info ? info[:base] : default_base
end

#bind_service(service, appname) ⇒ Object



241
242
243
244
245
246
247
248
249
250
251
# File 'lib/vmc/client.rb', line 241

def bind_service(service, appname)
  
  svc = services.detect { |s| s[:name] == service }
  app = app_info(appname)
  if infra_supported? && ! infras_match?(app,svc)
    raise TargetError, "Service #{service} and App #{appname} are not on the same infra"
  end
  services = app[:services] || []
  app[:services] = services << service
  update_app(appname, app)
end

#change_password(new_password) ⇒ Object

sets the password for the current logged user



333
334
335
336
337
338
339
340
# File 'lib/vmc/client.rb', line 333

def change_password(new_password)
  
   = json_get(path(VMC::USERS_PATH, @user))
  if 
    [:password] = new_password
    json_put(path(VMC::USERS_PATH, @user), )
  end
end

#check_resources(resources, infra = nil) ⇒ Object

Send in a resources manifest array to the system to have it check what is needed to actually send. Returns array indicating what is needed. This returned manifest should be sent in with the upload if resources were removed. E.g. [=> xxx, :size => xxx, :fn => filename]



279
280
281
282
283
284
285
286
287
# File 'lib/vmc/client.rb', line 279

def check_resources(resources,infra=nil)
  
  url = VMC::RESOURCES_PATH
  unless infra.nil?
    url += "?infra=#{infra}"
  end
  status, body, headers = json_post(url, resources)
  json_parse(body)
end

#create_app(name, manifest = {}) ⇒ Object



81
82
83
84
85
86
87
# File 'lib/vmc/client.rb', line 81

def create_app(name, manifest={})
  
  app = manifest.dup
  app[:name] = name
  app[:instances] ||= 1
  json_post(VMC::APPS_PATH, app)
end

#create_service(infra, service, name) ⇒ Object

Raises:



204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/vmc/client.rb', line 204

def create_service(infra,service, name)
  
  services = services_info
  services ||= []
  service_hash = nil

  service = service.to_s

  # FIXME!
  services.each do |service_type, value|
    value.each do |vendor, version|
      version.each do |version_str, service_descr|
        if service == service_descr[:vendor]
          service_hash = {
            :type => service_descr[:type], :tier => 'free',
            :vendor => service, :version => version_str
          }
          service_hash[:infra] = { :provider => infra } if infra
          break
        end
      end
    end
  end

  raise TargetError, "Service [#{service}] is not a valid service choice" unless service_hash
  service_hash[:name] = name
  json_post(path(VMC::SERVICES_PATH), service_hash)
end

#default_baseObject



395
396
397
398
399
400
401
402
403
# File 'lib/vmc/client.rb', line 395

def default_base
  # remove the protocol, and the first component of the url, which is normally api
  pattern = /https?:\/\/[^.]+\./
  if @target =~ pattern
    @target.sub(pattern,'')
  else
    "aws.af.cm"
  end
end

#delete_app(name) ⇒ Object



114
115
116
117
# File 'lib/vmc/client.rb', line 114

def delete_app(name)
  
  http_delete(path(VMC::APPS_PATH, name))
end

#delete_service(name) ⇒ Object

Raises:



233
234
235
236
237
238
239
# File 'lib/vmc/client.rb', line 233

def delete_service(name)
  
  svcs = services || []
  names = svcs.collect { |s| s[:name] }
  raise TargetError, "Service [#{name}] not a valid service" unless names.include? name
  http_delete(path(VMC::SERVICES_PATH, name))
end

#delete_user(user_email) ⇒ Object



363
364
365
366
# File 'lib/vmc/client.rb', line 363

def delete_user(user_email)
  
  http_delete(path(VMC::USERS_PATH, user_email))
end

#export_service(service) ⇒ Object



262
263
264
# File 'lib/vmc/client.rb', line 262

def export_service(service)
  json_get(path(VMC::SERVICE_EXPORT_PATH, service))
end

#import_service(service, uri) ⇒ Object



266
267
268
# File 'lib/vmc/client.rb', line 266

def import_service(service,uri)
  json_post(path(VMC::SERVICE_IMPORT_PATH, service),{:uri => uri})
end

#infoObject

Retrieves information on the target cloud, and optionally the logged in user



53
54
55
56
# File 'lib/vmc/client.rb', line 53

def info
  # TODO: Should merge for new version IMO, general, services, user_account
  json_get(VMC::INFO_PATH)
end

#infra_descriptionsObject



409
410
411
# File 'lib/vmc/client.rb', line 409

def infra_descriptions
  infras.select{|i| !i.has_key?(:available) || i[:available] == true}.map { |i| i[:description] }
end

#infra_name_for_description(desc) ⇒ Object



413
414
415
416
# File 'lib/vmc/client.rb', line 413

def infra_name_for_description(desc)
  info = infras.detect { |i| i[:description] == desc }
  info ? info[:infra] : ""
end

#infra_supported?Boolean

Returns:

  • (Boolean)


386
387
388
# File 'lib/vmc/client.rb', line 386

def infra_supported?
  !infras.empty?
end

#infra_valid?(name) ⇒ Boolean

Returns:

  • (Boolean)


405
406
407
# File 'lib/vmc/client.rb', line 405

def infra_valid?(name)
  infras.detect { |i| i[:infra] == name }
end

#infrasObject

Infrastructure



380
381
382
383
384
# File 'lib/vmc/client.rb', line 380

def infras
  json_get(path(VMC::GLOBAL_INFRAS_PATH))
rescue
  []
end

#logged_in?Boolean

Checks that the auth_token is valid

Returns:

  • (Boolean)


306
307
308
309
310
311
312
313
314
# File 'lib/vmc/client.rb', line 306

def logged_in?
  descr = info
  if descr
    return false unless descr[:user]
    return false unless descr[:usage]
    @user = descr[:user]
    true
  end
end

#login(user, password) ⇒ Object

login and return an auth_token Auth token can be retained and used in creating new clients, avoiding login.



323
324
325
326
327
328
329
330
# File 'lib/vmc/client.rb', line 323

def (user, password)
  status, body, headers = json_post(path(VMC::USERS_PATH, user, "tokens"), {:password => password})
  response_info = json_parse(body)
  if response_info
    @user = user
    @auth_token = response_info[:token]
  end
end

#proxy_for(proxy) ⇒ Object



350
351
352
# File 'lib/vmc/client.rb', line 350

def proxy_for(proxy)
  @proxy = proxy
end

#raw_infoObject



58
59
60
# File 'lib/vmc/client.rb', line 58

def raw_info
  http_get(VMC::INFO_PATH)
end

#runtimes_infoObject



68
69
70
# File 'lib/vmc/client.rb', line 68

def runtimes_info
  json_get(path(VMC::GLOBAL_RUNTIMES_PATH))
end

#servicesObject

listing of services that are available in the system



199
200
201
202
# File 'lib/vmc/client.rb', line 199

def services
  
  json_get(VMC::SERVICES_PATH)
end

#services_infoObject

Global listing of services that are available on the target system



63
64
65
66
# File 'lib/vmc/client.rb', line 63

def services_info
  
  json_get(path(VMC::GLOBAL_SERVICES_PATH))
end

#suggest_url(infra = nil) ⇒ Object



418
419
420
# File 'lib/vmc/client.rb', line 418

def suggest_url(infra=nil)
  @suggest_url ||= base_for_infra(infra || @infra)
end

#target_valid?Boolean

Checks that the target is valid

Returns:

  • (Boolean)


294
295
296
297
298
299
300
301
302
303
# File 'lib/vmc/client.rb', line 294

def target_valid?
  return false unless descr = info
  return false unless descr[:name]
  return false unless descr[:build]
  return false unless descr[:version]
  return false unless descr[:support]
  true
rescue
  false
end

#unbind_service(service, appname) ⇒ Object



253
254
255
256
257
258
259
260
# File 'lib/vmc/client.rb', line 253

def unbind_service(service, appname)
  
  app = app_info(appname)
  services = app[:services] || []
  services.delete(service)
  app[:services] = services
  update_app(appname, app)
end

#update_app(name, manifest) ⇒ Object



89
90
91
92
# File 'lib/vmc/client.rb', line 89

def update_app(name, manifest)
  
  json_put(path(VMC::APPS_PATH, name), manifest)
end

#upload_app(name, zipfile, hash, label, resource_manifest = nil) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/vmc/client.rb', line 94

def upload_app(name, zipfile, hash, label, resource_manifest=nil)
  #FIXME, manifest should be allowed to be null, here for compatability with old cc's
  resource_manifest ||= []
  
  upload_data = {:_method => 'put'}
  if zipfile
    if zipfile.is_a? File
      file = zipfile
    else
      file = File.new(zipfile, 'rb')
    end
    upload_data[:application] = file
  end
  headers = {:hash => hash, :label => label}
  upload_data[:resources] = resource_manifest.to_json if resource_manifest
  http_post(path(VMC::APPS_PATH, name, "application"), upload_data, nil, headers)
rescue RestClient::ServerBrokeConnection
  retry
end

#usersObject



354
355
356
357
# File 'lib/vmc/client.rb', line 354

def users
  
  json_get(VMC::USERS_PATH)
end