rockette 0.0.2 → 0.0.6

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.
@@ -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: ''