rockette 0.0.2 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+ require_relative "../commands/export"
5
+
6
+ module Rockette
7
+ # Export and download APEX application
8
+ class Exporter
9
+ include TextHelper
10
+
11
+ def initialize
12
+ @pastel = Pastel.new
13
+ @prompt = TTY::Prompt.new
14
+ @spinner = TTY::Spinner.new
15
+ end
16
+
17
+ def launch!
18
+ @conf = Psych.load(File.read(CONF))
19
+ puts padder("Choose an application to download.")
20
+ puts
21
+
22
+ # input/action loop
23
+ loop do
24
+ enviros = Rockette::Viewer.new.environments
25
+ list = list_builder(enviros)
26
+ action = @prompt.select("Which environment is the app found?", list)
27
+ break if action == list.length
28
+
29
+ apps_url = enviros[action - 1]["deployment_api"]
30
+ cred = enviros[action - 1]["web_cred"]
31
+ choose_app(apps_url, cred)
32
+ end
33
+ end
34
+
35
+ def do_export(app_id, apps_url, cred)
36
+ response = @prompt.yes?("Would you like to enter a filename for the export?")
37
+ if response == true
38
+ file = @prompt.ask("Please enter your desired filename:")
39
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => app_id, "url" => apps_url, "cred" => cred,
40
+ "file" => file, "force" => true
41
+ else
42
+ puts padder("Saving under default file name: f#{app_id}.sql")
43
+ options = Thor::CoreExt::HashWithIndifferentAccess.new "app_id" => app_id, "url" => apps_url, "cred" => cred, "force" => true
44
+ end
45
+ Rockette::Commands::Export.new(options).execute
46
+ puts
47
+ end
48
+
49
+ protected
50
+
51
+ def choose_app(apps_url, cred)
52
+ loop do
53
+ apps = Rockette::Viewer.new.applications(apps_url, cred)
54
+ list = list_builder(apps)
55
+ action = @prompt.slider("Download application => ", list, default: 1)
56
+ break if action == list.length
57
+
58
+ app_id = apps[action - 1]["application_id"]
59
+ do_export(app_id, apps_url, cred)
60
+ end
61
+ end
62
+
63
+ def list_builder(array)
64
+ names = [] # Start building selection list
65
+ if array[0].key?("name")
66
+ array.each { |n| names << n["name"] }
67
+ else
68
+ array.each { |n| names << "#{n["application_name"]} App ID: #{n["application_id"]}" }
69
+ end
70
+ names << "Go Back"
71
+ names.map.with_index { |n, x| [n, x + 1] }.to_h
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../text_helper"
4
+
5
+ module Rockette
6
+ # View resources
7
+ class Viewer
8
+ include TextHelper
9
+
10
+ def initialize
11
+ @config = TTY::Config.new
12
+ @config.append_path APP_PATH
13
+ @config.read
14
+ @conf = Psych.load(File.read(CONF))
15
+ @body = @conf["token_body"]
16
+ @hdrs = @conf["token_hdrs"]
17
+ #@hdrs["Authorization"] = @conf["web_creds"]["controller_cred"]
18
+ token_url = @conf["rockette"]["controller_url"].sub!('deploy/', '')
19
+ @token = get_token(token_url, "controller_cred")
20
+ @hdrs["Authorization"] = "Bearer " + @token
21
+ @pastel = Pastel.new
22
+ @prompt = TTY::Prompt.new
23
+ @spinner = TTY::Spinner.new # ("[:spinner] Loading APEX environments ...", format: pulse_2)
24
+ @view_actions = { "🏔 APEX Environments" => 1, "🎭 Registered Applications" => 2,
25
+ "🌎 Applications by Environment" => 3, "⬅️ Go Back" => 4 }
26
+ end
27
+
28
+ def self.config
29
+ @config ||= self.class.new.config
30
+ end
31
+
32
+ def launch!
33
+ puts padder("You can view environments or registered applications")
34
+ puts
35
+
36
+ # input/action loop
37
+ loop do
38
+ action = @prompt.select("Which would you like to see?", @view_actions)
39
+ break if action == 4
40
+
41
+ do_action(action)
42
+ end
43
+ end
44
+
45
+ def do_action(action)
46
+ case action
47
+ when 1
48
+ puts
49
+ environments unless @table_env
50
+ spinner(0.5)
51
+ puts @table_env.render(:unicode, resize: true, border: { style: :yellow })
52
+ puts
53
+ when 2
54
+ puts
55
+ registered unless @table_reg
56
+ puts @table_reg.render(:unicode, resize: true, border: { style: :yellow })
57
+ puts
58
+ when 3
59
+ puts
60
+ puts "This can take a while...hang tight!"
61
+ puts
62
+ all_apps unless @table_all_apps
63
+ puts @table_all_apps.render(:unicode, resize: true, border: { style: :yellow })
64
+ puts
65
+ else
66
+ puts "\nI don't understand that command.\n\n"
67
+ end
68
+ end
69
+
70
+ def add_web_cred(env_cred, env_name)
71
+ puts "You are attempting to access a resource that requires authentication."
72
+ puts "Please enter the OAuth client credentials for the #{env_name} environment."
73
+ user = @prompt.ask("User:")
74
+ pass = @prompt.ask("Pass:")
75
+ basey = 'Basic ' + Base64.encode64(user + ":" + pass).tr("\n", "")
76
+ @config.set(:web_creds, env_cred.to_sym, value: basey)
77
+ @config.write(force: true)
78
+ refresh_conf
79
+ end
80
+
81
+ def ape_e_i(uri, headers = @hdrs)
82
+ response = Rester.new(url: uri, headers: headers).rest_try
83
+ bail unless response
84
+ abort padder("#{uri} didn't work. Received: #{response.code}") unless response.code == 200
85
+ response
86
+ end
87
+
88
+ def applications(url, cred)
89
+ headers = @hdrs
90
+ #@hdrs["Authorization"] = @conf["web_creds"][cred]
91
+ @token = get_token(url, cred)
92
+ @hdrs["Authorization"] = "Bearer " + @token
93
+ uri = "#{url}deploy/apps/"
94
+
95
+ response = ape_e_i(uri, @hdrs)
96
+ @hdrs = headers
97
+ JSON.parse(response.body)["items"]
98
+ end
99
+
100
+ def environments
101
+ uri = "#{@conf["rockette"]["controller_url"]}deploy/environments/"
102
+ response = ape_e_i(uri)
103
+ @table_env = TTY::Table.new(header: ["Environment Name", "API", "Domain", "Owner", "Workspace", "Web Cred"])
104
+ items = JSON.parse(response.body)["items"]
105
+ items.each { |h| @table_env << [h["name"], h["deployment_api"], h["domain"], h["owner"], h["workspace"], h["web_cred"]] }
106
+ end
107
+
108
+ def get_token(url, cred)
109
+ @hdrs["Authorization"] = @conf["web_creds"][cred]
110
+ token_url = url + "oauth/token"
111
+ response = Rester.new(headers: @hdrs, meth: "Post", params: @body, url: token_url).rest_try
112
+ return JSON.parse(response.body)["access_token"]
113
+ end
114
+
115
+ def registered
116
+ uri = "#{@conf["rockette"]["controller_url"]}deploy/registered_apps/"
117
+ response = ape_e_i(uri)
118
+ @table_reg = TTY::Table.new(header: ["Registered Name", "Source App ID", "Source URI", "Target App ID",
119
+ "Target URI"])
120
+ JSON.parse(response.body)["items"].each do |h|
121
+ @table_reg << [h["registered_name"], h["src_app_id"], h["src_url"], h["tgt_app_id"], h["tgt_url"]]
122
+ end
123
+ end
124
+
125
+ def all_apps
126
+ environments unless @table_env
127
+ @table_all_apps = TTY::Table.new(header: ["Environment Name", "Application Name", "Application ID"])
128
+ @table_env.each do |env|
129
+ next if env[0] == "Environment Name"
130
+
131
+ creds = Hash.new
132
+ creds = @conf["web_creds"]
133
+ add_web_cred(env[5], env[0]) unless creds.has_key?(env[5])
134
+
135
+ apps = applications(env[1], env[5])
136
+ apps.each do |app|
137
+ @table_all_apps << [env[0], app["application_name"], app["application_id"]]
138
+ end
139
+ end
140
+ end
141
+
142
+ def refresh_conf
143
+ @config.read
144
+ @conf = Psych.load(File.read(CONF))
145
+ end
146
+
147
+ def spinner(dur=1)
148
+ @spinner.auto_spin
149
+ sleep(dur)
150
+ @spinner.stop
151
+ end
152
+
153
+ end
154
+ end
@@ -0,0 +1,85 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "controller/configurator"
4
+ require_relative "controller/deployer"
5
+ require_relative "controller/exporter"
6
+ require_relative "controller/viewer"
7
+ require_relative "text_helper"
8
+
9
+ module Rockette
10
+ MAIN_ACTIONS = { "🔭 View Resources" => 1, "🚀 Deploy" => 2, "📥 Export" => 3,
11
+ "🛠 Configure" => 4, "❌ Quit" => 5 }.freeze
12
+ # Manage Rockette in interactive mode
13
+ class Controller
14
+ def initialize
15
+ @conf = Psych.load(File.read(CONF))
16
+ @pastel = Pastel.new
17
+ @prompt = TTY::Prompt.new
18
+ end
19
+
20
+ def launch!
21
+ introduction
22
+
23
+ if @conf["rockette"]["check_for_url"] && @conf["rockette"]["controller_url"].length < 10
24
+ configurer = Rockette::Configurator.new
25
+ configurer.first_run
26
+ end
27
+
28
+ # input/action loop
29
+ loop do
30
+ action = actions
31
+ break if action == 5
32
+
33
+ do_action(action)
34
+ end
35
+ conclusion
36
+ end
37
+
38
+ private
39
+
40
+ def introduction
41
+ font = TTY::Font.new(:starwars)
42
+ puts "-" * 85
43
+ puts
44
+ puts @pastel.yellow(font.write("Rockette"))
45
+ puts
46
+ puts "-" * 85
47
+ puts "Version: " + VERSION
48
+ puts "-" * 14
49
+ puts
50
+ puts "Rockette helps export and deploy APEX applications."
51
+ puts
52
+ end
53
+
54
+ def conclusion
55
+ puts
56
+ puts "-" * 85
57
+ puts @pastel.yellow("Have a good one!".upcase.center(85))
58
+ puts "-" * 85
59
+ puts
60
+ end
61
+
62
+ def actions
63
+ @prompt.select("What would you like to do?", MAIN_ACTIONS)
64
+ end
65
+
66
+ def do_action(action)
67
+ case action
68
+ when 1
69
+ viewer = Rockette::Viewer.new
70
+ viewer.launch!
71
+ when 2
72
+ deployer = Rockette::Deployer.new
73
+ deployer.launch!
74
+ when 3
75
+ exporter = Rockette::Exporter.new
76
+ exporter.launch!
77
+ when 4
78
+ configurer = Rockette::Configurator.new
79
+ configurer.launch!
80
+ else
81
+ puts "\nI don't understand that command.\n\n"
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Rockette
4
+ # configurable rest-client calls with error handling and auto retries
5
+ class Rester
6
+ VERBS = {
7
+ "delete" => :Delete,
8
+ "get" => :Get,
9
+ "post" => :Post,
10
+ "put" => :Put
11
+ }.freeze
12
+
13
+ def initialize(headers: {}, meth: "Get", params: {}, url: "https://array/", config: {})
14
+ @headers = headers
15
+ @meth = meth
16
+ @params = params
17
+ @url = url
18
+ @config = config
19
+ @config["timeout"] = @config["timeout"] ||= 30
20
+ end
21
+
22
+ def make_call
23
+ response = RestClient::Request.execute(headers: @headers,
24
+ method: VERBS[@meth.downcase], payload: @params,
25
+ timeout: @config["timeout"], url: @url, verify_ssl: false)
26
+ rescue SocketError, IOError => e
27
+ puts "#{e.class}: #{e.message}"
28
+ nil
29
+ rescue StandardError => e
30
+ e.response
31
+ else
32
+ response
33
+ end
34
+
35
+ def cookie
36
+ if @url =~ %r{auth/session}
37
+ response = make_call
38
+ raise "There was an issue getting a cookie!" unless response.code == 200
39
+
40
+ (response.cookies.map { |key, val| "#{key}=#{val}" })[0]
41
+ else
42
+ error_text("cookie", @url.to_s, "auth/session")
43
+ end
44
+ end
45
+
46
+ # use rest-client with retry
47
+ def rest_try(tries = 3)
48
+ tries.times do |i|
49
+ response = make_call
50
+ unless response.nil?
51
+ break response if (200..299).include? response.code
52
+ break response if i > 1
53
+ end
54
+ puts "Failed #{@meth} on #{@url}, retry...#{i + 1}"
55
+ sleep 3 unless i > 1
56
+ return nil if i > 1 # Handles socket errors, etc. where there is no response.
57
+ end
58
+ end
59
+
60
+ private
61
+
62
+ def error_text(method_name, url, wanted)
63
+ {
64
+ "response" =>
65
+ "ERROR: Wrong url for the #{method_name} method.\n"\
66
+ "Sent: #{url}\n"\
67
+ "Expected: \"#{wanted}\" as part of the url.",
68
+ "status" => 400
69
+ }
70
+ end
71
+
72
+ def responder(response)
73
+ {
74
+ "response" => JSON.parse(response.body),
75
+ "status" => response.code.to_i
76
+ }
77
+ end
78
+ end
79
+ end
@@ -19,6 +19,12 @@ module TextHelper
19
19
  exit
