Skip to content

Instantly share code, notes, and snippets.

@chewmanfoo
Last active December 14, 2017 15:06
Show Gist options
  • Save chewmanfoo/e0fd89674902ac24484b9dff7b35df4d to your computer and use it in GitHub Desktop.
Save chewmanfoo/e0fd89674902ac24484b9dff7b35df4d to your computer and use it in GitHub Desktop.
cf_deployment.rb
# app/models/cf_deployment.rb
# env:string, account:string, delay:string, deploy_at:datetime, revision:string, branch:string, tag:string
class CfDeployment < ApplicationRecord
WORKPATH = "/tmp/plp1"
progname = "app/models/cf_deployment.rb"
# model association
belongs_to :cf_template
belongs_to :creator, :class_name => 'User'
#has_one :qk_deployment
attr_reader :deployment_path, :region, :files, :local_path
# callbacks
before_save {
@region = "us-east-1"
setup_services
@stack_name = @ns.name_cloudformation_stack
}
after_create {
setup_repo
setup_params
validate_artifacts
start_deployment
#estimate_stack_cost
}
before_destroy {
@region = "us-east-1"
setup_services
@stack_name = @ns.name_cloudformation_stack
}
after_destroy {
delete_stack
}
# validations
# :revision and _branch are not required fields
# if they are not present, we use HEAD on master
validates_presence_of :env, :account
validates_presence_of :deploy_at, if: Proc.new {|a| a.delay?}
# TODO these environments are also repeated in the credentials service - DRY
validates_inclusion_of :env, :in => %w( cit_certification cit_production ec_sandbox )
# TODO these accounts are also repeated in the credentials service - DRY
validates_inclusion_of :account, :in => %w( 234740779720 415334768129 163158673736 )
validates_inclusion_of :key, :in => User.all.map{|e| e.key}
# delegation
delegate :repo, :path, :nested, :parent_filename, :manifest_filename,
to: :cf_template, prefix: true
def delay?
delay == "true"
end
def dry_run?
dry_run == "true"
end
def template_buckets
{"ec_sandbox" => "sabre-sbx-templates", "cit_certification" => "sabre.templates", "cit_production" => "sabre-templates"}
end
# workflow
# deployment has a workflow -
# :preflight transitions to :start with
# :start transitions to :running with
# :running transitions to :complete with ; transitions to :failed with
# :complete transitions to :retire with
# :failed transitions to :retire with
# :retire done
# temporary functions
def setup_repo
args={repo: cf_template_repo, path: cf_template_path, workpath: WORKPATH,
nested: cf_template_nested, branch: branch, revision: revision, tag: tag}
@gs = GitService.new(args)
@local_path = @gs.get_repo
@files = @gs.get_file_list
end
def setup_services
args={env: env, cf_template_filename: cf_template_parent_filename, include_suffix: false}
@ns = NamingService.new(args)
args={environment: env, method: "env"}
@cs = AwsCredentialsService.new(args)
args={creds: @cs.creds, region: region, arn: @cs.arn}
@s3 = AwsS3Service.new(args)
args={creds: @cs.creds, arn: @cs.arn, region: region}
@cfs = AwsCloudFormationService.new(args)
end
def setup_params
end
def validate_artifacts
logger.info "got files: #{files}"
files.select{|e| e.include?(".json")}.each do |template_file|
s3url = @s3.put_local_file_in_s3({local_path: local_path, file_name: template_file, bucket: template_buckets[env]})
resp = @cfs.validate_template({url: s3url, arn: @cs.arn, region: region})
logger.info "resp: #{resp}"
#TODO what to do if any are invalid!!
end
end
def start_deployment
stack_name = @ns.name_cloudformation_stack
params = @cfs.convert_manifest_to_params({path: "#{local_path}#{cf_template_manifest_filename}",
file: cf_template_parent_filename, env: env, format: "internal"})
logger.info "got params!: #{params}"
s3url = @s3.get_file_url({filename: cf_template_parent_filename, bucket: template_buckets[env]})
@cfs.create_stack({url: s3url, arn: @cs.arn, stack_name: stack_name, region: region, params: params, dry_run: dry_run})
#########################################################################################
#TODO: this SHOULD BE asynchronous - need a out-of-band runner to execute this!
# this might timeout before it finishes
end
def delete_stack
stack_name = @ns.name_cloudformation_stack
if @cfs.stack_exists?({stack_name: stack_name, dry_run: dry_run})
@cfs.delete_stack({stack_name: stack_name, dry_run: dry_run})
else
logger.info "app/models/cf_deployment.rb #delete_stack - asked to delete stack called #{stack_name}, but stack does not exist! Skipping."
end
end
def estimate_stack_cost
stack_name = @ns.name_cloudformation_stack
params = @cfs.convert_manifest_to_params({path: "#{local_path}#{cf_template_manifest_filename}",
file: cf_template_parent_filename, env: env})
#p "got params!: #{params}"
s3url = @s3.get_file_url({filename: cf_template_parent_filename, bucket: template_buckets[env]})
@cost_url = @cfs.estimate_stack_cost({url: s3url, arn: @cs.arn, stack_name: stack_name, region: region, params: params})
#########################################################################################
#TODO: this SHOULD BE asynchronous - need a out-of-band runner to execute this!
# this might timeout before it finishes
end
end
ActiveRecord::Schema.define(version: 20171214002124) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "cf_deployments", force: :cascade do |t|
t.string "env"
t.string "account"
t.datetime "deploy_at"
t.integer "cf_template_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "delay"
t.string "revision"
t.string "branch"
t.string "tag"
t.string "dry_run"
t.string "cost_url"
t.string "stack_name"
t.integer "creator_id"
t.index ["cf_template_id"], name: "index_cf_deployments_on_cf_template_id", using: :btree
end
create_table "cf_templates", force: :cascade do |t|
t.string "repo"
t.string "path"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.string "nested"
t.integer "creator_id"
end
create_table "qk_deployments", force: :cascade do |t|
t.integer "cf_template_id"
t.integer "cf_deployment_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["cf_deployment_id"], name: "index_qk_deployments_on_cf_deployment_id", using: :btree
t.index ["cf_template_id"], name: "index_qk_deployments_on_cf_template_id", using: :btree
end
create_table "users", force: :cascade do |t|
t.string "name"
t.string "key"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_foreign_key "cf_deployments", "cf_templates"
add_foreign_key "qk_deployments", "cf_deployments"
add_foreign_key "qk_deployments", "cf_templates"
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment