nucleus 0.1.0

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.
Files changed (224) hide show
  1. checksums.yaml +7 -0
  2. data/.gitattributes +1 -0
  3. data/.gitignore +19 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +44 -0
  6. data/.travis.yml +21 -0
  7. data/CHANGELOG.md +19 -0
  8. data/CONTRIBUTING.md +13 -0
  9. data/Gemfile +16 -0
  10. data/Guardfile +22 -0
  11. data/LICENSE +21 -0
  12. data/README.md +675 -0
  13. data/Rakefile +137 -0
  14. data/bin/nucleus +91 -0
  15. data/bin/nucleus.bat +1 -0
  16. data/config.ru +18 -0
  17. data/config/adapters/cloud_control.yml +32 -0
  18. data/config/adapters/cloud_foundry_v2.yml +61 -0
  19. data/config/adapters/heroku.yml +13 -0
  20. data/config/adapters/openshift_v2.yml +20 -0
  21. data/config/nucleus_config.rb +47 -0
  22. data/lib/nucleus.rb +13 -0
  23. data/lib/nucleus/adapter_resolver.rb +115 -0
  24. data/lib/nucleus/adapters/base_adapter.rb +109 -0
  25. data/lib/nucleus/adapters/buildpack_translator.rb +79 -0
  26. data/lib/nucleus/adapters/v1/cloud_control/application.rb +108 -0
  27. data/lib/nucleus/adapters/v1/cloud_control/authentication.rb +27 -0
  28. data/lib/nucleus/adapters/v1/cloud_control/buildpacks.rb +23 -0
  29. data/lib/nucleus/adapters/v1/cloud_control/cloud_control.rb +153 -0
  30. data/lib/nucleus/adapters/v1/cloud_control/data.rb +76 -0
  31. data/lib/nucleus/adapters/v1/cloud_control/domains.rb +68 -0
  32. data/lib/nucleus/adapters/v1/cloud_control/lifecycle.rb +27 -0
  33. data/lib/nucleus/adapters/v1/cloud_control/log_poller.rb +71 -0
  34. data/lib/nucleus/adapters/v1/cloud_control/logs.rb +103 -0
  35. data/lib/nucleus/adapters/v1/cloud_control/regions.rb +32 -0
  36. data/lib/nucleus/adapters/v1/cloud_control/scaling.rb +17 -0
  37. data/lib/nucleus/adapters/v1/cloud_control/semantic_errors.rb +31 -0
  38. data/lib/nucleus/adapters/v1/cloud_control/services.rb +162 -0
  39. data/lib/nucleus/adapters/v1/cloud_control/token.rb +17 -0
  40. data/lib/nucleus/adapters/v1/cloud_control/vars.rb +88 -0
  41. data/lib/nucleus/adapters/v1/cloud_foundry_v2/app_states.rb +28 -0
  42. data/lib/nucleus/adapters/v1/cloud_foundry_v2/application.rb +111 -0
  43. data/lib/nucleus/adapters/v1/cloud_foundry_v2/authentication.rb +17 -0
  44. data/lib/nucleus/adapters/v1/cloud_foundry_v2/buildpacks.rb +23 -0
  45. data/lib/nucleus/adapters/v1/cloud_foundry_v2/cloud_foundry_v2.rb +141 -0
  46. data/lib/nucleus/adapters/v1/cloud_foundry_v2/data.rb +97 -0
  47. data/lib/nucleus/adapters/v1/cloud_foundry_v2/domains.rb +149 -0
  48. data/lib/nucleus/adapters/v1/cloud_foundry_v2/lifecycle.rb +41 -0
  49. data/lib/nucleus/adapters/v1/cloud_foundry_v2/logs.rb +303 -0
  50. data/lib/nucleus/adapters/v1/cloud_foundry_v2/regions.rb +33 -0
  51. data/lib/nucleus/adapters/v1/cloud_foundry_v2/scaling.rb +15 -0
  52. data/lib/nucleus/adapters/v1/cloud_foundry_v2/semantic_errors.rb +27 -0
  53. data/lib/nucleus/adapters/v1/cloud_foundry_v2/services.rb +286 -0
  54. data/lib/nucleus/adapters/v1/cloud_foundry_v2/vars.rb +80 -0
  55. data/lib/nucleus/adapters/v1/heroku/app_states.rb +57 -0
  56. data/lib/nucleus/adapters/v1/heroku/application.rb +93 -0
  57. data/lib/nucleus/adapters/v1/heroku/authentication.rb +27 -0
  58. data/lib/nucleus/adapters/v1/heroku/buildpacks.rb +27 -0
  59. data/lib/nucleus/adapters/v1/heroku/data.rb +78 -0
  60. data/lib/nucleus/adapters/v1/heroku/domains.rb +43 -0
  61. data/lib/nucleus/adapters/v1/heroku/heroku.rb +146 -0
  62. data/lib/nucleus/adapters/v1/heroku/lifecycle.rb +51 -0
  63. data/lib/nucleus/adapters/v1/heroku/logs.rb +108 -0
  64. data/lib/nucleus/adapters/v1/heroku/regions.rb +42 -0
  65. data/lib/nucleus/adapters/v1/heroku/scaling.rb +28 -0
  66. data/lib/nucleus/adapters/v1/heroku/semantic_errors.rb +23 -0
  67. data/lib/nucleus/adapters/v1/heroku/services.rb +168 -0
  68. data/lib/nucleus/adapters/v1/heroku/vars.rb +65 -0
  69. data/lib/nucleus/adapters/v1/openshift_v2/app_states.rb +68 -0
  70. data/lib/nucleus/adapters/v1/openshift_v2/application.rb +108 -0
  71. data/lib/nucleus/adapters/v1/openshift_v2/authentication.rb +21 -0
  72. data/lib/nucleus/adapters/v1/openshift_v2/data.rb +96 -0
  73. data/lib/nucleus/adapters/v1/openshift_v2/domains.rb +37 -0
  74. data/lib/nucleus/adapters/v1/openshift_v2/lifecycle.rb +60 -0
  75. data/lib/nucleus/adapters/v1/openshift_v2/logs.rb +106 -0
  76. data/lib/nucleus/adapters/v1/openshift_v2/openshift_v2.rb +125 -0
  77. data/lib/nucleus/adapters/v1/openshift_v2/regions.rb +58 -0
  78. data/lib/nucleus/adapters/v1/openshift_v2/scaling.rb +39 -0
  79. data/lib/nucleus/adapters/v1/openshift_v2/semantic_errors.rb +40 -0
  80. data/lib/nucleus/adapters/v1/openshift_v2/services.rb +173 -0
  81. data/lib/nucleus/adapters/v1/openshift_v2/vars.rb +49 -0
  82. data/lib/nucleus/adapters/v1/stub_adapter.rb +464 -0
  83. data/lib/nucleus/core/adapter_authentication_inductor.rb +62 -0
  84. data/lib/nucleus/core/adapter_extensions/auth/auth_client.rb +44 -0
  85. data/lib/nucleus/core/adapter_extensions/auth/authentication_retry_wrapper.rb +79 -0
  86. data/lib/nucleus/core/adapter_extensions/auth/expiring_token_auth_client.rb +53 -0
  87. data/lib/nucleus/core/adapter_extensions/auth/http_basic_auth_client.rb +37 -0
  88. data/lib/nucleus/core/adapter_extensions/auth/o_auth2_auth_client.rb +95 -0
  89. data/lib/nucleus/core/adapter_extensions/auth/token_auth_client.rb +36 -0
  90. data/lib/nucleus/core/adapter_extensions/http_client.rb +177 -0
  91. data/lib/nucleus/core/adapter_extensions/http_tail_client.rb +26 -0
  92. data/lib/nucleus/core/adapter_extensions/tail_stopper.rb +25 -0
  93. data/lib/nucleus/core/common/errors/ambiguous_adapter_error.rb +7 -0
  94. data/lib/nucleus/core/common/errors/file_existence_error.rb +7 -0
  95. data/lib/nucleus/core/common/errors/startup_error.rb +12 -0
  96. data/lib/nucleus/core/common/exit_codes.rb +25 -0
  97. data/lib/nucleus/core/common/files/application_repo_sanitizer.rb +52 -0
  98. data/lib/nucleus/core/common/files/archive_extractor.rb +112 -0
  99. data/lib/nucleus/core/common/files/archiver.rb +91 -0
  100. data/lib/nucleus/core/common/link_generator.rb +46 -0
  101. data/lib/nucleus/core/common/logging/logging.rb +52 -0
  102. data/lib/nucleus/core/common/logging/multi_logger.rb +59 -0
  103. data/lib/nucleus/core/common/logging/request_log_formatter.rb +48 -0
  104. data/lib/nucleus/core/common/ssh_handler.rb +108 -0
  105. data/lib/nucleus/core/common/stream_callback.rb +27 -0
  106. data/lib/nucleus/core/common/thread_config_accessor.rb +85 -0
  107. data/lib/nucleus/core/common/url_converter.rb +28 -0
  108. data/lib/nucleus/core/enums/application_states.rb +26 -0
  109. data/lib/nucleus/core/enums/logfile_types.rb +28 -0
  110. data/lib/nucleus/core/error_messages.rb +127 -0
  111. data/lib/nucleus/core/errors/adapter_error.rb +13 -0
  112. data/lib/nucleus/core/errors/adapter_missing_implementation_error.rb +12 -0
  113. data/lib/nucleus/core/errors/adapter_request_error.rb +10 -0
  114. data/lib/nucleus/core/errors/adapter_resource_not_found_error.rb +10 -0
  115. data/lib/nucleus/core/errors/endpoint_authentication_error.rb +10 -0
  116. data/lib/nucleus/core/errors/platform_specific_semantic_error.rb +12 -0
  117. data/lib/nucleus/core/errors/platform_timeout_error.rb +10 -0
  118. data/lib/nucleus/core/errors/platform_unavailable_error.rb +10 -0
  119. data/lib/nucleus/core/errors/semantic_adapter_request_error.rb +19 -0
  120. data/lib/nucleus/core/errors/unknown_adapter_call_error.rb +10 -0
  121. data/lib/nucleus/core/file_handling/archive_converter.rb +29 -0
  122. data/lib/nucleus/core/file_handling/file_manager.rb +64 -0
  123. data/lib/nucleus/core/file_handling/git_deployer.rb +133 -0
  124. data/lib/nucleus/core/file_handling/git_repo_analyzer.rb +23 -0
  125. data/lib/nucleus/core/import/adapter_configuration.rb +53 -0
  126. data/lib/nucleus/core/import/vendor_parser.rb +28 -0
  127. data/lib/nucleus/core/import/version_detector.rb +18 -0
  128. data/lib/nucleus/core/models/abstract_model.rb +29 -0
  129. data/lib/nucleus/core/models/endpoint.rb +30 -0
  130. data/lib/nucleus/core/models/provider.rb +26 -0
  131. data/lib/nucleus/core/models/vendor.rb +22 -0
  132. data/lib/nucleus/ext/kernel.rb +5 -0
  133. data/lib/nucleus/ext/regexp.rb +49 -0
  134. data/lib/nucleus/os.rb +15 -0
  135. data/lib/nucleus/root_dir.rb +13 -0
  136. data/lib/nucleus/scripts/finalize.rb +8 -0
  137. data/lib/nucleus/scripts/initialize.rb +9 -0
  138. data/lib/nucleus/scripts/initialize_config_defaults.rb +26 -0
  139. data/lib/nucleus/scripts/load.rb +17 -0
  140. data/lib/nucleus/scripts/load_dependencies.rb +43 -0
  141. data/lib/nucleus/scripts/setup_config.rb +28 -0
  142. data/lib/nucleus/scripts/shutdown.rb +11 -0
  143. data/lib/nucleus/version.rb +3 -0
  144. data/nucleus.gemspec +88 -0
  145. data/public/robots.txt +2 -0
  146. data/public/swagger-ui/css/reset.css +125 -0
  147. data/public/swagger-ui/css/screen.css +1224 -0
  148. data/public/swagger-ui/images/apple-touch-icon-114x114.png +0 -0
  149. data/public/swagger-ui/images/apple-touch-icon-120x120.png +0 -0
  150. data/public/swagger-ui/images/apple-touch-icon-144x144.png +0 -0
  151. data/public/swagger-ui/images/apple-touch-icon-152x152.png +0 -0
  152. data/public/swagger-ui/images/apple-touch-icon-57x57.png +0 -0
  153. data/public/swagger-ui/images/apple-touch-icon-60x60.png +0 -0
  154. data/public/swagger-ui/images/apple-touch-icon-72x72.png +0 -0
  155. data/public/swagger-ui/images/apple-touch-icon-76x76.png +0 -0
  156. data/public/swagger-ui/images/explorer_icons.png +0 -0
  157. data/public/swagger-ui/images/favicon-128.png +0 -0
  158. data/public/swagger-ui/images/favicon-16x16.png +0 -0
  159. data/public/swagger-ui/images/favicon-196x196.png +0 -0
  160. data/public/swagger-ui/images/favicon-32x32.png +0 -0
  161. data/public/swagger-ui/images/favicon-96x96.png +0 -0
  162. data/public/swagger-ui/images/favicon.ico +0 -0
  163. data/public/swagger-ui/images/logo_small.png +0 -0
  164. data/public/swagger-ui/images/mstile-144x144.png +0 -0
  165. data/public/swagger-ui/images/mstile-150x150.png +0 -0
  166. data/public/swagger-ui/images/mstile-310x150.png +0 -0
  167. data/public/swagger-ui/images/mstile-310x310.png +0 -0
  168. data/public/swagger-ui/images/mstile-70x70.png +0 -0
  169. data/public/swagger-ui/images/pet_store_api.png +0 -0
  170. data/public/swagger-ui/images/throbber.gif +0 -0
  171. data/public/swagger-ui/images/wordnik_api.png +0 -0
  172. data/public/swagger-ui/index.html +107 -0
  173. data/public/swagger-ui/lib/backbone-min.js +38 -0
  174. data/public/swagger-ui/lib/handlebars-1.0.0.js +2278 -0
  175. data/public/swagger-ui/lib/highlight.7.3.pack.js +1 -0
  176. data/public/swagger-ui/lib/jquery-1.8.0.min.js +2 -0
  177. data/public/swagger-ui/lib/jquery.ba-bbq.min.js +18 -0
  178. data/public/swagger-ui/lib/jquery.slideto.min.js +1 -0
  179. data/public/swagger-ui/lib/jquery.wiggle.min.js +8 -0
  180. data/public/swagger-ui/lib/shred.bundle.js +2765 -0
  181. data/public/swagger-ui/lib/shred/content.js +193 -0
  182. data/public/swagger-ui/lib/swagger-oauth.js +211 -0
  183. data/public/swagger-ui/lib/swagger.js +1653 -0
  184. data/public/swagger-ui/lib/underscore-min.js +32 -0
  185. data/public/swagger-ui/o2c.html +15 -0
  186. data/public/swagger-ui/redirect.html +14 -0
  187. data/public/swagger-ui/swagger-ui.js +2324 -0
  188. data/public/swagger-ui/swagger-ui.min.js +1 -0
  189. data/schemas/api.adapter.schema.yml +31 -0
  190. data/schemas/api.requirements.schema.yml +17 -0
  191. data/spec/factories/models.rb +61 -0
  192. data/spec/integration/api/auth_spec.rb +58 -0
  193. data/spec/integration/api/endpoints_spec.rb +167 -0
  194. data/spec/integration/api/errors_spec.rb +47 -0
  195. data/spec/integration/api/providers_spec.rb +157 -0
  196. data/spec/integration/api/swagger_schema_spec.rb +64 -0
  197. data/spec/integration/api/vendors_spec.rb +45 -0
  198. data/spec/integration/integration_spec_helper.rb +27 -0
  199. data/spec/integration/test_data_generator.rb +55 -0
  200. data/spec/nucleus_git_key.pem +51 -0
  201. data/spec/spec_helper.rb +98 -0
  202. data/spec/support/shared_example_request_types.rb +99 -0
  203. data/spec/test_suites.rake +31 -0
  204. data/spec/unit/adapters/archive_converter_spec.rb +25 -0
  205. data/spec/unit/adapters/file_manager_spec.rb +93 -0
  206. data/spec/unit/adapters/git_deployer_spec.rb +262 -0
  207. data/spec/unit/adapters/v1/stub_spec.rb +14 -0
  208. data/spec/unit/common/helpers/auth_helper_spec.rb +73 -0
  209. data/spec/unit/common/oauth2_auth_client_spec.rb +108 -0
  210. data/spec/unit/common/regexp_spec.rb +33 -0
  211. data/spec/unit/common/request_log_formatter_spec.rb +108 -0
  212. data/spec/unit/common/thread_config_accessor_spec.rb +97 -0
  213. data/spec/unit/models/endpoint_spec.rb +83 -0
  214. data/spec/unit/models/provider_spec.rb +102 -0
  215. data/spec/unit/models/vendor_spec.rb +100 -0
  216. data/spec/unit/schemas/adapter_schema_spec.rb +16 -0
  217. data/spec/unit/schemas/adapter_validation_spec.rb +56 -0
  218. data/spec/unit/schemas/requirements_schema_spec.rb +16 -0
  219. data/spec/unit/unit_spec_helper.rb +11 -0
  220. data/tasks/compatibility.rake +113 -0
  221. data/tasks/evaluation.rake +162 -0
  222. data/wiki/adapter_tests.md +99 -0
  223. data/wiki/implement_new_adapter.md +155 -0
  224. metadata +836 -0