20
20
  end
21
21
 
22
+ def no_rockette_dir
23
+ puts "Unable to locate a suitable place for the .rockette directory."
24
+ puts "Please double check your home directory..."
25
+ exit
26
+ end
27
+
22
28
  def padder(str)
23
29
  "\n#{str}\n"
24
30
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Rockette
4
- VERSION = "0.0.2"
4
+ VERSION = "0.0.6"
5
5
  end
data/lib/rockette.rb CHANGED
@@ -1,91 +1,35 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "erb"
4
- require "json"
5
- require "psych"
6
- require "rest-client"
7
- require "thor"
8
- require_relative "rockette/cli"
9
- require_relative "rockette/text_helper"
10
- require_relative "rockette/version"
3
+ require_relative "requirements"
4
+
5
+ # Set paths
6
+ APP_PATH = if File.exist?(File.join("/", "usr", "app"))
7
+ File.join("/", "usr", "app", ".rockette")
8
+ elsif File.exist?(Dir.home)
9
+ File.join(Dir.home, ".rockette")
10
+ else
11
+ no_rockette_dir
12
+ end
13
+ lib_path = File.expand_path("../lib", __dir__)
14
+ tem_path = File.expand_path("../templates", __dir__)
15
+ $LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include?(lib_path)
16
+
17
+ # Create directories and config file if needed
18
+ Dir.mkdir(APP_PATH) unless File.exist?(APP_PATH)
19
+ unless File.exist?(File.join(APP_PATH, "config.yml"))
20
+ template = File.read(File.join(tem_path, "config.yml.erb"))
21
+ data = ERB.new(template).result(binding)
22
+ File.write(File.join(APP_PATH, "config.yml"), data)
23
+ end
24
+ Dir.mkdir(File.join(APP_PATH, "exports")) unless File.exist?(File.join(APP_PATH, "exports"))
25
+
26
+ # Set config and export directory paths
27
+ CONF = File.join(APP_PATH, "config.yml")
28
+ ENV["THOR_SILENCE_DEPRECATION"] = "true"
29
+ EXPORT_DIR = File.join(APP_PATH, "exports")
11
30
 
