Class: EY::CloudClient::Environment
- Inherits:
-
Object
- Object
- EY::CloudClient::Environment
- Defined in:
- lib/engineyard-cloud-client/models/environment.rb
Instance Attribute Summary collapse
-
#account ⇒ Object
Returns the value of attribute account.
-
#apps ⇒ Object
Returns the value of attribute apps.
Class Method Summary collapse
-
.all(api) ⇒ Object
Return list of all Environments linked to all current user’s accounts.
-
.by_name(api, environment_name, account_name = nil) ⇒ Object
Accepts an api object, environment name and optional account name and returns the best matching environment for the given constraints.
-
.create(api, attrs = {}) ⇒ Object
Usage Environment.create(api, { app: app, # requires: app.id name: ‘myapp_production’, region: ‘us-west-1’, # default: us-east-1 app_server_stack_name: ‘nginx_thin’, # default: nginx_passenger3 framework_env: ‘staging’ # default: production cluster_configuration: { configuration: ‘single’ # default: single, cluster, custom } }).
-
.resolve(api, constraints) ⇒ Object
Return a constrained list of environments given a set of constraints like:.
Instance Method Summary collapse
- #account_name ⇒ Object
- #add_app_environment(app_env) ⇒ Object
-
#add_instance(opts) ⇒ Object
Throws a POST request at the API to /add_instances and adds one instance to this environment.
- #app_environments ⇒ Object
- #attributes=(attrs) ⇒ Object
- #bridge ⇒ Object
- #bridge!(ignore_bad_bridge = false) ⇒ Object
- #deploy_to_instances ⇒ Object
-
#download_recipes ⇒ Object
See Recipes#download.
- #hierarchy_name ⇒ Object
-
#instance_by_id(id) ⇒ Object
Gets an instance’s Amazon ID by its “id” attribute as reported by AWSM.
- #instances ⇒ Object
-
#instances_by_role(*roles) ⇒ Object
Simple version of select_instances that only selects roles, not names instances_by_role(:app_master, :app) # same instances_by_role(%w[app_master app]) # same select_instances(app_master: true, app: true) # same.
- #logs ⇒ Object
- #provisioned_instances ⇒ Object
- #recipes ⇒ Object
-
#remove_instance(instance) ⇒ Object
Sends a request to the API to remove the instance specified by its “provisioned_id” (Amazon ID).
-
#run_custom_recipes ⇒ Object
See Recipes#run.
-
#select_instances(options) ⇒ Object
Select instances by role, with optional name constraints.
- #shorten_name_for(app) ⇒ Object
- #ssh_username=(user) ⇒ Object
- #update ⇒ Object (also: #rebuild)
-
#upload_recipes(file_to_upload) ⇒ Object
See Recipes#upload.
-
#upload_recipes_at_path(recipes_path) ⇒ Object
See Recipes#upload_path.
Instance Attribute Details
#account ⇒ Object
Returns the value of attribute account.
101 102 103 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 101 def account @account end |
#apps ⇒ Object
Returns the value of attribute apps.
101 102 103 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 101 def apps @apps end |
Class Method Details
.all(api) ⇒ Object
Return list of all Environments linked to all current user’s accounts
21 22 23 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 21 def self.all(api) self.from_array(api, api.get("/environments", "no_instances" => "true")["environments"]) end |
.by_name(api, environment_name, account_name = nil) ⇒ Object
Accepts an api object, environment name and optional account name and returns the best matching environment for the given constraints.
This is a shortcut for resolve_environments. Raises if nothing is found or if more than one environment is found.
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 45 def self.by_name(api, environment_name, account_name=nil) constraints = { :environment_name => environment_name, :account_name => account_name, } resolver = resolve(api, constraints) resolver.one_match { |match| return match } resolver.no_matches do |errors, suggestions| = nil if suggestions.any? = "Suggestions found:\n" suggestions.sourt_by{|suggest| suggest['account_name']}.each do |suggest| << "\t#{suggest['account_name']}/#{suggest['env_name']}\n" end end raise ResourceNotFound.new([errors,].compact.join("\n").strip) end resolver.many_matches do |matches| = "Multiple environments possible, please be more specific:\n" matches.sort_by {|env| env.account}.each do |env| << "\t#{env.account.name}/#{env.name}\n" end raise MultipleMatchesError.new() end end |
.create(api, attrs = {}) ⇒ Object
Usage Environment.create(api, {
app: app, # requires: app.id
name: 'myapp_production',
region: 'us-west-1', # default: us-east-1
app_server_stack_name: 'nginx_thin', # default: nginx_passenger3
framework_env: 'staging' # default: production
cluster_configuration: {
configuration: 'single' # default: single, cluster, custom
}
})
NOTE: Syntax above is for Ruby 1.9. In Ruby 1.8, keys must all be strings.
TODO - allow any attribute to be sent through that the API might allow; e.g. region, ruby_version, stack_label
90 91 92 93 94 95 96 97 98 99 100 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 90 def self.create(api, attrs={}) app = attrs.delete("app") cluster_configuration = attrs.delete('cluster_configuration') raise EY::CloudClient::AttributeRequiredError.new("app", EY::CloudClient::App) unless app raise EY::CloudClient::AttributeRequiredError.new("name") unless attrs["name"] params = {"environment" => attrs.dup} unpack_cluster_configuration(params, cluster_configuration) response = api.post("/apps/#{app.id}/environments", params) self.from_hash(api, response['environment']) end |
.resolve(api, constraints) ⇒ Object
Return a constrained list of environments given a set of constraints like:
-
app_name: app name full or partial match string
-
account_name: account name full or partial match string
-
environment_name: environment name full or partial match string
-
remotes: An array of git remote URIs
32 33 34 35 36 37 38 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 32 def self.resolve(api, constraints) clean_constraints = constraints.reject { |k,v| v.nil? } params = {'constraints' => clean_constraints} response = api.get("/environments/resolve", params)['resolver'] matches = from_array(api, response['matches']) ResolverResult.new(api, matches, response['errors'], response['suggestions']) end |
Instance Method Details
#account_name ⇒ Object
136 137 138 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 136 def account_name account && account.name end |
#add_app_environment(app_env) ⇒ Object
115 116 117 118 119 120 121 122 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 115 def add_app_environment(app_env) @app_environments ||= [] existing_app_env = @app_environments.detect { |ae| app_env.environment == ae.environment } unless existing_app_env @app_environments << app_env end existing_app_env || app_env end |
#add_instance(opts) ⇒ Object
Throws a POST request at the API to /add_instances and adds one instance to this environment.
Usage example:
api = EY::CloudClient.new(token: ‘your token here’) env = api.environment_by_name(‘your_env_name’)
env.add_instance(role: “app”) env.add_instance(role: “util”, name: “foo”)
Note that the role for an instance MUST be either “app” or “util”. No other value is acceptable. The “name” parameter can be anything, but it only applies to utility instances.
Note also that if you add a util instance, you must specify a name. This method will raise if you don’t.
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 265 def add_instance(opts) unless %w[app util].include?(opts[:role].to_s) # Fail immediately because we don't have valid arguments. raise InvalidInstanceRole, "Instance role must be one of: app, util" end # Sanitize the name to remove whitespace if there is any if opts[:name] name = opts[:name].gsub(/\s+/, '') end if opts[:role] == 'util' unless name && name.length > 0 raise InvalidInstanceName, "When specifying a util instance you must also specify a name." end end # We know opts[:role] is right, name can be passed straight to the API. # Return the response body for error output, logging, etc. return api.post("/environments/#{id}/add_instances", :request => { "role" => opts[:role], "name" => opts[:name] }) end |
#app_environments ⇒ Object
124 125 126 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 124 def app_environments @app_environments ||= [] end |
#attributes=(attrs) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 103 def attributes=(attrs) account_attrs = attrs.delete('account') apps_attrs = attrs.delete('apps') instances_attrs = attrs.delete('instances') super set_account account_attrs if account_attrs set_apps apps_attrs if apps_attrs set_instances instances_attrs if instances_attrs end |
#bridge ⇒ Object
160 161 162 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 160 def bridge @bridge ||= instances.detect { |inst| inst.bridge? } end |
#bridge!(ignore_bad_bridge = false) ⇒ Object
164 165 166 167 168 169 170 171 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 164 def bridge!(ignore_bad_bridge = false) if bridge.nil? raise NoBridgeError.new(name) elsif !ignore_bad_bridge && !bridge.running? raise BadBridgeStatusError.new(bridge.status, api.endpoint) end bridge end |
#deploy_to_instances ⇒ Object
156 157 158 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 156 def deploy_to_instances provisioned_instances.select { |inst| inst.has_app_code? } end |
#download_recipes ⇒ Object
See Recipes#download
229 230 231 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 229 def download_recipes recipes.download end |
#hierarchy_name ⇒ Object
140 141 142 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 140 def hierarchy_name [account_name, name].join(" / ") end |
#instance_by_id(id) ⇒ Object
Gets an instance’s Amazon ID by its “id” attribute as reported by AWSM. When an instance is added via the API, the JSON that’s returned contains an “id” attribute for that instance. Developers may save that ID so they can later discover an instance’s Amazon ID. This is because, when an instance object is first created (see #add_instance above), its Amazon ID isn’t yet known. The object is created, and then later provisioned, so you can’t get an Amazon ID until after provisioning has taken place. This method allows you to send an ID to it, and then returns the instance object that corresponds to that ID, which will have an Amazon ID with it if the instance has been provisioned at the time the environment information was read.
Note that the ID passed in must be an integer.
Usage example:
api = EY::CloudClient.new(token: 'token')
env = api.environment_by_name('my_env')
env.instance_by_id(12345)
=> <EY::CloudClient::Instance ...>
312 313 314 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 312 def instance_by_id(id) instances.detect { |x| x.id == id } # ID should always be unique end |
#instances ⇒ Object
132 133 134 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 132 def instances @instances ||= request_instances end |
#instances_by_role(*roles) ⇒ Object
Simple version of select_instances that only selects roles, not names
instances_by_role(:app_master, :app) # same
instances_by_role(%w[app_master app]) # same
select_instances(app_master: true, app: true) # same
208 209 210 211 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 208 def instances_by_role(*roles) roles = roles.flatten.map(&:to_s) instances.select { |inst| roles.include?(inst.role.to_s) } end |
#logs ⇒ Object
148 149 150 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 148 def logs Log.from_array(api, api.get("/environments/#{id}/logs")["logs"]) end |
#provisioned_instances ⇒ Object
152 153 154 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 152 def provisioned_instances instances.select { |inst| inst.provisioned? } end |
#recipes ⇒ Object
219 220 221 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 219 def recipes Recipes.new(api, self) end |
#remove_instance(instance) ⇒ Object
Sends a request to the API to remove the instance specified by its “provisioned_id” (Amazon ID).
Usage example:
api = EY::CloudClient.new(token: 'token')
env = api.environment_by_name('my_app_production')
bad_instance = env.instance_by_id(12345) # instance ID should be saved upon creation
env.remove_instance(bad_instance)
Warnings/caveats:
+ The API is responsible for actually removing this instance. All this
does is send an appropriate request to the API.
+ You should look carefully at the API response JSON to see whether or
not the API accepted or rejected your request. If it accepted the
request, that instance *should* be removed as soon as possible.
+ Note that this is a client that talks to an API, which talks to an
API, which talks to an API. Ultimately the IaaS provider API has the
final say on whether or not to remove an instance, so a failure there
can definitely affect how things work at every point down the line.
+ If the instance you pass in doesn’t exist in the live cloud
environment you're working on, the status should be rejected and thus
the instance won't be removed (because *that* instance isn't there).
This is important to keep in mind for scheduled/auto scaling; if
for some reason the automatically added instance is removed before
a "scale down" event that you might trigger, you may wind up with an
unknown/unexpected number of instances in your environment.
+ Only works for app/util instances. Raises an error if you pass one
that isn't valid.
347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 347 def remove_instance(instance) unless instance raise ArgumentError, "A argument of type Instance was expected. Got #{instance.inspect}" end # Check to make sure that we have a valid instance role here first. unless %w[app util].include?(instance.role) raise InvalidInstanceRole, "Removing instances is only supported for app, util instances" end # Check to be sure that instance is actually provisioned # TODO: Rip out the amazon_id stuff when we have IaaS agnosticism nailed down unless instance.amazon_id && instance.provisioned? raise InstanceNotProvisioned, "Instance is not provisioned or is in unusual state." end response = api.post("/environments/#{id}/remove_instances", :request => { :provisioned_id => instance.amazon_id, :role => instance.role, :name => instance.name }) # Reset instances so they are fresh if they are requested again. @instances = nil # Return the response. return response end |
#run_custom_recipes ⇒ Object
See Recipes#run
224 225 226 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 224 def run_custom_recipes recipes.run end |
#select_instances(options) ⇒ Object
Select instances by role, with optional name constraints.
Select the “master” app instance: select_instances(app_master: true)
Select the “master” db instance on a solo or multi-instance env: select_instances(solo: true, db_master: true)
Select app, app_master, or utils (only if they are named resque or redis): select_instances(app_master: true, app: true, util: %w[resque redis])
Select all instances (same as the method #instances): select_instances(all: true)
See #instances_by_role for a simpler interface.
188 189 190 191 192 193 194 195 196 197 198 199 200 201 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 188 def select_instances() instances_by_role(.keys).select do |inst| # get the value of the string/symbol key that matches without losing nil/false values val = .fetch(inst.role.to_sym) { .fetch(inst.role.to_s, false) } case val when true, false then val when inst.name then true when nil, '' then [nil, ''].include?(inst.name) when Array then val.include?(inst.name) else false end end end |
#shorten_name_for(app) ⇒ Object
243 244 245 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 243 def shorten_name_for(app) name.gsub(/^#{Regexp.quote(app.name)}_/, '') end |
#ssh_username=(user) ⇒ Object
144 145 146 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 144 def ssh_username=(user) self.username = user end |
#update ⇒ Object Also known as: rebuild
213 214 215 216 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 213 def update api.put("/environments/#{id}/update_instances") true # raises on failure end |
#upload_recipes(file_to_upload) ⇒ Object
See Recipes#upload
239 240 241 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 239 def upload_recipes(file_to_upload) recipes.upload(file_to_upload) end |
#upload_recipes_at_path(recipes_path) ⇒ Object
See Recipes#upload_path
234 235 236 |
# File 'lib/engineyard-cloud-client/models/environment.rb', line 234 def upload_recipes_at_path(recipes_path) recipes.upload_path(recipes_path) end |