@@ -0,0 +1,137 @@
1
+ import 'tasks/compatibility.rake'
2
+ import 'tasks/evaluation.rake'
3
+ import 'spec/test_suites.rake'
4
+
5
+ require 'rake'
6
+ require 'rubygems'
7
+ require 'bundler'
8
+ require 'bundler/gem_tasks'
9
+ require 'rspec/core/rake_task'
10
+ require 'rainbow/ext/string' unless String.respond_to?(:color)
11
+ require 'rubocop/rake_task'
12
+
13
+ RuboCop::RakeTask.new
14
+
15
+ # first check code style, then execute the tests
16
+ task default: [:rubocop, :spec]
17
+
18
+ # map spec task to all test suites
19
+ task :spec do
20
+ # first, run all tests
21
+ Rake::Task['spec:suite:all'].invoke
22
+ # if on the CI system, push coverage report to codeclimate
23
+ if ENV['CODECLIMATE_REPO_TOKEN']
24
+ require 'simplecov'
25
+ require 'codeclimate-test-reporter'
26
+ CodeClimate::TestReporter::Formatter.new.format(SimpleCov.result)
27
+ end
28
+ end
29
+
30
+ task :doc_toc do
31
+ File.open('README.md', 'r') do |f|
32
+ f.each_line do |line|
33
+ forbidden_words = ['Table of contents', 'define', 'pragma']
34
+ next if !line.start_with?('#') || forbidden_words.any? { |w| line =~ /#{w}/ }
35
+
36
+ title = line.delete('#').strip
37
+ href = title.tr(' ', '-').downcase
38
+ puts ' ' * (line.count('#') - 1) + "* [#{title}](\##{href})"
39
+ end
40
+ end
41
+ end
42
+
43
+ desc 'Record all adapter tests'
44
+ task :record do
45
+ # http://www.relishapp.com/vcr/vcr/v/2-9-3/docs/record-modes
46
+ ENV['VCR_RECORD_MODE'] = 'once'
47
+ # recording only valid for adapter tests
48
+ Rake::Task['spec:suite:adapters'].invoke
49
+ end
50
+
51
+ namespace :record do
52
+ FileList['spec/adapter/v1/**'].each do |file|
53
+ next unless File.directory?(file)
54
+ adapter = File.basename(file)
55
+
56
+ desc "Record #{adapter} adapter tests"
57
+ RSpec::Core::RakeTask.new(adapter) do |t|
58
+ # new_episodes
59
+ ENV['VCR_RECORD_MODE'] = 'once'
60
+ t.pattern = "spec/adapter/v1/#{adapter}/*_spec.rb"
61
+ t.verbose = true
62
+ end
63
+ end
64
+ end
65
+
66
+ task :environment do
67
+ ENV['RACK_ENV'] ||= 'development'
68
+ require 'configatron'
69
+ require 'nucleus/scripts/setup_config'
70
+ nucleus_config.logging.level = Logger::Severity::ERROR
71
+ require 'nucleus_api/scripts/load_api'
72
+ require 'nucleus_api/scripts/initialize_api'
73
+ end
74
+
75
+ task routes: :environment do
76
+ Nucleus::API::RootAPI.routes.each do |route|
77
+ next if route.nil? || route.route_method.nil?
78
+ method = route.route_method.ljust(10)
79
+ path = route.route_path
80
+ version = route.instance_variable_get(:@options)[:version]
81
+ path = path.gsub(/:version/, version) unless version.nil?
82
+ puts " #{method} #{path} - [#{version}]"
83
+ end
84
+ end
85
+
86
+ task schema_v1: :environment do
87
+ require 'json'
88
+ response = Nucleus::API::RootAPI.call(
89
+ 'REQUEST_METHOD' => 'GET',
90
+ 'PATH_INFO' => '/schema',
91
+ 'rack.input' => StringIO.new)[2].body[0]
92
+ json = JSON.parse(response)
93
+ puts JSON.pretty_generate(json)
94
+ end
95
+
96
+ begin
97
+ require 'yard'
98
+ DOC_FILES = %w(lib/**/*.rb)
99
+
100
+ YARD::Rake::YardocTask.new(:doc) do |t|
101
+ t.files = DOC_FILES
102
+ end
103
+
104
+ namespace :doc do
105
+ YARD::Rake::YardocTask.new(:pages) do |t|
106
+ t.files = DOC_FILES
107
+ t.options = ['-o', '../nucleus.doc/docs', '--title', "Nucleus #{Nucleus::VERSION} Documentation"]
108
+ end
109
+
110
+ desc 'Check out gh-pages.'
111
+ task :checkout do
112
+ dir = File.join(__dir__, '..', 'nucleus.doc')
113
+ unless Dir.exist?(dir)
114
+ Dir.mkdir(dir)
115
+ Dir.chdir(dir) do
116
+ system('git init')
117
+ system('git remote add origin git@github.com:stefan-kolb/nucleus.git')
118
+ system('git pull')
119
+ system('git checkout gh-pages')
120
+ end
121
+ end
122
+ end
123
+
124
+ desc 'Generate and publish YARD docs to GitHub pages.'
125
+ task publish: %w(doc:pages:checkout doc:pages) do
126
+ Dir.chdir(File.join(__dir__, '..', 'nucleus.doc')) do
127
+ system('git checkout gh-pages')
128
+ system('git add .')
129
+ system('git add -u')
130
+ system("git commit -m 'Generating docs for version #{Nucleus::VERSION}.'")
131
+ system('git push origin gh-pages')
132
+ end
133
+ end
134
+ end
135
+ rescue LoadError
136
+ puts 'You need to install YARD.'
137
+ end
@@ -0,0 +1,91 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ # set the process name on ps, does not work on OS X due to system limitations
4
+ $0 = 'Nucleus'
5
+ Process.setproctitle('Nucleus') if Process.respond_to?(:setproctitle)
6
+
7
+ root_dir = File.join(__dir__, '..')
8
+
9
+ require 'optparse'
10
+ require 'yaml'
11
+ require 'thin'
12
+
13
+ NUCLEUS_CONFIG_LOCATION = File.join(root_dir, 'config', 'nucleus_config.rb')
14
+
15
+ options = { env: 'development', logdir: File.join(root_dir, 'log'), config: File.expand_path(NUCLEUS_CONFIG_LOCATION) }
16
+ optparse = OptionParser.new do |opts|
17
+ opts.banner = <<BANNER
18
+ Usage:
19
+ nucleus [options]
20
+
21
+ Options:
22
+ BANNER
23
+ opts.on('-r', '--hostname HOSTNAME', 'Bind to HOST address (default: localhost)') { |host| ENV['NUCLEUS_API_HOST'] = host }
24
+ opts.on('-p', '--port PORT', 'Use PORT (default: 9292)') { |port| ENV['NUCLEUS_API_PORT'] = port }
25
+ opts.on('-e', '--env ENV', 'Environment (default: "development")') { |env| options[:env] = env }
26
+ opts.on('-t', '--timeout TIMEOUT', 'Timeout for single request (default: 30)') { |timeout| ENV['NUCLEUS_API_TIMEOUT'] = timeout }
27
+ opts.on('-h', '--help', '') { options[:help] = true }
28
+ opts.separator <<EOS
29
+
30
+ Daemon options:
31
+ EOS
32
+ opts.on('-d', '--daemon', 'Run the server as daemon in the background (default: false)') { options[:daemon] = true }
33
+ opts.on('-u', '--user USER', 'User to run daemon as. Use with -d (default: "nobody")') { |user| options[:user] = user }
34
+ opts.on('-g', '--group GROUP', 'Group to run daemon as. Use with -d (default: "nobody")') { |group| options[:group] = group }
35
+ opts.on('-b', '--pid PID', 'File to store PID (default: tmp/pids/thin.pid)') { |pid| options[:pid] = pid }
36
+ opts.on('-l', '--logdir LOGDIR', "Directory for log files if run as daemon, defaults to #{options[:logdir]}") { |opt| options[:logdir] = opt }
37
+ opts.separator <<EOS
38
+
39
+ SSL options:
40
+ EOS
41
+ opts.on('-s', '--ssl', 'Enable SSL (default: false, use with: ssl-key and ssl-cert)') { options[:ssl] = true }
42
+ opts.on('-k', '--ssl-key KEY', 'SSL key file to use (use with: ssl and ssl-cert)') { |key| options[:ssl_key] = key }
43
+ opts.on('-c', '--ssl-cert CERT', 'SSL certificate file to use (use with: ssl and ssl-key)') { |cert| options[:ssl_cert] = cert }
44
+ end
45
+
46
+ optparse.parse!
47
+
48
+ if options[:help]
49
+ puts optparse
50
+ exit(0)
51
+ end
52
+
53
+ if options[:env] == 'production' && ( !options.key?(:ssl) || options[:ssl] == false)
54
+ puts 'You need to use HTTPS when running a production server. Please specify the SSL key and certificate.'
55
+ exit(201)
56
+ end
57
+
58
+ if options[:ssl]
59
+ unless options[:ssl_key]
60
+ puts "You need to set SSL key using '-k /path/to/keyfile.key'"
61
+ exit(101)
62
+ end
63
+ unless options[:ssl_cert]
64
+ puts "You need to set SSL certificate using '-c /path/to/certificate.crt'"
65
+ exit(102)
66
+ end
67
+ end
68
+
69
+ ENV['NUCLEUS_API_HOST'] = 'localhost' unless ENV['NUCLEUS_API_HOST']
70
+ ENV['NUCLEUS_API_PORT'] = '9292' unless ENV['NUCLEUS_API_PORT']
71
+
72
+ argv_opts = ARGV.clone
73
+ argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0])
74
+ argv_opts << ['--address', ENV['NUCLEUS_API_HOST'] ]
75
+ argv_opts << ['--port', ENV['NUCLEUS_API_PORT'] ]
76
+ argv_opts << ['--rackup', File.join(root_dir, 'config.ru') ]
77
+ argv_opts << ['-e', options[:env] ]
78
+ argv_opts << ['--timeout', ENV['NUCLEUS_API_TIMEOUT'] || '60']
79
+ argv_opts << ['--ssl', '--ssl-key-file', options[:ssl_key], '--ssl-cert-file', options[:ssl_cert]] if options[:ssl]
80
+
81
+ if options[:daemon]
82
+ options[:env] = 'production'
83
+ argv_opts << [ '--daemonize', '--user', options[:user] || 'nobody', '--tag', 'Nucleus on Thin']
84
+ argv_opts << [ '--pid', options[:pid]] if options[:pid]
85
+ argv_opts << [ '--group', options[:group] || 'nobody' ]
86
+ argv_opts << [ '--log', File.join(options[:logdir], 'nucleus_daemon.log')] unless ENV['NUCLEUS_API_LOG']
87
+ end
88
+ argv_opts.flatten!
89
+
90
+ thin = Thin::Runner.new(argv_opts)
91
+ thin.run!
@@ -0,0 +1 @@
1
+ @ruby -C%~dp0.. "%~dp0nucleus" %*
@@ -0,0 +1,18 @@
1
+ #########################
2
+ ### Setup Application ###
3
+ #########################
4
+ require 'bundler/setup'
5
+
6
+ # Load configuration
7
+ require 'nucleus/scripts/setup_config'
8
+ # Load application
9
+ require 'nucleus_api/scripts/load_api'
10
+ # Initialize the application
11
+ require 'nucleus_api/scripts/initialize_api'
12
+
13
+ # Initialize the Rack environment
14
+ # GO TO THIS FILE TO INCLUDE MIDDLEWARE (!)
15
+ require 'nucleus_api/scripts/rack_application'
16
+
17
+ # finally start the application
18
+ run Nucleus::API::Rack.app
@@ -0,0 +1,32 @@
1
+ ---
2
+ name: "cloudControl"
3
+ id: "cloudcontrol"
4
+ providers:
5
+ -
6
+ name: "cloudControl"
7
+ id: "cloudcontrol"
8
+ endpoints:
9
+ -
10
+ name: "cloudControl"
11
+ id: "cloudcontrol"
12
+ url: "api.cloudcontrol.com"
13
+ -
14
+ name: "dotCloud"
15
+ id: "dotcloud"
16
+ url: "api.dotcloudapp.com"
17
+ -
18
+ name: "exoscale Apps"
19
+ id: "exoscale"
20
+ endpoints:
21
+ -
22
+ name: "exoscale Apps"
23
+ id: "exoscale"
24
+ url: "api.app.exo.io"
25
+ -
26
+ name: "Cloud&Heat App Elevator"
27
+ id: "cloudandheat"
28
+ endpoints:
29
+ -
30
+ name: "Cloud&Heat App Elevator"
31
+ id: "cloudandheat"
32
+ url: "api.cnh-apps.com"
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: "Cloud Foundry v2"
3
+ id: "cloud_foundry_v2"
4
+ providers:
5
+ -
6
+ name: "bosh"
7
+ id: "cf-bosh"
8
+ endpoints:
9
+ -
10
+ name: "bosh local"
11
+ id: "cf-bosh-local"
12
+ url: "api.10.244.0.34.xip.io"
13
+ app_domain: "10.244.0.34.xip.io"
14
+ # trust endpoint, no ssl certificate verification
15
+ trust: true
16
+ -
17
+ name: "Pivotal"
18
+ id: "pivotal"
19
+ endpoints:
20
+ -
21
+ name: "Pivotal Web Services"
22
+ id: "pivotal"
23
+ url: "api.run.pivotal.io"
24
+ app_domain: "cfapps.io"
25
+ -
26
+ name: "IBM Bluemix"
27
+ id: "bluemix"
28
+ endpoints:
29
+ -
30
+ name: "Europe - Great Britain"
31
+ id: "bluemix-eu-gb"
32
+ url: "api.eu-gb.bluemix.net"
33
+ app_domain: "eu-gb.mybluemix.net"
34
+ -
35
+ name: "United States - South"
36
+ id: "bluemix-us-south"
37
+ url: "api.ng.bluemix.net"
38
+ app_domain: "ng.mybluemix.net"
39
+ -
40
+ name: "Anynines"
41
+ id: "anynines"
42
+ endpoints:
43
+ -
44
+ name: "Anynines"
45
+ id: "anynines"
46
+ url: "api.de.a9s.eu"
47
+ app_domain: "a9s.eu"
48
+ -
49
+ name: "AppFog"
50
+ id: "appfog"
51
+ endpoints:
52
+ -
53
+ name: "US East"
54
+ id: "appfog-us-east"
55
+ url: "api.useast.appfog.ctl.io"
56
+ app_domain: "useast.appfog.ctl.io"
57
+ -
58
+ name: "US West"
59
+ id: "appfog-us-west"
60
+ url: "api.uswest.appfog.ctl.io"
61
+ app_domain: "uswest.appfog.ctl.io"
@@ -0,0 +1,13 @@
1
+ ---
2
+ name: "Heroku"
3
+ id: "heroku"
4
+ providers:
5
+ -
6
+ name: "Heroku"
7
+ id: "heroku"
8
+ endpoints:
9
+ -
10
+ name: "Heroku"
11
+ id: "heroku"
12
+ url: "api.heroku.com"
13
+ app_domain: "herokuapp.com"
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: "Openshift v2"
3
+ id: "openshift_v2"
4
+ providers:
5
+ -
6
+ name: "Openshift Online"
7
+ id: "openshift-online"
8
+ endpoints:
9
+ -
10
+ name: "Openshift Online"
11
+ id: "openshift-online"
12
+ url: "openshift.redhat.com/broker/rest"
13
+ -
14
+ name: "Getup Cloud"
15
+ id: "getup"
16
+ endpoints:
17
+ -
18
+ name: "Getup Cloud"
19
+ id: "getup"
20
+ url: "broker.getupcloud.com/broker/rest"
@@ -0,0 +1,47 @@
1
+ # [optional] The available levels are: FATAL, ERROR, WARN, INFO, DEBUG
2
+ # Defaults to: Logger::Severity::WARN
3
+ # nucleus_config.logging.level = Logger::Severity::WARN
4
+
5
+ # [optional] Logging directory
6
+ # Defaults to: File.expand_path(File.join(File.dirname(__FILE__), '..', 'log'))
7
+ # nucleus_config.logging.path = File.expand_path(File.join(File.dirname(__FILE__), '..', 'log'))
8
+
9
+ # [optional] Database backend to use. Choose one of: [:Daybreak, :LMDB]
10
+ # Defaults to: :Daybreak on Unix, :LMDB on windows systems.
11
+ # nucleus_config.db.backend = :Daybreak
12
+
13
+ # [optional] Options to start the backend.
14
+ # See http://www.rubydoc.info/gems/moneta/Moneta/Adapters for valid options on the chosen adapter.
15
+ # Defaults to: {}
16
+ # nucleus_config.db.backend_options = {}
17
+
18
+ # [optional] Please specify the DB directory if you plan to use a file storage.
19
+ # Defaults to: a temporary directory.
20
+ # nucleus_config.db.path = '/Users/cmr/Documents/workspace-rubymine/nucleus/store/'
21
+
22
+ # [optional] If true, the DB will be deleted when the server is being closed.
23
+ # Defaults to: true
24
+ # nucleus_config.db.delete_on_shutdown = false
25
+
26
+ # [optional, requires 'nucleus_config.db.path'] If true, the DB will be initialized with default values,
27
+ # which may partially override previously persisted entities.
28
+ # False keeps the changes that were applied during runtime.
29
+ # Defaults to: false
30
+ # nucleus_config.db.override = false
31
+
32
+ # [optional] Specify the location of a private key (ssh-rsa, OpenSSH) that shall be used for Git actions.
33
+ # E.g. /home/myusername/.ssh/id_rsa
34
+ # If set to false, Nucleus will use its own private key (config/nucleus_git_key.pem) to authenticate all Git actions.
35
+ # Defaults to: nil
36
+ # nucleus_config.ssh.custom_key = nil
37
+
38
+ # [optional] Specify the public API description
39
+ # nucleus_config.api.title = 'Nucleus - Platform as a Service abstraction layer API'
40
+ # nucleus_config.api.description = 'Nucleus allows to manage multiple PaaS providers with just one API to be used'
41
+ # nucleus_config.api.contact = 'stefan.kolb@uni-bamberg.de'
42
+ # # The name of the license.
43
+ # nucleus_config.api.license = 'TBD'
44
+ # # The URL of the license.
45
+ # nucleus_config.api.license_url = ''
46
+ # # The URL of the API terms and conditions.
47
+ # nucleus_config.api.terms_of_service_url = 'API still under development, no guarantees (!)'
@@ -0,0 +1,13 @@
1
+ require 'nucleus/version'
2
+
3
+ # _Nucleus_ is a RESTful abstraction layer to achieve unified deployment and management functions
4
+ # of Platform-as-a-Service (PaaS) providers.<br>
5
+ module Nucleus
6
+ # Load the default configuration
7
+ require 'nucleus/scripts/setup_config'
8
+ # Load the actual application and its dependencies
9
+ require 'nucleus/scripts/load'
10
+
11
+ # now require the parts that are only relevant when using Nucleus as gem
12
+ require 'nucleus/adapter_resolver'
13
+ end
@@ -0,0 +1,115 @@
1
+ module Nucleus
2
+ # The {AdapterResolver} can be used within Ruby applications to retrieve a Nucleus adapter.
3
+ # Returned adapters are patched so that each call enforces authentication and retries a call when a token was expired.
4
+ class AdapterResolver
5
+ include Nucleus::UrlConverter
6
+
7
+ def initialize(requested_version)
8
+ fail 'No such version supported' unless Nucleus::VersionDetector.api_versions.include?(requested_version)
9
+ @api_version = requested_version
10
+ end
11
+
12
+ # Get a list of all adapters that are currently supported.
13
+ # @return [Hash<String, Hash<String, Nucleus::Adapters::BaseAdapter>>] currently supported adapters
14
+ def adapters
15
+ setup
16
+ @adapters
17
+ end
18
+
19
+ # Load the adapter to interact with the platform of the vendor that is offered at the endpoint_url.
20
+ # @param [String] vendor The vendor / adapter name that shall be used to communicate with the endpoint.
21
+ # Must be supported, otherwise a +StandardError+ will be thrown.
22
+ # @param [String] username The username that shall be used for authentication
23
+ # @param [String] password The password that shall be used for authentication
24
+ # @param [Hash<Symbol,?>] options Further options to apply when creating the adapter instance.
25
+ # If available, the default configuration of the vendor configuration is applied as default.
26
+ # @option options [String] :app_domain The domain where applications of the platform will be made available at.
27
+ # This option must be set for custom deployments of platforms like Cloud Foundry or Openshift.
28
+ # For IBM Bluemix this value would be: +eu-gb.mybluemix.net+ or +ng.mybluemix.net+, depending on the endpoint.
29
+ # @option options [String] :check_ssl Set to false if SSL certificates shall not be verified (trust self-signed)
30
+ # @option options [String] :api_url URL of the endpoint's API that shall be used.
31
+ # Must be specified if there are multiple endpoints available and will be forced to https://
32
+ # @raise [StandardError] if the vendor is unknown / not supported or no unique API endpoint could be identified
33
+ # @return [Nucleus::Adapters::BaseAdapter] loaded adapter implementation
34
+ def load(vendor, username, password, options = {})
35
+ setup
36
+ fail StandardError, "Could not find adapter for vendor '#{vendor}'" unless @adapters.key?(vendor)
37
+
38
+ # load the endpoint's HTTPS enabled API URL
39
+ endpoint_url = load_endpoint(vendor, options)
40
+
41
+ # load default configuration if available
42
+ if @configurations[vendor].key?(endpoint_url)
43
+ default_configuration = @configurations[vendor][endpoint_url]
44
+ options = default_configuration.merge(options)
45
+ end
46
+
47
+ check_ssl = options.key?(:check_ssl) ? options[:check_ssl] : true
48
+ adapter = @adapters[vendor].new(endpoint_url, options[:app_domain], check_ssl)
49
+
50
+ fake_env = { 'HTTP_AUTHORIZATION' => 'Basic ' + ["#{username}:#{password}"].pack('m*').gsub(/\n/, '') }
51
+ # patch the adapter so that calls are wrapped and expect valid authentication
52
+ AdapterAuthenticationInductor.patch(adapter, fake_env)
53
+
54
+ cache_key = adapter.cache_key(username, password)
55
+ # no auth object available, perform authentication first
56
+ auth_object = adapter.auth_client
57
+ # throws an error if the authentication failed
58
+ auth_object.authenticate(username, password)
59
+ # cache the auth object so it does not have to be retrieved per request
60
+ adapter.cache(cache_key, auth_object)
61
+
62
+ # return patched and initially authenticated adapter
63
+ adapter
64
+ end
65
+
66
+ private
67
+
68
+ def load_endpoint(vendor, options)
69
+ if options.key?(:api_url)
70
+ # use chosen url endpoint
71
+ endpoint_url = options[:api_url]
72
+ elsif @configurations[vendor].length == 1
73
+ # use default endpoint
74
+ endpoint_url = @configurations[vendor].keys.first
75
+ else
76
+ fail StandardError, "Could not identify an API endpoint for the vendor '#{vendor}'. "\
77
+ "Please specify the API URL to use with the ':api_url' option."
78
+ end
79
+
80
+ # make sure url uses https
81
+ secure_url(endpoint_url)
82
+ end
83
+
84
+ def setup
85
+ # perform the setup only once
86
+ return if @adapters
87
+
88
+ # Initialize the application (import adapters, load DAOs, ...)
89
+ require 'nucleus/scripts/initialize'
90
+ # load the configuration values
91
+ require 'nucleus/scripts/initialize_config_defaults'
92
+ # Once invoked the configuration is locked
93
+ require 'nucleus/scripts/finalize'
94
+
95
+ @adapters = {}
96
+ @configurations = {}
97
+ Nucleus::Adapters.configuration_files.each do |adapter_config|
98
+ vendor = Nucleus::VendorParser.parse(adapter_config)
99
+ next unless vendor
100
+ adapter_clazz = Nucleus::Adapters.adapter_clazz(adapter_config, @api_version)
101
+ next unless adapter_clazz
102
+ @adapters[vendor.id] = adapter_clazz
103
+ @configurations[vendor.id] = {}
104
+
105
+ # now load the default configurations for this vendor
106
+ vendor.providers.each do |provider|
107
+ provider.endpoints.each do |endpoint|
108
+ @configurations[vendor.id][secure_url(endpoint.url)] = { check_ssl: !endpoint.trust,
109
+ app_domain: endpoint.app_domain }
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end