appfront 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 505d73e7f8af1914c2103171441ba6e705bcd073
4
+ data.tar.gz: cf4ae7841945f10427fcf413cb867866b9c45bb7
5
+ SHA512:
6
+ metadata.gz: accd83b850c4cf86a43b757b63dd8d65e1541d76c4d1ab50eaad252d4bfada70003163a9a6b3724f80c76b0f8091b3e1e7c3fb8ef024da18c0fa2d5e20bff740
7
+ data.tar.gz: a66551fd5579be5222de0271f4e7d129beae87699f8a00fc9a6252f01f4e776f4a441e38cc168005bbc001f5f7836fcc456fea33609d20d017a1ce67e865e40f
data/bin/appfront ADDED
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'appfront/cli'
4
+
5
+ Appfront::CLI.run ARGV
data/lib/appfront.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Appfront
2
+ require 'appfront/cli'
3
+ end
@@ -0,0 +1,76 @@
1
+ class Appfront::API
2
+ require 'restclient'
3
+ require 'json'
4
+
5
+ attr_reader :email, :host
6
+
7
+ def initialize(opts = {})
8
+ @host = opts[:host] || 'https://api.appfront.io/v1'
9
+
10
+ if opts[:email] and opts[:password]
11
+ @email, @pass = opts[:email], opts[:password]
12
+ else
13
+ @email, @pass = Appfront::Command::Auth.credentials
14
+ end
15
+ end
16
+
17
+ def login
18
+ return unless (@email && @pass)
19
+
20
+ @pass = RestClient.post(
21
+ "#{@host}/auth",
22
+ email: @email, password: @pass
23
+ )
24
+ rescue => e
25
+ puts e.response
26
+ exit 1
27
+ end
28
+
29
+ def method_missing(m, *args, &block)
30
+ unless ['get', 'post', 'put', 'delete'].include? m.to_s
31
+ raise NoMethodError, "undefined method: #{m}"
32
+ end
33
+
34
+ res = self.send('req', m, args)
35
+ #TODO Da capire JSON.parse res rescue ""
36
+ JSON.parse res rescue res
37
+ end
38
+
39
+ private
40
+
41
+ def req(method, *args)
42
+ raise if args.empty?
43
+ args = args.shift
44
+ path = args.shift
45
+
46
+ resource = RestClient::Resource.new(
47
+ "#{@host}#{path}", user: @pass, password: 'x'
48
+ )
49
+
50
+ begin
51
+ if path != '/flow.yaml'
52
+ resource.send method, (args.first || {})
53
+ else
54
+ file = args.first[:file]
55
+ request = RestClient::Request.new(
56
+ :method => method.to_sym,
57
+ :url => "#{host}#{path}",
58
+ :user => @pass,
59
+ :password => 'x',
60
+ :payload => {
61
+ :multipart => true,
62
+ :file => File.new(file, 'rb')
63
+ })
64
+ response = request.execute
65
+ end
66
+ rescue => e
67
+ if e.respond_to? :response
68
+ puts e.response
69
+ else
70
+ puts 'Something went wrong, we have been notified.'
71
+ end
72
+
73
+ exit 1
74
+ end
75
+ end
76
+ end
@@ -0,0 +1,55 @@
1
+ module Appfront
2
+ libs = Dir[File.join(File.dirname(__FILE__), "initializers", "*.rb")]
3
+ libs.each { |file| require file }
4
+
5
+ require 'appfront/command'
6
+
7
+ class CLI
8
+ require 'optparse'
9
+
10
+ def self.parse(args)
11
+ options = {}
12
+
13
+ opt_parser = OptionParser.new do |opts|
14
+ opts.banner = "Usage: example.rb [options]"
15
+
16
+ opts.on("-f", "--flow Flow", "Specify the flow involved") do |v|
17
+ options[:flow] = v
18
+ end
19
+
20
+ opts.on("-p", "--provider Provider", "Specify the provider involved") do |v|
21
+ options[:provider] = v
22
+ end
23
+
24
+ opts.on("-a", "--access Access Key", "Specify the access key involved") do |v|
25
+ options[:access] = v
26
+ end
27
+
28
+ opts.on("-s", "--secret Secret Key", "Specify the secret key involved") do |v|
29
+ options[:secret] = v
30
+ end
31
+
32
+ opts.on("-y", "--yaml File", "Specify the yaml file to upload") do |v|
33
+ options[:yaml] = v
34
+ end
35
+
36
+ opts.on("-t", "--tail", "Continue running and print new events (off)") do |v|
37
+ options[:follow] = v
38
+ end
39
+
40
+ opts.on("-h", "--help", "Show this help") do |v|
41
+ options[:help] = true
42
+ end
43
+ end
44
+
45
+ opt_parser.parse! args
46
+
47
+ [ARGV, options]
48
+ end
49
+
50
+ def self.run(args)
51
+ cmd, opts = parse ARGV
52
+ Appfront::Command.run cmd, opts
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,67 @@
1
+ module Appfront::Command
2
+ require 'appfront/api'
3
+ require 'appfront/command/base'
4
+
5
+ libs = Dir[File.join(File.dirname(__FILE__), "command", "*.rb")]
6
+ libs.each { |file| require file }
7
+
8
+ def self.run(args, opts)
9
+ cmd = args.shift
10
+
11
+ unless cmd
12
+ Appfront::Command::Help.root_help
13
+ exit 0
14
+ end
15
+
16
+ klass, act = cmd.split ':', 2
17
+ klass = klass.downcase
18
+
19
+ if klass == 'help'
20
+ m = args.shift || 'root_help'
21
+ m = m.split(':')[0]
22
+
23
+ Appfront::Command::Help.send m
24
+ exit 0
25
+ end
26
+
27
+ unless (klass == 'login' or cmd == 'auth:login')
28
+ Appfront::Command::Auth.authenticate!
29
+ end
30
+
31
+ Appfront::Command::Base.api = Appfront::API.new
32
+
33
+ if Appfront::Command::Alias.respond_to? klass
34
+ Appfront::Command::Alias.send klass.downcase, args, opts
35
+ exit 0
36
+ end
37
+
38
+ act ||= 'list'
39
+
40
+ begin
41
+ klass = "Appfront::Command::#{klass.capitalize}".constantize
42
+ rescue
43
+ unless Appfront::Command::Base.respond_to? cmd
44
+ puts 'Invalid command: ' + cmd
45
+ exit 1
46
+ end
47
+
48
+ return Appfront::Command::Base.send cmd
49
+ end
50
+
51
+ unless klass.respond_to? act
52
+ puts 'Invalid action ' + act
53
+ exit 1
54
+ end
55
+
56
+ method_args = klass.method(act).arity
57
+
58
+ case method_args
59
+ when 0
60
+ klass.send act
61
+ when 1
62
+ klass.send act, opts
63
+ when 2
64
+ klass.send act, args, opts
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,30 @@
1
+ class Appfront::Command::Alias < Appfront::Command::Base
2
+ def self.login(*opts)
3
+ Appfront::Command::Auth.login
4
+ end
5
+
6
+ def self.logout(*opts)
7
+ Appfront::Command::Auth.logout
8
+ end
9
+
10
+ def self.signup(*opts)
11
+ puts 'Please go to: https://appfront.io/signup'
12
+ end
13
+
14
+ def self.version(*opts)
15
+ puts 'Appfront CLI 1.0.0'
16
+ end
17
+
18
+ def self.ls(*opts)
19
+ Appfront::Command::Flows.list
20
+ end
21
+
22
+ def self.create(args, opts)
23
+ Appfront::Command::Flows.create args, opts
24
+ end
25
+
26
+ def self.info(args, opts)
27
+ Appfront::Command::Flows.info opts
28
+ end
29
+
30
+ end
@@ -0,0 +1,67 @@
1
+ class Appfront::Command::Auth < Appfront::Command::Base
2
+ require 'netrc'
3
+
4
+ def self.login
5
+ puts "Enter your Appfront credentials."
6
+
7
+ print "email: "
8
+ email = ask
9
+
10
+ print "password: "
11
+
12
+ echo_off
13
+ pass = ask_for_password
14
+ echo_on
15
+
16
+ api = Appfront::API.new(email: email, password: pass)
17
+ key = api.login
18
+
19
+ netrc.delete 'jarvis.appfront.io'
20
+
21
+ netrc['jarvis.appfront.io'] = email, key
22
+ netrc.save
23
+
24
+ true
25
+ end
26
+
27
+ def self.logout
28
+ netrc.delete 'jarvis.appfront.io'
29
+ netrc.save
30
+
31
+ true
32
+ end
33
+
34
+ def self.authenticate!
35
+ return true if authenticated?
36
+ login
37
+ end
38
+
39
+ def self.credentials
40
+ netrc['jarvis.appfront.io']
41
+ end
42
+
43
+ private
44
+ def self.netrc
45
+ @netrc ||= Netrc.read netrc_path
46
+ end
47
+
48
+ def self.netrc_path
49
+ default = Netrc.default_path
50
+ encrypted = default + ".gpg"
51
+
52
+ File.exists?(encrypted) ? encrypted : default
53
+ end
54
+
55
+ def self.ask_for_password
56
+ echo_off
57
+ password = ask
58
+ puts
59
+ echo_on
60
+
61
+ password
62
+ end
63
+
64
+ def self.authenticated?
65
+ netrc['jarvis.appfront.io'] ? true : false
66
+ end
67
+ end
@@ -0,0 +1,78 @@
1
+ class Module
2
+ def cattr_accessor(attribute_name)
3
+ class_eval <<-CODE
4
+ def self.#{attribute_name}
5
+ @@#{attribute_name} ||= nil
6
+ end
7
+ def self.#{attribute_name}=(value)
8
+ @@#{attribute_name} = value
9
+ end
10
+ CODE
11
+ end
12
+ end
13
+
14
+ class Appfront::Command::Base
15
+ cattr_accessor :api
16
+
17
+ protected
18
+ def self.echo_off
19
+ with_tty do
20
+ system "stty -echo"
21
+ end
22
+ end
23
+
24
+ def self.echo_on
25
+ with_tty do
26
+ system "stty echo"
27
+ end
28
+ end
29
+
30
+ def self.with_tty(&block)
31
+ return unless $stdin.isatty
32
+ yield
33
+ end
34
+
35
+ def self.ask
36
+ $stdin.gets.to_s.strip
37
+ end
38
+
39
+ def self.find_flow!(opts)
40
+ if opts[:flow]
41
+ @flow = opts[:flow]
42
+ end
43
+
44
+ return true if @flow
45
+
46
+ puts 'No flow specified.'
47
+ puts 'Specify which flow to use with --flow FLOW.'
48
+ exit 1
49
+ end
50
+
51
+ def self.which(cmd)
52
+ exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
53
+ ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
54
+ exts.each { |ext|
55
+ exe = File.join(path, "#{cmd}#{ext}")
56
+ return exe if File.executable? exe
57
+ }
58
+ end
59
+ return nil
60
+ end
61
+
62
+ def self.spinner(desc, &block)
63
+ chars = %w{ | / - \\ }
64
+
65
+ t = Thread.new { block.call }
66
+ while t.alive?
67
+ print "#{desc} [#{chars[0]}]\t"
68
+ sleep 0.1
69
+ print "\r"
70
+
71
+ chars.push chars.shift
72
+ end
73
+
74
+ t.join
75
+
76
+ print "#{desc} [ok] \t"
77
+ end
78
+ end
@@ -0,0 +1,97 @@
1
+ class Appfront::Command::Clusters < Appfront::Command::Base
2
+
3
+ def self.list
4
+ clusters = api.get "/clusters"
5
+ puts '=== Clusters List:'
6
+ clusters.each do |cl|
7
+ puts "Cluster #{cl['uuid']} ---> Name: #{cl['name']} \tProvider: #{cl['provider']}"
8
+ end
9
+ end
10
+
11
+ def self.info(args, opts)
12
+ exit 1 unless args[0]
13
+ uuid = args[0]
14
+ exit 1 unless opts[:provider]
15
+ exit 1 unless opts[:provider] == 'amazon' or opts[:provider] == 'digitalocean' or opts[:provider] == 'manual'
16
+ c = api.get "/cluster/#{uuid}"
17
+ puts "=== Cluster #{uuid}: \n"
18
+ puts "\t === Name: #{c['name']}\n"
19
+ puts "\t === Token: #{c['token']}\n"
20
+ puts "\t === Region: #{c['region']}\n"
21
+ puts "\t === Active Boxes: #{c['boxes']}\n"
22
+ puts "\n"
23
+ end
24
+
25
+ def self.create(args, opts)
26
+ exit 1 unless opts[:provider]
27
+ exit 1 unless opts[:provider] == 'amazon' or opts[:provider] == 'digitalocean' or opts[:provider] == 'manual'
28
+
29
+ if args.count == 3
30
+ name = args[0]
31
+ type = args[1]
32
+ region = args[2]
33
+ elsif args.count == 2
34
+ type = args[0]
35
+ region = args[1]
36
+ elsif args.count == 1
37
+ name = args[0]
38
+ type = 'manual'
39
+ region = 'manual'
40
+ end
41
+
42
+ tier = opts[:provider]
43
+ if type == 'manual'
44
+ spinner "Creating new manual cluster ..." do
45
+ @info = api.post "/provider/#{tier}/cluster/#{region}/#{type}" unless name
46
+ @info = api.post "/provider/#{tier}/cluster/#{region}/#{type}", name: name if name
47
+ end
48
+ else
49
+ spinner "Creating new cluster on region #{region}..." do
50
+ @info = api.post "/provider/#{tier}/cluster/#{region}/#{type}" unless name
51
+ @info = api.post "/provider/#{tier}/cluster/#{region}/#{type}", name: name if name
52
+ end
53
+ end
54
+ print "\n"
55
+ end
56
+
57
+ def self.rm(args, opts)
58
+ exit 1 unless args[0]
59
+ uuid = args[0]
60
+ exit 1 unless opts[:provider]
61
+ exit 1 unless opts[:provider] == 'amazon' or opts[:provider] == 'digitalocean' or opts[:provider] == 'manual'
62
+ tier = opts[:provider]
63
+
64
+ spinner "Removing cluster #{uuid}..." do
65
+ sleep 1
66
+ @info = api.delete "/provider/#{tier}/cluster/#{uuid}"
67
+ end
68
+ print "\n"
69
+ end
70
+
71
+ def self.scale_up(args, opts)
72
+ exit 1 unless args[0]
73
+ uuid = args[0]
74
+ exit 1 unless opts[:provider]
75
+ exit 1 unless opts[:provider] == 'amazon' or opts[:provider] == 'digitalocean'
76
+
77
+ spinner "Scaling UP cluster #{uuid}..." do
78
+ api.put "/provider/cluster/#{uuid}/scale/up"
79
+ end
80
+ print "\n"
81
+
82
+ end
83
+
84
+ def self.scale_down(args, opts)
85
+ uuid = args[0]
86
+ exit 1 unless args[0]
87
+ exit 1 unless opts[:provider]
88
+ exit 1 unless opts[:provider] == 'amazon' or opts[:provider] == 'digitalocean'
89
+ exit 1 unless args[0]
90
+
91
+ spinner "Scaling DOWN cluster #{uuid}..." do
92
+ api.put "/provider/cluster/#{uuid}/scale/down"
93
+ end
94
+ print "\n"
95
+
96
+ end
97
+ end
@@ -0,0 +1,70 @@
1
+ class Appfront::Command::Config < Appfront::Command::Base
2
+ def self.set(vars, opts)
3
+ unless vars.size > 0 and vars.all? { |a| a.include?('=') }
4
+ puts "Usage: appfront config:set KEY1=VALUE1 [KEY2=VALUE2 ...]\nMust specify KEY and VALUE to set."
5
+ exit 1
6
+ end
7
+
8
+ vars = parse_vars! vars
9
+
10
+ find_app! opts
11
+
12
+ puts "Setting ENV vars..."
13
+
14
+ api.post "/apps/#{@app}/vars", vars: vars
15
+
16
+ vars.each { |k, v| puts "#{k}:\t#{v}" }
17
+
18
+ puts
19
+ puts 'Please use ps:restart command to restart your app when you\'re ready.'
20
+ end
21
+
22
+ def self.unset(vars, opts)
23
+ if vars.empty?
24
+ puts "Usage: appfront config:unset KEY1 [KEY2 ...]\nMust specify KEY to unset."
25
+ exit 1
26
+ end
27
+
28
+ find_app! opts
29
+
30
+ puts "Unsetting ENV vars..."
31
+
32
+ api.post "/apps/#{@app}/vars/unset", vars: vars
33
+
34
+ puts
35
+ puts 'Please use ps:restart command to restart your app when you\'re ready.'
36
+ end
37
+
38
+ def self.get(args, opts)
39
+ var = args.shift
40
+ find_app! opts
41
+
42
+ vars = api.get("/domains/#{@app}")['vars']
43
+
44
+ value = vars.select {|v| v['key_name'] == var }.first['value'] rescue nil
45
+
46
+ puts value if value
47
+ end
48
+
49
+ def self.list(opts)
50
+ find_app! opts
51
+
52
+ puts "=== #{@app} Config Vars"
53
+
54
+ vars = api.get("/domains/#{@app}")['vars']
55
+
56
+ vars.each {|v| puts "#{v['key_name']}:\t#{v['value']}" }
57
+ end
58
+
59
+ private
60
+ def self.parse_vars!(vars)
61
+ parsed_vars = {}
62
+
63
+ vars.each do |var|
64
+ k, v = var.split '=', 2
65
+ parsed_vars[k] = v || ''
66
+ end
67
+
68
+ parsed_vars
69
+ end
70
+ end
@@ -0,0 +1,68 @@
1
+ class Appfront::Command::Flows < Appfront::Command::Base
2
+
3
+ def self.yaml(opts)
4
+ find_flow! opts
5
+ spinner "Retrieving YAML configuration from Jarvis..." do
6
+ @file = api.get "/flow/#{@flow}/yaml"
7
+ end
8
+ puts "\nYAML file starts from here: \n\n"
9
+ puts @file
10
+ print "\n"
11
+ end
12
+
13
+ def self.up(args, opts)
14
+ spinner "Uploading Flow YAML configuration to Jarvis..." do
15
+ api.post "/flow.yaml", file: args[0]
16
+ end
17
+ puts "\n"
18
+ end
19
+
20
+ def self.update(args, opts)
21
+ spinner "Updating Flow YAML configuration to Jarvis..." do
22
+ api.put "/flow.yaml", file: args[0]
23
+ end
24
+ puts "\n"
25
+ end
26
+
27
+ def self.rm(args, opts)
28
+ find_flow! opts
29
+ spinner "Removing Flow..." do
30
+ api.delete "/flow/#{@flow}"
31
+ end
32
+ puts "\n"
33
+ end
34
+
35
+ def self.info(opts)
36
+ find_flow! opts
37
+
38
+ h = api.get "/flow/#{@flow}"
39
+
40
+ puts "=== #{@flow}"
41
+ puts
42
+ puts "Git URL:\t#{h['git_repo']}"
43
+ puts "Owner Email:\t#{h['owner_email']}"
44
+ puts "Region:\t\tEU"
45
+ # puts "Slug Size:\t#{h['slug_size']}"
46
+ puts "Web URL:\thttp://#{h['live_address']}"
47
+
48
+ return unless (db = h['db'])
49
+
50
+ puts
51
+ puts "=== Database #{db['identifier']}"
52
+ puts "Plan: \t#{db['plan']['name']}"
53
+ puts "Nodes: \t#{db['plan']['nodes']}" unless db['plan']['shared']
54
+ end
55
+
56
+ def self.list
57
+ flows = api.get "/flows"
58
+ unless flows.count == 0
59
+ puts '=== Flows List'
60
+ flows.each do |flow|
61
+ puts "#{flow['name']}:#{flow['tier']} ---> status: #{flow['status']}"
62
+ end
63
+ else
64
+ puts '=== You have no flows.'
65
+ end
66
+ puts "\n"
67
+ end
68
+ end
@@ -0,0 +1,68 @@
1
+ class Appfront::Command::Help < Appfront::Command::Base
2
+ def self.root_help
3
+ puts <<-HELP
4
+ Usage: appfront COMMAND [-f FLOW] [command-specific-options]
5
+
6
+ Primary help topics, type "appfront help TOPIC" for more details:
7
+
8
+ flows # manage flows
9
+ clusters # manage clusters
10
+ providers # manager connection with Amazon or DigitalOcean
11
+
12
+ Additional topics:
13
+
14
+ help # list commands and display help
15
+ version # display version
16
+ HELP
17
+ end
18
+
19
+ def self.flows
20
+ puts <<-HELP
21
+ Flows commands:
22
+
23
+ flows:create [NAME] # create a new flow
24
+ flows:destroy # permanently destroy an flow
25
+ flows:info # show detailed flow information
26
+ flows:list # show flow list
27
+ HELP
28
+ end
29
+
30
+ def self.clusters
31
+ puts <<-HELP
32
+ Clusters commands:
33
+
34
+ clusters:create -p [provider] [NAME] [type] [region] # create a new cluster
35
+ clusters:rm # permanently destroy a cluster
36
+ clusters:info # show detailed cluster information
37
+ clusters:list # show clusters list
38
+ HELP
39
+ end
40
+
41
+ def self.providers
42
+ puts <<-HELP
43
+ Providers commands:
44
+
45
+ providers:connect -p [amazon|digitalocean] -a access_key -s secret_key # connect to the choosen provider
46
+ providers:disconnect # disconnect from provider
47
+ HELP
48
+ end
49
+
50
+
51
+ def self.ps
52
+ puts <<-HELP
53
+ PS commands:
54
+
55
+ ps:resize web=TIER # resize dot to the given tier
56
+ ps:scale web=N [mode=scaling|manual] # scale dots by the given amount
57
+ ps:stop # stop all dots
58
+ ps:reload # restart all dots
59
+ HELP
60
+ end
61
+
62
+ def self.method_missing(m, *args, &block)
63
+ unless self.respond_to? m
64
+ puts "Invalid command: #{m}"
65
+ exit 1
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,15 @@
1
+ class Appfront::Command::Logs < Appfront::Command::Base
2
+ def self.list(opts)
3
+ find_flow! opts
4
+
5
+ max_id = nil
6
+
7
+ begin
8
+ res = api.get "/flow/#{@flow}/logs?max_id=#{max_id}"
9
+ max_id, events = res['max_id'], res['events']
10
+ events.each {|e| puts e }
11
+ sleep 2
12
+ end while opts[:follow]
13
+ end
14
+
15
+ end
@@ -0,0 +1,34 @@
1
+ class Appfront::Command::Providers < Appfront::Command::Base
2
+
3
+ def self.list
4
+ providers = api.get "/providers"
5
+ unless providers.count == 0
6
+ puts '=== Providers Connection Status:'
7
+ providers.each do |p|
8
+ puts "\t#{p['tier'].capitalize} ---> Connected"
9
+ end
10
+ else
11
+ puts '=== No Providers connected with this account'
12
+ end
13
+ end
14
+
15
+ def self.disconnect(args, opts)
16
+ provider = opts[:provider]
17
+ exit 1 unless provider == 'amazon' or provider == 'digitalocean'
18
+
19
+ spinner "Disconnecting #{provider.capitalize}... " do
20
+ api.delete "/provider/#{provider}"
21
+ end
22
+ puts "\n"
23
+ end
24
+
25
+ def self.connect(opts)
26
+ exit 1 unless opts[:provider] and opts[:access] and opts[:secret]
27
+ provider = opts[:provider]
28
+ spinner "Connecting your account with #{provider.capitalize}... " do
29
+ api.post "/provider/#{provider}", access_key: opts[:access], secret_key: opts[:secret]
30
+ end
31
+ puts "\n"
32
+ end
33
+
34
+ end
@@ -0,0 +1,128 @@
1
+ class Appfront::Command::Ps < Appfront::Command::Base
2
+
3
+ def self.reload(args, opts)
4
+ find_flow! opts
5
+ api.put "/flow/#{@flow}/reload"
6
+
7
+ spinner "Reloading Flow..." do
8
+ loop do
9
+ sleep 3
10
+ info = api.get "/flow/#{@flow}"
11
+ break if info['status'] == 'running'
12
+ end
13
+ end
14
+ puts "\n"
15
+ end
16
+
17
+ def self.force_restart(args, opts)
18
+ find_flow! opts
19
+ api.put "/flow/#{@flow}/force-restart"
20
+
21
+ spinner "Force restarting Flow..." do
22
+ loop do
23
+ sleep 3
24
+ info = api.get "/flow/#{@flow}"
25
+ break if info['status'] == 'running'
26
+ end
27
+ end
28
+ puts "\n"
29
+ end
30
+
31
+ def self.stop(args, opts)
32
+ find_flow! opts
33
+ api.put "/flow/#{@flow}/stop"
34
+
35
+ spinner "Stopping Flow..." do
36
+ loop do
37
+ sleep 3
38
+ info = api.get "/flow/#{@flow}"
39
+ break if info['status'] == 'deactivated'
40
+ end
41
+ end
42
+ puts "\n"
43
+ end
44
+
45
+ def self.run(args, opts)
46
+ find_flow! opts
47
+ api.put "/flow/#{@flow}/run"
48
+
49
+ spinner "Running Flow..." do
50
+ loop do
51
+ sleep 3
52
+ info = api.get "/flow/#{@flow}"
53
+ break if info['status'] == 'running'
54
+ end
55
+ end
56
+ puts "\n"
57
+ end
58
+
59
+ def self.scale_up(opts)
60
+ find_flow! opts
61
+
62
+ spinner "Scaling up flow instances..." do
63
+ api.put "/flow/#{@flow}/scale/up"
64
+ end
65
+ puts "\n"
66
+ end
67
+
68
+ def self.scale_down(opts)
69
+ find_flow! opts
70
+
71
+ spinner "Scaling down flow instances..." do
72
+ api.put "/flow/#{@flow}/scale/down"
73
+ end
74
+
75
+ puts "\n"
76
+ end
77
+
78
+ def self.scale(settings, opts)
79
+ find_flow! opts
80
+
81
+ count, mode = nil
82
+ settings.each do |s|
83
+ p, v = s.split('=',2)
84
+ count = v if p == 'instances'
85
+ mode = nil
86
+ end
87
+
88
+ unless count
89
+ puts 'Usage: appfront ps:scale instances=N'
90
+ exit 1
91
+ end
92
+
93
+ params[:scaling] = mode if mode
94
+ params[:instances] = count
95
+
96
+ api.put "/flows/#{@flow}/scaling", params
97
+
98
+ spinner "Scaling flow instances..." do
99
+ loop do
100
+ sleep 3
101
+ info = api.get "/flow/#{@flow}"
102
+ break if info['status'] == 'running'
103
+ end
104
+ end
105
+
106
+ puts "Now running N instances"
107
+ end
108
+
109
+ private
110
+
111
+ def self.time_ago(since)
112
+ if since.is_a?(String)
113
+ since = Time.parse(since)
114
+ end
115
+
116
+ elapsed = Time.now - since
117
+
118
+ message = since.strftime("%Y/%m/%d %H:%M:%S")
119
+ if elapsed <= 60
120
+ message << " (~ #{elapsed.floor}s ago)"
121
+ elsif elapsed <= (60 * 60)
122
+ message << " (~ #{(elapsed / 60).floor}m ago)"
123
+ elsif elapsed <= (60 * 60 * 25)
124
+ message << " (~ #{(elapsed / 60 / 60).floor}h ago)"
125
+ end
126
+ message
127
+ end
128
+ end
@@ -0,0 +1,13 @@
1
+ class String
2
+ def constantize
3
+ names = self.split('::')
4
+ names.shift if names.empty? || names.first.empty?
5
+
6
+ constant = Object
7
+ names.each do |name|
8
+ constant = constant.const_defined?(name) ? constant.const_get(name) : constant.const_missing(name)
9
+ end
10
+ constant
11
+ end
12
+ end
13
+
metadata ADDED
@@ -0,0 +1,102 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: appfront
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Appfront
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-01-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: netrc
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ~>
18
+ - !ruby/object:Gem::Version
19
+ version: 0.7.7
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ~>
25
+ - !ruby/object:Gem::Version
26
+ version: 0.7.7
27
+ - !ruby/object:Gem::Dependency
28
+ name: rest-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: 1.6.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: launchy
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: 2.4.2
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 2.4.2
55
+ description: Appfront Command Line Tool
56
+ email: hello@appfront.io
57
+ executables:
58
+ - appfront
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - bin/appfront
63
+ - lib/appfront.rb
64
+ - lib/appfront/api.rb
65
+ - lib/appfront/cli.rb
66
+ - lib/appfront/command.rb
67
+ - lib/appfront/command/alias.rb
68
+ - lib/appfront/command/auth.rb
69
+ - lib/appfront/command/base.rb
70
+ - lib/appfront/command/clusters.rb
71
+ - lib/appfront/command/config.rb
72
+ - lib/appfront/command/flows.rb
73
+ - lib/appfront/command/help.rb
74
+ - lib/appfront/command/logs.rb
75
+ - lib/appfront/command/providers.rb
76
+ - lib/appfront/command/ps.rb
77
+ - lib/appfront/initializers/string.rb
78
+ homepage: https://appfront.io
79
+ licenses:
80
+ - MIT
81
+ metadata: {}
82
+ post_install_message:
83
+ rdoc_options: []
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
92
+ requirements:
93
+ - - '>='
94
+ - !ruby/object:Gem::Version
95
+ version: '0'
96
+ requirements: []
97
+ rubyforge_project:
98
+ rubygems_version: 2.0.3
99
+ signing_key:
100
+ specification_version: 4
101
+ summary: Appfront Command Line Tool
102
+ test_files: []