12
31
  # APEX deployment
13
32
  module Rockette
14
33
  class Error < StandardError; end
15
-
16
- # rest-client calls with error handling and auto retries
17
- class Rester
18
- VERBS = {
19
- "delete" => :Delete,
20
- "get" => :Get,
21
- "post" => :Post,
22
- "put" => :Put
23
- }.freeze
24
-
25
- def initialize(headers: {}, meth: "Get", params: {}, url: "https://array/", config: {})
26
- @headers = headers
27
- @meth = meth
28
- @params = params
29
- @url = url
30
- @config = config
31
- @config["timeout"] = @config["timeout"] ||= 30
32
- end
33
-
34
- def make_call
35
- response = RestClient::Request.execute(headers: @headers,
36
- method: VERBS[@meth.downcase], payload: @params,
37
- timeout: @config["timeout"], url: @url, verify_ssl: false)
38
- rescue SocketError, IOError => e
39
- puts "#{e.class}: #{e.message}"
40
- nil
41
- rescue StandardError => e
42
- e.response
43
- else
44
- response
45
- end
46
-
47
- def cookie
48
- if @url =~ %r{auth/session}
49
- response = make_call
50
- raise "There was an issue getting a cookie!" unless response.code == 200
51
-
52
- (response.cookies.map { |key, val| "#{key}=#{val}" })[0]
53
- else
54
- error_text("cookie", @url.to_s, "auth/session")
55
- end
56
- end
57
-
58
- # use rest-client with retry
59
- def rest_try
60
- 3.times do |i|
61
- response = make_call
62
- unless response.nil?
63
- break response if (200..299).include? response.code
64
- break response if i > 1
65
- end
66
- puts "Failed #{@meth} on #{@url}, retry...#{i + 1}"
67
- sleep 3 unless i > 1
68
- return nil if i > 1 # Handles socket errors, etc. where there is no response.
69
- end
70
- end
71
-
72
- private
73
-
74
- def error_text(method_name, url, wanted)
75
- {
76
- "response" =>
77
- "ERROR: Wrong url for the #{method_name} method.\n"\
78
- "Sent: #{url}\n"\
79
- "Expected: \"#{wanted}\" as part of the url.",
80
- "status" => 400
81
- }
82
- end
83
-
84
- def responder(response)
85
- {
86
- "response" => JSON.parse(response.body),
87
- "status" => response.code.to_i
88
- }
89
- end
90
- end
34
+ # Code in lib/rockette
91
35
  end
data/rockette.gemspec CHANGED
@@ -32,10 +32,15 @@ Gem::Specification.new do |spec|
32
32
  # Dev dependencies
33
33
  spec.add_development_dependency "pry", "~> 0.0"
34
34
 
35
- # Uncomment to register a new dependency of your gem
35
+ # Dependencies
36
+ spec.add_dependency "oci", "~> 2.0"
37
+ spec.add_dependency "pastel", "~> 0.0"
36
38
  spec.add_dependency "rest-client", "~> 2.0"
37
39
  spec.add_dependency "thor", "~> 1.0"
38
-
39
- # For more information and examples about making a new gem, checkout our
40
- # guide at: https://bundler.io/guides/creating_gem.html
40
+ spec.add_dependency "tty-config", "~> 0.0"
41
+ spec.add_dependency "tty-editor", "~> 0.0"
42
+ spec.add_dependency "tty-font", "~> 0.0"
43
+ spec.add_dependency "tty-prompt", "~> 0.0"
44
+ spec.add_dependency "tty-spinner", "~> 0.0"
45
+ spec.add_dependency "tty-table", "~> 0.0"
41
46
  end
@@ -1,17 +1,9 @@
1
1
  ---
2
- push_hdrs:
3
- Content-Type: application/json
4
- created_by: dcs_automation
5
- message_date: ''
6
- msg_from_addr: ''
7
- msg_from_name: ''
8
- file_charset: UTF-8
9
- file_mimetype: text/plain
10
- file_name: ''
11
- file_type: sql
12
- tags: ''
13
- target_use: push_deployment
14
- deploy_body:
15
- app_id_src: ''
16
- app_id_tgt: ''
17
- blob_url: https://local.data_loader
2
+ token_body:
3
+ grant_type: client_credentials
4
+ token_hdrs:
5
+ Content-Type: application/x-www-form-urlencoded
6
+ rockette:
7
+ check_for_url: true
8
+ controller_cred: ''
9
+ controller_url: ''