├── .gitignore ├── Gemfile ├── Gemfile.lock ├── Guardfile ├── LICENSE.md ├── README.md ├── Rakefile ├── app ├── assets │ ├── images │ │ └── .keep │ ├── javascripts │ │ ├── application.js │ │ ├── support │ │ │ └── waiting_dialog.js │ │ └── virtual_machines.js │ └── stylesheets │ │ ├── application.css │ │ └── boostrap_sass.scss ├── controllers │ ├── application_controller.rb │ ├── concerns │ │ └── .keep │ ├── login_controller.rb │ └── virtual_machines_controller.rb ├── forms │ ├── login_form.rb │ └── virtual_machine_form.rb ├── helpers │ ├── application_helper.rb │ └── form_helper.rb ├── jobs │ ├── warm_cache_job.rb │ ├── warm_configuration_cache_job.rb │ ├── warm_create_options_cache_job.rb │ ├── warm_datacenters_cache_job.rb │ ├── warm_package_cache_job.rb │ ├── warm_product_categories_cache_job.rb │ └── warm_store_hash_cache_job.rb ├── mailers │ └── .keep ├── models │ ├── .keep │ ├── concerns │ │ └── .keep │ ├── softlayer_connection.rb │ ├── store_hash.rb │ ├── store_hash │ │ ├── pricing.rb │ │ └── region.rb │ ├── virtual_machine.rb │ └── virtual_machine │ │ └── pricing.rb └── views │ ├── application │ └── _navbar.html.erb │ ├── layouts │ ├── application.html.erb │ └── login.html.erb │ ├── login │ └── new.html.erb │ ├── shared │ └── form_helper │ │ └── _error_tag.html.erb │ └── virtual_machines │ ├── _form.html.erb │ ├── _price_box.html.erb │ ├── _vm.html.erb │ ├── destroy.js.erb │ ├── index.html.erb │ ├── new.html.erb │ ├── power_cycle.js.erb │ ├── price_box.js.erb │ └── reboot.js.erb ├── bin ├── bundle ├── rails ├── rake ├── rspec ├── setup └── spring ├── config.ru ├── config ├── application.rb ├── boot.rb ├── database.yml ├── environment.rb ├── environments │ ├── development.rb │ ├── production.rb │ └── test.rb ├── initializers │ ├── assets.rb │ ├── backtrace_silencers.rb │ ├── cookies_serializer.rb │ ├── filter_parameter_logging.rb │ ├── inflections.rb │ ├── mime_types.rb │ ├── session_store.rb │ ├── simple_form.rb │ ├── simple_form_bootstrap.rb │ ├── softlayer.rb │ └── wrap_parameters.rb ├── locales │ ├── en.yml │ ├── responders.en.yml │ └── simple_form.en.yml ├── routes.rb └── secrets.yml ├── db └── seeds.rb ├── lib ├── application_responder.rb ├── assets │ └── .keep ├── tasks │ ├── .keep │ └── custom_seed.rake └── templates │ └── haml │ └── scaffold │ └── _form.html.haml ├── public ├── 404.html ├── 422.html ├── 500.html ├── favicon.ico └── robots.txt ├── spec ├── rails_helper.rb └── spec_helper.rb ├── test ├── controllers │ └── .keep ├── fixtures │ └── .keep ├── helpers │ └── .keep ├── integration │ └── .keep ├── mailers │ └── .keep ├── models │ └── .keep └── test_helper.rb └── vendor └── assets ├── javascripts └── .keep └── stylesheets └── .keep /.gitignore: -------------------------------------------------------------------------------- 1 | ### Rails ### 2 | *.rbc 3 | capybara-*.html 4 | .rspec 5 | /log 6 | /tmp 7 | /db/*.sqlite3 8 | /db/*.sqlite3-journal 9 | /public/system 10 | /coverage/ 11 | /spec/tmp 12 | **.orig 13 | rerun.txt 14 | pickle-email-*.html 15 | 16 | ## Environment normalisation: 17 | /.bundle 18 | /vendor/bundle 19 | /vendor/cache 20 | 21 | # these should all be checked in to normalise the environment: 22 | # Gemfile.lock, .ruby-version, .ruby-gemset 23 | 24 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 25 | .rvmrc 26 | 27 | # if using bower-rails ignore default bower_components path bower.json files 28 | /vendor/assets/bower_components 29 | *.bowerrc 30 | bower.json 31 | 32 | 33 | ### Ruby ### 34 | *.gem 35 | *.rbc 36 | /.config 37 | /coverage/ 38 | /InstalledFiles 39 | /pkg/ 40 | /spec/reports/ 41 | /test/tmp/ 42 | /test/version_tmp/ 43 | /tmp/ 44 | 45 | ## Specific to RubyMotion: 46 | .dat* 47 | .repl_history 48 | build/ 49 | 50 | ## Documentation cache and generated files: 51 | /.yardoc/ 52 | /_yardoc/ 53 | /doc/ 54 | /rdoc/ 55 | 56 | ## Environment normalisation: 57 | /.bundle/ 58 | /lib/bundler/man/ 59 | 60 | # for a library or gem, you might want to ignore these files since the code is 61 | # intended to run in multiple environments; otherwise, check them in: 62 | # Gemfile.lock 63 | # .ruby-version 64 | # .ruby-gemset 65 | 66 | # unless supporting rvm < 1.11.0 or doing something fancy, ignore this: 67 | .rvmrc 68 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | 4 | # Bundle edge Rails instead: gem 'rails', github: 'rails/rails' 5 | gem 'rails', '4.2.6' 6 | # Use sqlite3 as the database for Active Record 7 | gem 'sqlite3' 8 | # Use SCSS for stylesheets 9 | gem 'sass-rails', '~> 5.0' 10 | # Use Uglifier as compressor for JavaScript assets 11 | gem 'uglifier', '>= 1.3.0' 12 | # Use CoffeeScript for .coffee assets and views 13 | gem 'coffee-rails', '~> 4.1.0' 14 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes 15 | # gem 'therubyracer', platforms: :ruby 16 | 17 | # Use jquery as the JavaScript library 18 | gem 'jquery-rails' 19 | # Turbolinks makes following links in your web application faster. Read more: https://github.com/rails/turbolinks 20 | gem 'turbolinks', '5.0.0.beta2' 21 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder 22 | gem 'jbuilder', '~> 2.0' 23 | # bundle exec rake doc:rails generates the API under doc/api. 24 | gem 'sdoc', '~> 0.4.0', group: :doc 25 | 26 | # Use ActiveModel has_secure_password 27 | # gem 'bcrypt', '~> 3.1.7' 28 | 29 | # Use Unicorn as the app server 30 | # gem 'unicorn' 31 | 32 | # Use Capistrano for deployment 33 | # gem 'capistrano-rails', group: :development 34 | 35 | group :development, :test do 36 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console 37 | gem 'byebug' 38 | 39 | # Access an IRB console on exception pages or by using <%= console %> in views 40 | gem 'web-console', '~> 2.0' 41 | 42 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring 43 | gem 'spring' 44 | end 45 | 46 | gem 'bootstrap-sass', '~> 3.3.6' 47 | gem 'country_select', '~> 2.5' 48 | gem 'devise', '~> 3.5' 49 | gem 'softlayer', '~> 0.0' 50 | gem 'json', '~> 1.8' 51 | gem 'paloma', '~> 5.0' 52 | gem 'reform', '~> 2.1' 53 | gem 'responders', '~> 2.1' 54 | gem 'sidekiq', '~> 4.1' 55 | gem 'simple_form', '~> 3.2' 56 | 57 | group :development do 58 | gem 'better_errors' 59 | gem 'binding_of_caller' 60 | gem 'guard', require: false 61 | gem 'guard-rails', require: false 62 | gem 'guard-bundler', require: false 63 | gem 'guard-livereload', require: false 64 | gem 'guard-rspec', require: false 65 | gem 'letter_opener' 66 | gem 'quiet_assets' 67 | gem 'spring-commands-rspec' 68 | gem 'thin' 69 | # pry stuff 70 | gem 'pry' 71 | gem 'pry-rails' 72 | gem 'pry-doc' 73 | gem 'pry-remote' 74 | gem 'pry-byebug', '3.2.0' 75 | gem 'hirb' 76 | gem 'awesome_print' 77 | end 78 | 79 | group :development, :test do 80 | gem 'rspec-rails' 81 | gem 'shoulda-matchers', require: false 82 | end 83 | 84 | group :test do 85 | gem 'capybara' 86 | gem 'email_spec' 87 | gem 'turnip' 88 | end 89 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | actionmailer (4.2.6) 5 | actionpack (= 4.2.6) 6 | actionview (= 4.2.6) 7 | activejob (= 4.2.6) 8 | mail (~> 2.5, >= 2.5.4) 9 | rails-dom-testing (~> 1.0, >= 1.0.5) 10 | actionpack (4.2.6) 11 | actionview (= 4.2.6) 12 | activesupport (= 4.2.6) 13 | rack (~> 1.6) 14 | rack-test (~> 0.6.2) 15 | rails-dom-testing (~> 1.0, >= 1.0.5) 16 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 17 | actionview (4.2.6) 18 | activesupport (= 4.2.6) 19 | builder (~> 3.1) 20 | erubis (~> 2.7.0) 21 | rails-dom-testing (~> 1.0, >= 1.0.5) 22 | rails-html-sanitizer (~> 1.0, >= 1.0.2) 23 | activejob (4.2.6) 24 | activesupport (= 4.2.6) 25 | globalid (>= 0.3.0) 26 | activemodel (4.2.6) 27 | activesupport (= 4.2.6) 28 | builder (~> 3.1) 29 | activerecord (4.2.6) 30 | activemodel (= 4.2.6) 31 | activesupport (= 4.2.6) 32 | arel (~> 6.0) 33 | activesupport (4.2.6) 34 | i18n (~> 0.7) 35 | json (~> 1.7, >= 1.7.7) 36 | minitest (~> 5.1) 37 | thread_safe (~> 0.3, >= 0.3.4) 38 | tzinfo (~> 1.1) 39 | addressable (2.4.0) 40 | akami (1.3.1) 41 | gyoku (>= 0.4.0) 42 | nokogiri 43 | arel (6.0.3) 44 | autoprefixer-rails (6.3.6) 45 | execjs 46 | awesome_print (1.6.1) 47 | axiom-types (0.1.1) 48 | descendants_tracker (~> 0.0.4) 49 | ice_nine (~> 0.11.0) 50 | thread_safe (~> 0.3, >= 0.3.1) 51 | bcrypt (3.1.11) 52 | better_errors (2.1.1) 53 | coderay (>= 1.0.0) 54 | erubis (>= 2.6.6) 55 | rack (>= 0.9.0) 56 | binding_of_caller (0.7.2) 57 | debug_inspector (>= 0.0.1) 58 | bootstrap-sass (3.3.6) 59 | autoprefixer-rails (>= 5.2.1) 60 | sass (>= 3.3.4) 61 | builder (3.2.2) 62 | byebug (5.0.0) 63 | columnize (= 0.9.0) 64 | capybara (2.6.2) 65 | addressable 66 | mime-types (>= 1.16) 67 | nokogiri (>= 1.3.3) 68 | rack (>= 1.0.0) 69 | rack-test (>= 0.5.4) 70 | xpath (~> 2.0) 71 | coderay (1.1.1) 72 | coercible (1.0.0) 73 | descendants_tracker (~> 0.0.1) 74 | coffee-rails (4.1.1) 75 | coffee-script (>= 2.2.0) 76 | railties (>= 4.0.0, < 5.1.x) 77 | coffee-script (2.4.1) 78 | coffee-script-source 79 | execjs 80 | coffee-script-source (1.10.0) 81 | columnize (0.9.0) 82 | concurrent-ruby (1.0.1) 83 | connection_pool (2.2.0) 84 | countries (1.2.5) 85 | currencies (~> 0.4.2) 86 | i18n_data (~> 0.7.0) 87 | country_select (2.5.2) 88 | countries (~> 1.2.0) 89 | sort_alphabetical (~> 1.0) 90 | currencies (0.4.2) 91 | daemons (1.2.3) 92 | debug_inspector (0.0.2) 93 | declarative (0.0.7) 94 | uber (>= 0.0.15) 95 | descendants_tracker (0.0.4) 96 | thread_safe (~> 0.3, >= 0.3.1) 97 | devise (3.5.6) 98 | bcrypt (~> 3.0) 99 | orm_adapter (~> 0.1) 100 | railties (>= 3.2.6, < 5) 101 | responders 102 | thread_safe (~> 0.1) 103 | warden (~> 1.2.3) 104 | diff-lcs (1.2.5) 105 | disposable (0.2.6) 106 | declarative (~> 0.0.6) 107 | representable (>= 2.4.0, <= 3.1.0) 108 | uber 109 | em-websocket (0.5.1) 110 | eventmachine (>= 0.12.9) 111 | http_parser.rb (~> 0.6.0) 112 | email_spec (2.0.0) 113 | htmlentities (~> 4.3.3) 114 | launchy (~> 2.1) 115 | mail (~> 2.6.3) 116 | equalizer (0.0.11) 117 | erubis (2.7.0) 118 | eventmachine (1.2.0.1) 119 | excon (0.49.0) 120 | execjs (2.6.0) 121 | ffi (1.9.10) 122 | formatador (0.2.5) 123 | gherkin (2.12.2) 124 | multi_json (~> 1.3) 125 | globalid (0.3.6) 126 | activesupport (>= 4.1.0) 127 | guard (2.13.0) 128 | formatador (>= 0.2.4) 129 | listen (>= 2.7, <= 4.0) 130 | lumberjack (~> 1.0) 131 | nenv (~> 0.1) 132 | notiffany (~> 0.0) 133 | pry (>= 0.9.12) 134 | shellany (~> 0.0) 135 | thor (>= 0.18.1) 136 | guard-bundler (2.1.0) 137 | bundler (~> 1.0) 138 | guard (~> 2.2) 139 | guard-compat (~> 1.1) 140 | guard-compat (1.2.1) 141 | guard-livereload (2.5.2) 142 | em-websocket (~> 0.5) 143 | guard (~> 2.8) 144 | guard-compat (~> 1.0) 145 | multi_json (~> 1.8) 146 | guard-rails (0.7.2) 147 | guard (~> 2.11) 148 | guard-compat (~> 1.0) 149 | guard-rspec (4.6.5) 150 | guard (~> 2.1) 151 | guard-compat (~> 1.1) 152 | rspec (>= 2.99.0, < 4.0) 153 | gyoku (1.3.1) 154 | builder (>= 2.1.2) 155 | hashie (3.4.3) 156 | hirb (0.7.3) 157 | htmlentities (4.3.4) 158 | http_parser.rb (0.6.0) 159 | httpi (2.4.1) 160 | rack 161 | i18n (0.7.0) 162 | i18n_data (0.7.0) 163 | ice_nine (0.11.2) 164 | jbuilder (2.4.1) 165 | activesupport (>= 3.0.0, < 5.1) 166 | multi_json (~> 1.2) 167 | jquery-rails (4.1.1) 168 | rails-dom-testing (>= 1, < 3) 169 | railties (>= 4.2.0) 170 | thor (>= 0.14, < 2.0) 171 | json (1.8.3) 172 | launchy (2.4.3) 173 | addressable (~> 2.3) 174 | letter_opener (1.4.1) 175 | launchy (~> 2.2) 176 | listen (3.0.6) 177 | rb-fsevent (>= 0.9.3) 178 | rb-inotify (>= 0.9.7) 179 | loofah (2.0.3) 180 | nokogiri (>= 1.5.9) 181 | lumberjack (1.0.10) 182 | mail (2.6.4) 183 | mime-types (>= 1.16, < 4) 184 | method_source (0.8.2) 185 | mime-types (3.0) 186 | mime-types-data (~> 3.2015) 187 | mime-types-data (3.2016.0221) 188 | mini_portile2 (2.0.0) 189 | minitest (5.8.4) 190 | multi_json (1.11.2) 191 | nenv (0.3.0) 192 | nokogiri (1.6.7.2) 193 | mini_portile2 (~> 2.0.0.rc2) 194 | nori (2.6.0) 195 | notiffany (0.0.8) 196 | nenv (~> 0.1) 197 | shellany (~> 0.0) 198 | orm_adapter (0.5.0) 199 | paloma (5.0.0) 200 | pry (0.10.3) 201 | coderay (~> 1.1.0) 202 | method_source (~> 0.8.1) 203 | slop (~> 3.4) 204 | pry-byebug (3.2.0) 205 | byebug (~> 5.0) 206 | pry (~> 0.10) 207 | pry-doc (0.8.0) 208 | pry (~> 0.9) 209 | yard (~> 0.8) 210 | pry-rails (0.3.4) 211 | pry (>= 0.9.10) 212 | pry-remote (0.1.8) 213 | pry (~> 0.9) 214 | slop (~> 3.0) 215 | quiet_assets (1.1.0) 216 | railties (>= 3.1, < 5.0) 217 | rack (1.6.4) 218 | rack-test (0.6.3) 219 | rack (>= 1.0) 220 | rails (4.2.6) 221 | actionmailer (= 4.2.6) 222 | actionpack (= 4.2.6) 223 | actionview (= 4.2.6) 224 | activejob (= 4.2.6) 225 | activemodel (= 4.2.6) 226 | activerecord (= 4.2.6) 227 | activesupport (= 4.2.6) 228 | bundler (>= 1.3.0, < 2.0) 229 | railties (= 4.2.6) 230 | sprockets-rails 231 | rails-deprecated_sanitizer (1.0.3) 232 | activesupport (>= 4.2.0.alpha) 233 | rails-dom-testing (1.0.7) 234 | activesupport (>= 4.2.0.beta, < 5.0) 235 | nokogiri (~> 1.6.0) 236 | rails-deprecated_sanitizer (>= 1.0.1) 237 | rails-html-sanitizer (1.0.3) 238 | loofah (~> 2.0) 239 | railties (4.2.6) 240 | actionpack (= 4.2.6) 241 | activesupport (= 4.2.6) 242 | rake (>= 0.8.7) 243 | thor (>= 0.18.1, < 2.0) 244 | rake (11.1.2) 245 | rb-fsevent (0.9.7) 246 | rb-inotify (0.9.7) 247 | ffi (>= 0.5.0) 248 | rdoc (4.2.2) 249 | json (~> 1.4) 250 | redis (3.2.2) 251 | reform (2.1.0) 252 | disposable (>= 0.2.2, < 0.3.0) 253 | representable (>= 2.4.0, < 3.1.0) 254 | uber (~> 0.0.11) 255 | representable (2.4.1) 256 | declarative (~> 0.0.5) 257 | uber (~> 0.0.15) 258 | responders (2.1.2) 259 | railties (>= 4.2.0, < 5.1) 260 | rspec (3.4.0) 261 | rspec-core (~> 3.4.0) 262 | rspec-expectations (~> 3.4.0) 263 | rspec-mocks (~> 3.4.0) 264 | rspec-core (3.4.4) 265 | rspec-support (~> 3.4.0) 266 | rspec-expectations (3.4.0) 267 | diff-lcs (>= 1.2.0, < 2.0) 268 | rspec-support (~> 3.4.0) 269 | rspec-mocks (3.4.1) 270 | diff-lcs (>= 1.2.0, < 2.0) 271 | rspec-support (~> 3.4.0) 272 | rspec-rails (3.4.2) 273 | actionpack (>= 3.0, < 4.3) 274 | activesupport (>= 3.0, < 4.3) 275 | railties (>= 3.0, < 4.3) 276 | rspec-core (~> 3.4.0) 277 | rspec-expectations (~> 3.4.0) 278 | rspec-mocks (~> 3.4.0) 279 | rspec-support (~> 3.4.0) 280 | rspec-support (3.4.1) 281 | sass (3.4.22) 282 | sass-rails (5.0.4) 283 | railties (>= 4.0.0, < 5.0) 284 | sass (~> 3.1) 285 | sprockets (>= 2.8, < 4.0) 286 | sprockets-rails (>= 2.0, < 4.0) 287 | tilt (>= 1.1, < 3) 288 | savon (2.11.1) 289 | akami (~> 1.2) 290 | builder (>= 2.1.2) 291 | gyoku (~> 1.2) 292 | httpi (~> 2.3) 293 | nokogiri (>= 1.4.0) 294 | nori (~> 2.4) 295 | wasabi (~> 3.4) 296 | sdoc (0.4.1) 297 | json (~> 1.7, >= 1.7.7) 298 | rdoc (~> 4.0) 299 | shellany (0.0.1) 300 | shoulda-matchers (3.1.1) 301 | activesupport (>= 4.0.0) 302 | sidekiq (4.1.1) 303 | concurrent-ruby (~> 1.0) 304 | connection_pool (~> 2.2, >= 2.2.0) 305 | redis (~> 3.2, >= 3.2.1) 306 | simple_form (3.2.1) 307 | actionpack (> 4, < 5.1) 308 | activemodel (> 4, < 5.1) 309 | slop (3.6.0) 310 | softlayer (0.0.8) 311 | excon (~> 0.45) 312 | hashie (~> 3.4) 313 | representable (~> 2.3) 314 | savon (~> 2.11) 315 | virtus (~> 1.0) 316 | sort_alphabetical (1.0.2) 317 | unicode_utils (>= 1.2.2) 318 | spring (1.6.4) 319 | spring-commands-rspec (1.0.4) 320 | spring (>= 0.9.1) 321 | sprockets (3.5.2) 322 | concurrent-ruby (~> 1.0) 323 | rack (> 1, < 3) 324 | sprockets-rails (3.0.4) 325 | actionpack (>= 4.0) 326 | activesupport (>= 4.0) 327 | sprockets (>= 3.0.0) 328 | sqlite3 (1.3.11) 329 | thin (1.6.4) 330 | daemons (~> 1.0, >= 1.0.9) 331 | eventmachine (~> 1.0, >= 1.0.4) 332 | rack (~> 1.0) 333 | thor (0.19.1) 334 | thread_safe (0.3.5) 335 | tilt (2.0.2) 336 | turbolinks (5.0.0.beta2) 337 | turbolinks-source 338 | turbolinks-source (5.0.0.beta4) 339 | turnip (2.1.0) 340 | gherkin (~> 2.5) 341 | rspec (>= 3.0, < 4.0) 342 | tzinfo (1.2.2) 343 | thread_safe (~> 0.1) 344 | uber (0.0.15) 345 | uglifier (3.0.0) 346 | execjs (>= 0.3.0, < 3) 347 | unicode_utils (1.4.0) 348 | virtus (1.0.5) 349 | axiom-types (~> 0.1) 350 | coercible (~> 1.0) 351 | descendants_tracker (~> 0.0, >= 0.0.3) 352 | equalizer (~> 0.0, >= 0.0.9) 353 | warden (1.2.6) 354 | rack (>= 1.0) 355 | wasabi (3.5.0) 356 | httpi (~> 2.0) 357 | nokogiri (>= 1.4.2) 358 | web-console (2.3.0) 359 | activemodel (>= 4.0) 360 | binding_of_caller (>= 0.7.2) 361 | railties (>= 4.0) 362 | sprockets-rails (>= 2.0, < 4.0) 363 | xpath (2.0.0) 364 | nokogiri (~> 1.3) 365 | yard (0.8.7.6) 366 | 367 | PLATFORMS 368 | ruby 369 | 370 | DEPENDENCIES 371 | awesome_print 372 | better_errors 373 | binding_of_caller 374 | bootstrap-sass (~> 3.3.6) 375 | byebug 376 | capybara 377 | coffee-rails (~> 4.1.0) 378 | country_select (~> 2.5) 379 | devise (~> 3.5) 380 | email_spec 381 | guard 382 | guard-bundler 383 | guard-livereload 384 | guard-rails 385 | guard-rspec 386 | hirb 387 | jbuilder (~> 2.0) 388 | jquery-rails 389 | json (~> 1.8) 390 | letter_opener 391 | paloma (~> 5.0) 392 | pry 393 | pry-byebug (= 3.2.0) 394 | pry-doc 395 | pry-rails 396 | pry-remote 397 | quiet_assets 398 | rails (= 4.2.6) 399 | reform (~> 2.1) 400 | responders (~> 2.1) 401 | rspec-rails 402 | sass-rails (~> 5.0) 403 | sdoc (~> 0.4.0) 404 | shoulda-matchers 405 | sidekiq (~> 4.1) 406 | simple_form (~> 3.2) 407 | softlayer (~> 0.0) 408 | spring 409 | spring-commands-rspec 410 | sqlite3 411 | thin 412 | turbolinks (= 5.0.0.beta2) 413 | turnip 414 | uglifier (>= 1.3.0) 415 | web-console (~> 2.0) 416 | 417 | BUNDLED WITH 418 | 1.12.2 419 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | # A sample Guardfile 2 | # More info at https://github.com/guard/guard#readme 3 | 4 | ## Uncomment and set this to only include directories you want to watch 5 | # directories %w(app lib config test spec feature) 6 | 7 | ## Uncomment to clear the screen before every task 8 | # clearing :on 9 | 10 | ## Guard internally checks for changes in the Guardfile and exits. 11 | ## If you want Guard to automatically start up again, run guard in a 12 | ## shell loop, e.g.: 13 | ## 14 | ## $ while bundle exec guard; do echo "Restarting Guard..."; done 15 | ## 16 | ## Note: if you are using the `directories` clause above and you are not 17 | ## watching the project directory ('.'), the you will want to move the Guardfile 18 | ## to a watched dir and symlink it back, e.g. 19 | # 20 | # $ mkdir config 21 | # $ mv Guardfile config/ 22 | # $ ln -s config/Guardfile . 23 | # 24 | # and, you'll have to watch "config/Guardfile" instead of "Guardfile" 25 | 26 | # Workaround to make guard bundler works with bundler >= v1.12.0 27 | # more info https://github.com/guard/guard-bundler/issues/32 28 | Open3.popen3("gem contents bundler") do |i, o| 29 | Kernel.system("gem install bundler") if o.read.empty? 30 | end 31 | 32 | guard :bundler do 33 | require 'guard/bundler' 34 | require 'guard/bundler/verify' 35 | helper = Guard::Bundler::Verify.new 36 | 37 | files = ['Gemfile'] 38 | files += Dir['*.gemspec'] if files.any? { |f| helper.uses_gemspec?(f) } 39 | 40 | # Assume files are symlinked from somewhere 41 | files.each { |file| watch(helper.real_path(file)) } 42 | end 43 | 44 | guard 'livereload' do 45 | watch(%r{app/views/.+\.(erb|haml|slim)$}) 46 | watch(%r{app/helpers/.+\.rb}) 47 | watch(%r{public/.+\.(css|js|html)}) 48 | watch(%r{config/locales/.+\.yml}) 49 | # Rails Assets Pipeline 50 | watch(%r{(app|vendor)(/assets/\w+/(.+\.(css|js|html|png|jpg))).*}) { |m| "/assets/#{m[3]}" } 51 | end 52 | 53 | guard 'rails' do 54 | watch('Gemfile.lock') 55 | watch(%r{^(config|lib)/.*}) 56 | ignore(%r{config/routes.rb}) 57 | end 58 | 59 | 60 | # Note: The cmd option is now required due to the increasing number of ways 61 | # rspec may be run, below are examples of the most common uses. 62 | # * bundler: 'bundle exec rspec' 63 | # * bundler binstubs: 'bin/rspec' 64 | # * spring: 'bin/rspec' (This will use spring if running and you have 65 | # installed the spring binstubs per the docs) 66 | # * zeus: 'zeus rspec' (requires the server to be started separately) 67 | # * 'just' rspec: 'rspec' 68 | 69 | guard :rspec, cmd: "bundle exec rspec" do 70 | require "guard/rspec/dsl" 71 | dsl = Guard::RSpec::Dsl.new(self) 72 | 73 | # Feel free to open issues for suggestions and improvements 74 | 75 | # RSpec files 76 | rspec = dsl.rspec 77 | watch(rspec.spec_helper) { rspec.spec_dir } 78 | watch(rspec.spec_support) { rspec.spec_dir } 79 | watch(rspec.spec_files) 80 | 81 | # Ruby files 82 | ruby = dsl.ruby 83 | dsl.watch_spec_files_for(ruby.lib_files) 84 | 85 | # Rails files 86 | rails = dsl.rails(view_extensions: %w(erb haml slim)) 87 | dsl.watch_spec_files_for(rails.app_files) 88 | dsl.watch_spec_files_for(rails.views) 89 | 90 | watch(rails.controllers) do |m| 91 | [ 92 | rspec.spec.("routing/#{m[1]}_routing"), 93 | rspec.spec.("controllers/#{m[1]}_controller"), 94 | rspec.spec.("acceptance/#{m[1]}") 95 | ] 96 | end 97 | 98 | # Rails config changes 99 | watch(rails.spec_helper) { rspec.spec_dir } 100 | watch(rails.routes) { "#{rspec.spec_dir}/routing" } 101 | watch(rails.app_controller) { "#{rspec.spec_dir}/controllers" } 102 | 103 | # Capybara features specs 104 | watch(rails.view_dirs) { |m| rspec.spec.("features/#{m[1]}") } 105 | 106 | # Turnip features and steps 107 | watch(%r{^spec/acceptance/(.+)\.feature$}) 108 | watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) do |m| 109 | Dir[File.join("**/#{m[1]}.feature")][0] || "spec/acceptance" 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 IBM Corporation. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Stratos 2 | 3 | Would like to see how SoftLayer API can help on your cloud automating tasks? Are you ready for a demonstration? Fasten your seat belts! 4 | 5 | This project is a Ruby on Rails application that offers the possibility to interact to SoftLayer API, exposing a web interface and showing some tasks using your API key, and you give the rules. 6 | 7 | ## Installation 8 | 9 | To run on your machine you need to follow the steps below: 10 | 11 | * bundle install (to install Ruby dependencies) 12 | * no need to configure database (we are not persisting any data) 13 | * rails s 14 | * Access http://localhost:3000/ 15 | * Login with your API Key 16 | 17 | If you'd like to test in a production environment, it's normal rails deployment, set `SECRET_KEY_BASE` variable and run `rake assets:precompile`, that's it! 18 | 19 | ## Security 20 | 21 | Don't worry about logging with your API user and key, because Stratos was develop to avoid data leakage, so we assume some premisses: 22 | 23 | * We store your API user and key as a cookie on your browser (vanished when you close your browser) 24 | * Cookies are signed with rails app key and stored in _encrypted_ form, check this [page](http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html) for more info on cookies 25 | * API Key won't be saved on log, as you log, Rails will replace and show `"api_key"=>"[FILTERED]"` on log 26 | * Disabled logging on Jobs that receive api user / key to process API info on background. 27 | * We connect to SoftLayer API using HTTPS 28 | 29 | ## Roadmap 30 | 31 | 1. Support creation of Cloud Servers 32 | 2. Support creation of Hourly Bare Metal 33 | 3. DNS Support 34 | 4. Support creation of more complex Bare Metal packages 35 | 5. Tickets Interaction 36 | 6. Release 0.1 37 | 38 | ## Technical Premisses 39 | 40 | * (Unofficial) SoftLayer Client 41 | 42 | [SoftLayer](http://github.com/zertico/softlayer) is a (unofficial) ruby library to talk to SLAPI, it has high level Ruby models, and its the core of this application, if you're a ruby programmer and want to automate some SoftLayer task, we do **really** recommends you to check it! 43 | 44 | * Twitter bootstrap 45 | 46 | Using twitter bootstrap in the simplest possible way, so it makes easir for you to customize the views. 47 | 48 | * Trailblazer 49 | 50 | As its own description _Trailblazer is a thin layer on top of Rails. It gently enforces encapsulation, an intuitive code structure and gives you an object-oriented architecture._, so it makes easier to create the integration layer between Rails and SoftLayer API once we don't use ActiveRecord/ActiveModel. 51 | 52 | ## Contributing 53 | 54 | TODO: Write CONTRIBUTING file 55 | 56 | ## Information 57 | 58 | You can get in touch in #softlayer at freenode. 59 | 60 | TODO: Should create a google groups or mailing for questions and leave GH just for bugs? 61 | 62 | ### Questions and Bug reports 63 | 64 | If you have any question, please open an issue! If you discover any bugs, feel free to create an issue on GitHub. Please add as much information as possible to help us fixing the possible bug. We also encourage you to help even more by forking and sending us a pull request. 65 | 66 | https://github.com/softlayer/stratos/issues 67 | 68 | ## Maintainers 69 | 70 | * Celso Fernandes (https://github.com/fernandes) 71 | 72 | ## License 73 | 74 | [MIT License](LICENSE.md). Copyright (c) 2015 IBM Corporation. 75 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require File.expand_path('../config/application', __FILE__) 5 | 6 | Rails.application.load_tasks 7 | -------------------------------------------------------------------------------- /app/assets/images/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/app/assets/images/.keep -------------------------------------------------------------------------------- /app/assets/javascripts/application.js: -------------------------------------------------------------------------------- 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files 2 | // listed below. 3 | // 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, 5 | // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path. 6 | // 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the 8 | // compiled file. 9 | // 10 | // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details 11 | // about supported directives. 12 | // 13 | //= require jquery 14 | //= require jquery_ujs 15 | //= require turbolinks 16 | //= require paloma 17 | //= require bootstrap-sprockets 18 | //= require_tree . 19 | 20 | $(document).on('click', '.panel-heading span.clickable', function(e){ 21 | var $this = $(this); 22 | if(!$this.hasClass('panel-collapsed')) { 23 | $this.parents('.panel').find('.panel-body').slideUp(); 24 | $this.addClass('panel-collapsed'); 25 | $this.find('i').removeClass('glyphicon-chevron-up').addClass('glyphicon-chevron-down'); 26 | } else { 27 | $this.parents('.panel').find('.panel-body').slideDown(); 28 | $this.removeClass('panel-collapsed'); 29 | $this.find('i').removeClass('glyphicon-chevron-down').addClass('glyphicon-chevron-up'); 30 | } 31 | }) 32 | 33 | var initializePaloma = function() { 34 | Paloma.start(); 35 | } 36 | 37 | $(document).on('turbolinks:load', function(){ 38 | initializePaloma(); 39 | }); 40 | 41 | $(document).on('ajax:send', function(event, xhr){ 42 | var link = $(event.target); 43 | var message = link.data('loading-message'); 44 | var progressType = link.data('loading-progress-type'); 45 | if (message === undefined) { message = "Loading" }; 46 | if (progressType === undefined) { progressType = "success" }; 47 | waitingDialog.show(message, { progressType: progressType }); 48 | }); 49 | 50 | $(document).on('ajax:complete', function(event, xhr, status){ 51 | waitingDialog.hide(); 52 | }); 53 | 54 | 55 | document.addEventListener("turbolinks:click", function(event) { 56 | var $target = $(event.target); 57 | var loading_message = $target.data('loading-message'); 58 | if (loading_message !== undefined) { 59 | var progressType = $target.data('loading-progress-type'); 60 | if (progressType === undefined) { progressType = "success" }; 61 | waitingDialog.show(loading_message, { progressType: progressType }); 62 | } 63 | }) 64 | 65 | document.addEventListener("turbolinks:before-cache", function(event) { 66 | waitingDialog.hide(); 67 | }) 68 | -------------------------------------------------------------------------------- /app/assets/javascripts/support/waiting_dialog.js: -------------------------------------------------------------------------------- 1 | var waitingDialog = waitingDialog || (function ($) { 2 | 'use strict'; 3 | 4 | // Creating modal dialog's DOM 5 | var $dialog = $( 6 | ''); 14 | 15 | return { 16 | /** 17 | * Opens our dialog 18 | * @param message Custom message 19 | * @param options Custom options: 20 | * options.dialogSize - bootstrap postfix for dialog size, e.g. "sm", "m"; 21 | * options.progressType - bootstrap postfix for progress bar type, e.g. "success", "warning". 22 | */ 23 | show: function (message, options) { 24 | // Assigning defaults 25 | if (typeof options === 'undefined') { 26 | options = {}; 27 | } 28 | if (typeof message === 'undefined') { 29 | message = 'Loading'; 30 | } 31 | var settings = $.extend({ 32 | dialogSize: 'm', 33 | progressType: '', 34 | onHide: null // This callback runs after the dialog was hidden 35 | }, options); 36 | 37 | // Configuring dialog 38 | $dialog.find('.modal-dialog').attr('class', 'modal-dialog').addClass('modal-' + settings.dialogSize); 39 | $dialog.find('.progress-bar').attr('class', 'progress-bar'); 40 | if (settings.progressType) { 41 | $dialog.find('.progress-bar').addClass('progress-bar-' + settings.progressType); 42 | } 43 | $dialog.find('h3').text(message); 44 | // Adding callbacks 45 | if (typeof settings.onHide === 'function') { 46 | $dialog.off('hidden.bs.modal').on('hidden.bs.modal', function (e) { 47 | settings.onHide.call($dialog); 48 | }); 49 | } 50 | // Opening dialog 51 | $dialog.modal(); 52 | }, 53 | /** 54 | * Closes dialog 55 | */ 56 | hide: function () { 57 | $dialog.modal('hide'); 58 | } 59 | }; 60 | 61 | })(jQuery); 62 | -------------------------------------------------------------------------------- /app/assets/javascripts/virtual_machines.js: -------------------------------------------------------------------------------- 1 | var VirtualMachinesController = Paloma.controller('VirtualMachines'); 2 | 3 | VirtualMachinesController.prototype.new = function(){ 4 | var paloma = this; 5 | paloma.formPosting = false; 6 | 7 | $('#virtual_machine_hourly').change(function() { 8 | if ($(this).is(':checked')) { 9 | // show only hourly items 10 | $('#virtual_machine_bandwidth').val(1800); 11 | $('select option[data-recurringfee]').addClass('hidden'); 12 | $('select option[data-hourlyfee]').removeClass('hidden'); 13 | } else { 14 | // show only monthly items 15 | $('#virtual_machine_bandwidth').val(50367); 16 | $('select option[data-hourlyfee]').addClass('hidden'); 17 | $('select option[data-recurringfee]').removeClass('hidden'); 18 | } 19 | mountConflicts(this); 20 | chooseAlternativeOption(); 21 | refreshSelectItems(); 22 | refreshPriceBox(paloma); 23 | }); 24 | // hide options with location dependent true 25 | $("[data-location-dependent-flag=1]").addClass('hidden'); 26 | 27 | $("[data-resource]").change(function(){ 28 | // if we de-select datacenter option 29 | if($('[data-resource="datacenter"]').val() == ""){ 30 | // show all base prices 31 | hideDependant(); 32 | } else { 33 | // here we have a data center to process 34 | // non dependent are data centers with base prices, they are not present 35 | // on conflict hash, so we need to chack this way 36 | var non_dependent_flag = $(this).find(':selected').data('standard-prices-flag'); 37 | if (non_dependent_flag) { 38 | hideDependant(); 39 | mountConflicts(this); 40 | } else { 41 | // otherwise we need to process the datacenter based on conflict hash 42 | resource = $(this).data('resource'); 43 | hideNonDependant(); 44 | mountConflicts(this); 45 | } 46 | } 47 | 48 | // after we change the datacenter, we choose the alternative options to replace 49 | // and refresh the conflicts for alternative options 50 | chooseAlternativeOption(); 51 | refreshSelectItems(); 52 | refreshPriceBox(paloma); 53 | }); 54 | 55 | // when every select (except for datacenter) is changed 56 | // we need to show the options and hide for that price 57 | $("select[data-resource!=datacenter]").change(function(){ 58 | selected = $(this).find("option:checked"); 59 | non_dependent_flag = selected.data('location-dependent-flag'); 60 | if (!non_dependent_flag) { 61 | hideDependant(); 62 | } else { 63 | hideNonDependant(); 64 | } 65 | // hide conflicts for each price 66 | hideConflicts(conflictHash.priceToPrice, selected.val()); 67 | chooseAlternativeOption(); 68 | refreshSelectItems(); 69 | refreshPriceBox(paloma); 70 | }); 71 | 72 | loadDefaultOptions(this); 73 | }; 74 | 75 | function scrollToPriceBoxAnchor() { 76 | $('#price_box .category-name a').click(function(e) { 77 | e.preventDefault(); 78 | anchorHref = this.getAttribute('href'); 79 | $('html, body').animate({ 80 | scrollTop: $(anchorHref).offset().top - 90 81 | }, 200); 82 | }); 83 | }; 84 | 85 | function refreshPriceBox(paloma) { 86 | // bind ajax to form 87 | if (paloma.formPosting === false) { 88 | paloma.formPosting = true; 89 | form = $('form#new_virtual_machine'); 90 | formData = form.serialize(); 91 | jQuery.ajax({ 92 | type: "POST", 93 | url: '/virtual_machines/price_box', 94 | data: formData, 95 | complete: function() { 96 | paloma.formPosting = false; 97 | scrollToPriceBoxAnchor(); 98 | } 99 | }); 100 | } 101 | } 102 | function chooseAlternativeOption() { 103 | // choose alternative options 104 | $('select:not([data-resource="datacenter"])').each(function() { 105 | option = $(this).find("option:checked"); 106 | desc = option.data('item-description'); 107 | if (desc !== undefined) { 108 | new_option = $(this).find('option[class!="hidden"][data-item-description="'+desc+'"]'); 109 | if (new_option.size() === 0) { 110 | // TODO: improve the error message 111 | alert('removing option ' + desc); 112 | $(this).val(''); 113 | } 114 | $(this).val(new_option.val()); 115 | } 116 | }); 117 | } 118 | 119 | function loadDefaultOptions(paloma) { 120 | // set default options after everything is loaded 121 | paloma.params.defaultOptions.forEach(function(id) { 122 | option = $('select option[value='+id+']') 123 | select = option.closest('select'); 124 | select.val(option.val()); 125 | // select.trigger('change'); 126 | }); 127 | $('select option[data-hourlyfee]').addClass('hidden'); 128 | $('select option[data-recurringfee]').removeClass('hidden'); 129 | $('#virtual_machine_hourly').trigger('change'); 130 | mountConflicts(this); 131 | chooseAlternativeOption(); 132 | refreshSelectItems(); 133 | refreshPriceBox(paloma); 134 | } 135 | function hideDependant() { 136 | $("[data-location-dependent-flag=0]").removeClass('hidden'); 137 | $("[data-location-dependent-flag=1]").addClass('hidden'); 138 | } 139 | 140 | function hideNonDependant() { 141 | $("[data-location-dependent-flag=1]").removeClass('hidden'); 142 | } 143 | 144 | function refreshSelectItems() { 145 | // hide conflicts for other items 146 | $('select[data-resource!=datacenter]').each(function() { 147 | if ($(this).val()) { 148 | hideConflicts(conflictHash.priceToPrice, $(this).val()); 149 | hideConflicts(conflictHash.priceToLocation, $(this).val()); 150 | } 151 | }); 152 | } 153 | 154 | function hideConflicts(conflictHash, value){ 155 | if(conflictHash.hasOwnProperty(value)){ 156 | conflictHash[value].forEach(function(id){ 157 | $('option[value="' + id + '"]').addClass('hidden'); 158 | }); 159 | } 160 | } 161 | 162 | function mountConflicts(select){ 163 | errors = []; 164 | resource = $(select).data('resource'); 165 | $("select[data-resource]").each(function() { 166 | resource = $(this).data('resource'); 167 | var datacenter_id = $(this).find(':selected').data('datacenter-id'); 168 | if (datacenter_id === undefined) { 169 | datacenter_id = 957095; 170 | } 171 | if (resource === "datacenter") { 172 | hideConflicts(conflictHash.locationToPrice, datacenter_id); 173 | } else { 174 | hideConflicts(conflictHash.priceToPrice, datacenter_id); 175 | } 176 | }); 177 | } 178 | -------------------------------------------------------------------------------- /app/assets/stylesheets/application.css: -------------------------------------------------------------------------------- 1 | /* 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files 3 | * listed below. 4 | * 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. 7 | * 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the 9 | * compiled file so the styles you add here take precedence over styles defined in any styles 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new 11 | * file per style scope. 12 | * 13 | *= require_tree . 14 | *= require_self 15 | */ 16 | 17 | /* margin for fixed navbar */ 18 | body { 19 | padding-top: 70px; 20 | padding-bottom: 100px; 21 | } 22 | 23 | ul.actions { 24 | list-style-type: none; 25 | padding-left: 0px; 26 | } 27 | 28 | .fixedElement { 29 | background-color: #c0c0c0; 30 | position:fixed; 31 | top:0; 32 | width:100%; 33 | z-index:100; 34 | } 35 | 36 | .panel-heading span { 37 | margin-top: -20px; 38 | font-size: 15px; 39 | } 40 | 41 | .summary-total-container { 42 | padding: 10px; 43 | border: 1px solid #d1d3d4; 44 | border-radius: 5px; 45 | background-color: #f1f2f2; 46 | margin: 10px 0; 47 | } 48 | 49 | p.total-price { 50 | font-size: 20px; 51 | font-style: normal; 52 | font-weight: bold; 53 | margin-bottom: 10px; 54 | height: 20px; 55 | } 56 | 57 | p.total-fees { 58 | font-size: 12px; 59 | } 60 | 61 | div.summary-item { 62 | padding: 5px 0; 63 | font-size: 12px; 64 | min-height: 20px; 65 | border-bottom: 1px solid #d1d3d4; 66 | } 67 | -------------------------------------------------------------------------------- /app/assets/stylesheets/boostrap_sass.scss: -------------------------------------------------------------------------------- 1 | @import "bootstrap-sprockets"; 2 | @import "bootstrap"; 3 | -------------------------------------------------------------------------------- /app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | require "application_responder" 2 | 3 | class ApplicationController < ActionController::Base 4 | self.responder = ApplicationResponder 5 | respond_to :html 6 | before_action :check_softlayer_login 7 | before_action :set_current_user 8 | rescue_from Softlayer::Errors::SoapError, with: :handle_softlayer_exception 9 | 10 | # Prevent CSRF attacks by raising an exception. 11 | # For APIs, you may want to use :null_session instead. 12 | protect_from_forgery with: :exception 13 | 14 | def connection 15 | SoftlayerConnection.new(cookies.signed[:api_user], cookies.signed[:api_key]) 16 | end 17 | 18 | def set_current_user 19 | @current_user = cookies.signed[:api_user] 20 | end 21 | 22 | private 23 | def check_softlayer_login 24 | if cookies.signed[:api_user].nil? and cookies.signed[:api_key].nil? 25 | redirect_to login_path 26 | end 27 | end 28 | 29 | def handle_softlayer_exception(exception) 30 | return exception_invalid_login if exception.message.match /Invalid API token./ 31 | end 32 | 33 | def exception_invalid_login 34 | cookies.signed[:api_user] = nil 35 | cookies.signed[:api_key] = nil 36 | redirect_to login_path, alert: "API returned 'Invalid Credentials', Please Login Again" 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /app/controllers/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/app/controllers/concerns/.keep -------------------------------------------------------------------------------- /app/controllers/login_controller.rb: -------------------------------------------------------------------------------- 1 | class LoginController < ApplicationController 2 | skip_before_action :check_softlayer_login 3 | 4 | def new 5 | @form = LoginForm.new(OpenStruct.new) 6 | end 7 | 8 | def create 9 | @form = LoginForm.new(OpenStruct.new) 10 | if @form.validate(params[:login]) 11 | api_user = params[:login][:api_user] 12 | api_key = params[:login][:api_key] 13 | 14 | connection = SoftlayerConnection.new(api_user, api_key) 15 | if connection.valid? 16 | cookies.signed[:api_user] = api_user 17 | cookies.signed[:api_key] = api_key 18 | WarmCacheJob.logger = nil 19 | WarmCacheJob.perform_later(api_user, api_key) 20 | redirect_to root_path, notice: "Logged In Successfully" 21 | else 22 | redirect_to login_path, alert: "Invalid Credentials" 23 | end 24 | else 25 | redirect_to login_path, alert: "Invalid Credentials" 26 | end 27 | end 28 | 29 | def destroy 30 | cookies.signed[:api_user] = nil 31 | cookies.signed[:api_key] = nil 32 | redirect_to login_path, notice: 'Logged Out Successfully' 33 | end 34 | end -------------------------------------------------------------------------------- /app/controllers/virtual_machines_controller.rb: -------------------------------------------------------------------------------- 1 | class VirtualMachinesController < ApplicationController 2 | def index 3 | @virtual_machines = VirtualMachine.all 4 | end 5 | 6 | def new 7 | @vm = VirtualMachine.new 8 | @form = VirtualMachineForm.new(@vm) 9 | @conflict_hash = StoreHash.generate_hash 10 | @prices = @vm.components_price 11 | js defaultOptions: @vm.default_options 12 | end 13 | 14 | def create 15 | @vm = VirtualMachine.new 16 | @form = VirtualMachineForm.new(@vm) 17 | @conflict_hash = StoreHash.generate_hash 18 | @prices = @vm.components_price 19 | js '#new', defaultOptions: @vm.default_options 20 | if @form.validate(params[:virtual_machine]) 21 | @form.save do |hash| 22 | order_template = VirtualMachine.new(hash).template_hash 23 | container = Softlayer::Product::Order.verify_order(order_data: order_template) 24 | Softlayer::Product::Order.place_order(order_data: container) 25 | redirect_to root_path, notice: "Virtual Machine Created Successfully" 26 | end 27 | else 28 | render :new 29 | end 30 | end 31 | 32 | def price_box 33 | @vm = VirtualMachine.new(params[:virtual_machine].to_hash) 34 | @prices = @vm.components_price 35 | respond_to do |format| 36 | format.js { render action: "price_box" } 37 | end 38 | end 39 | 40 | def reboot 41 | vm = VirtualMachine.find(params[:id]) 42 | vm.reboot 43 | 44 | respond_to do |format| 45 | format.js { render } 46 | end 47 | end 48 | 49 | def power_cycle 50 | vm = VirtualMachine.find(params[:id]) 51 | 52 | if vm.running? 53 | vm.power_off 54 | @notice = "Machine turned off" 55 | elsif 56 | vm.power_on 57 | @notice = "Machine turned on" 58 | end 59 | 60 | respond_to do |format| 61 | format.js { render } 62 | end 63 | end 64 | 65 | def destroy 66 | vm = VirtualMachine.find(params[:id]) 67 | vm.destroy 68 | 69 | respond_to do |format| 70 | format.js { render } 71 | end 72 | end 73 | end 74 | -------------------------------------------------------------------------------- /app/forms/login_form.rb: -------------------------------------------------------------------------------- 1 | class LoginForm < Reform::Form 2 | property :api_user 3 | property :api_key 4 | 5 | validates :api_user, presence: true 6 | validates :api_key, presence: true 7 | end -------------------------------------------------------------------------------- /app/forms/virtual_machine_form.rb: -------------------------------------------------------------------------------- 1 | class VirtualMachineForm < Reform::Form 2 | property :hostname 3 | property :domain 4 | property :hourly 5 | property :datacenter 6 | property :guest_core 7 | property :ram 8 | property :os 9 | property :guest_disk0 10 | property :guest_disk1 11 | property :guest_disk2 12 | property :guest_disk3 13 | property :guest_disk4 14 | property :bandwidth 15 | property :port_speed 16 | property :sec_ip_addresses 17 | property :pri_ipv6_addresses 18 | property :static_ipv6_addresses 19 | property :os_addon 20 | property :cdp_backup 21 | property :control_panel 22 | property :database 23 | property :firewall 24 | property :av_spyware_protection 25 | property :intrusion_protection 26 | property :monitoring_package 27 | property :evault 28 | property :monitoring 29 | property :response 30 | property :bc_insurance 31 | 32 | validates :hostname, presence: true 33 | validates :domain, presence: true 34 | validates :hourly, presence: true 35 | validates :datacenter, presence: true, numericality: { only_integer: true } 36 | validates :guest_core, presence: true, numericality: { only_integer: true } 37 | validates :ram, presence: true, numericality: { only_integer: true } 38 | validates :os, presence: true, numericality: { only_integer: true } 39 | validates :guest_disk0, presence: true, numericality: { only_integer: true } 40 | validates :bandwidth, presence: true, numericality: { only_integer: true } 41 | validates :port_speed, presence: true, numericality: { only_integer: true } 42 | validates :monitoring, presence: true, numericality: { only_integer: true } 43 | validates :response, presence: true, numericality: { only_integer: true } 44 | end 45 | -------------------------------------------------------------------------------- /app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | def bootstrap_class_for(flash_type) 3 | { success: "alert-success", error: "alert-danger", alert: "alert-warning", notice: "alert-info" }[flash_type.to_sym] || flash_type.to_s 4 | end 5 | 6 | def flash_messages(opts = {}) 7 | flash.each do |msg_type, message| 8 | concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do 9 | concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' }) 10 | concat t(message) 11 | end) 12 | end 13 | nil 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /app/helpers/form_helper.rb: -------------------------------------------------------------------------------- 1 | module FormHelper 2 | def error_tag(model, field) 3 | errors = model.errors[field] 4 | if errors.any? 5 | render("shared/form_helper/error_tag", errors: errors) 6 | else 7 | nil 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /app/jobs/warm_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmCacheJob < ActiveJob::Base 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | WarmDatacentersCacheJob.perform_later(api_user, api_key) 7 | WarmCreateOptionsCacheJob.perform_later(api_user, api_key) 8 | WarmPackageCacheJob.perform_later(api_user, api_key) 9 | WarmConfigurationCacheJob.perform_later(api_user, api_key) 10 | WarmProductCategoriesCacheJob.perform_later(api_user, api_key) 11 | WarmStoreHashCacheJob.perform_later(api_user, api_key) 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /app/jobs/warm_configuration_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmConfigurationCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | vm = VirtualMachine.new 7 | vm.send(:configuration) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/jobs/warm_create_options_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmCreateOptionsCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | vm = VirtualMachine.new 7 | vm.send(:create_options) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/jobs/warm_datacenters_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmDatacentersCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | vm = VirtualMachine.new 7 | vm.send(:datacenters) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/jobs/warm_package_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmPackageCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | vm = VirtualMachine.new 7 | vm.send(:package) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/jobs/warm_product_categories_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmProductCategoriesCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | vm = VirtualMachine.new 7 | vm.send(:product_categories) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /app/jobs/warm_store_hash_cache_job.rb: -------------------------------------------------------------------------------- 1 | class WarmStoreHashCacheJob < WarmCacheJob 2 | queue_as :default 3 | 4 | def perform(api_user, api_key) 5 | SoftlayerConnection.new(api_user, api_key) 6 | StoreHash.generate_hash 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /app/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/app/mailers/.keep -------------------------------------------------------------------------------- /app/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/app/models/.keep -------------------------------------------------------------------------------- /app/models/concerns/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/app/models/concerns/.keep -------------------------------------------------------------------------------- /app/models/softlayer_connection.rb: -------------------------------------------------------------------------------- 1 | class SoftlayerConnection 2 | def initialize(user, key) 3 | @api_user = user 4 | @api_key = key 5 | connection 6 | end 7 | 8 | def valid? 9 | Softlayer::Account.get_current_user 10 | true 11 | rescue Softlayer::Errors::SoapError => e 12 | false 13 | end 14 | 15 | def connection 16 | Softlayer.configure do |config| 17 | config.username = @api_user 18 | config.api_key = @api_key 19 | config.open_timeout = 30 # if you want specify timeout (default 5) 20 | config.read_timeout = 30 # if you want specify timeout (default 5) 21 | end 22 | end 23 | end -------------------------------------------------------------------------------- /app/models/store_hash.rb: -------------------------------------------------------------------------------- 1 | class StoreHash 2 | attr_reader :pricing, :region, :conflict_hash 3 | 4 | def self.generate_hash 5 | Rails.cache.fetch("softlayer/package-46-conflict-hash", expires_in: 12.hours) do 6 | sh = self.new 7 | sh.conflict_hash.camelize_keys.to_json 8 | end 9 | end 10 | 11 | def initialize 12 | @pricing = StoreHash::Pricing.new 13 | @region = StoreHash::Region.new 14 | @conflict_hash = { price_to_price: {}, location_to_price: {}, price_to_location: {} } 15 | generate_conflict_hash 16 | end 17 | 18 | private 19 | def generate_conflict_hash 20 | @items 21 | hash = {} 22 | region.datacenters_ids.each { |x| conflict_hash[:location_to_price][x] = [] } 23 | items.each do |item| 24 | process_item_conflicts(item) if item.conflict_count != "0" 25 | process_location_conflicts(item) if item.location_conflict_count != "0" 26 | process_price_location_conflicts(item) 27 | process_capacity_conflicts(item) 28 | end 29 | hash 30 | end 31 | 32 | def process_item_conflicts(item) 33 | prices_for_item = pricing.prices_for(item.id) 34 | item.conflicts.each do |conflict| 35 | price_conflicts = pricing.prices_for(conflict.resource_table_id) 36 | if price_conflicts 37 | prices_for_item.each do |item_price| 38 | conflict_hash[:price_to_price][item_price] = [] if conflict_hash[:price_to_price][item_price].nil? 39 | conflict_hash[:price_to_price][item_price].concat price_conflicts 40 | end 41 | end 42 | end 43 | end 44 | 45 | def process_location_conflicts(item) 46 | prices_for_item = pricing.prices_for(item.id) 47 | item.location_conflicts.each do |conflict| 48 | 49 | # add a conflict location removing price 50 | datacenter = @region.datacenter_with_id(conflict.resource_table_id) 51 | conflict_hash[:location_to_price][datacenter.id].concat prices_for_item 52 | 53 | # add a conflict price removing location 54 | prices_for_item.each do |price| 55 | conflict_hash[:price_to_location][price] = [] if conflict_hash[:price_to_location][price].nil? 56 | conflict_hash[:price_to_location][price] << datacenter.id 57 | end 58 | end 59 | end 60 | 61 | def process_price_location_conflicts(item) 62 | dcs_ids = region.datacenters_ids 63 | 64 | # handle non base prices 65 | non_base_prices = item.prices.select { |x| x.location_group_id != nil } 66 | default_price = item.prices.select { |x| x.location_group_id.nil? }.first 67 | 68 | non_base_prices.each do |price| 69 | dcs_conflicts = region.datacenters_conflicts_for price.location_group_id 70 | dcs_conflicts.each { |x| conflict_hash[:location_to_price][x] << price.id } 71 | dcs_conflicts.each do |x| 72 | # do not add for non dependant datacenters 73 | conflict_hash[:location_to_price][x] << default_price.id if region.standard?(x) 74 | end 75 | end 76 | end 77 | 78 | def process_capacity_conflicts(item) 79 | item.prices.each do |price| 80 | unless price.capacity_restriction_type.nil? 81 | capacity_restriction_type = price.capacity_restriction_type 82 | capacity_restriction_type = "(CORE|PRIVATE_CORE)" if price.capacity_restriction_type == "CORE" 83 | # get restricted based on unit 84 | restricted = items.select { |x| x.units.match capacity_restriction_type unless x.units.nil? } 85 | # filter based on provided 86 | items_to_remove = restricted.select do |x| 87 | x.capacity.to_i > price.capacity_restriction_maximum.to_i or 88 | x.capacity.to_i < price.capacity_restriction_minimum.to_i 89 | end 90 | 91 | prices_to_remove = [] 92 | items_to_remove.each do |item| 93 | prices_to_remove.concat item.prices.map { |x| x.id } 94 | end 95 | 96 | prices_to_remove.each do |priceconf| 97 | conflict_hash[:price_to_price][priceconf] = [] if conflict_hash[:price_to_price][priceconf].nil? 98 | conflict_hash[:price_to_price][priceconf] << price.id 99 | end 100 | end 101 | end 102 | end 103 | 104 | def items 105 | Rails.cache.fetch("softlayer/package-46-items", expires_in: 12.hours) do 106 | package = Softlayer::Product::Package.find(46) 107 | items_mask = 'mask[conflictCount,conflicts,globalCategoryConflictCount,globalCategoryConflicts,locationConflictCount,locationConflicts,prices[pricingLocationGroup]]' 108 | package.mask(items_mask).get_items 109 | end 110 | end 111 | end 112 | -------------------------------------------------------------------------------- /app/models/store_hash/pricing.rb: -------------------------------------------------------------------------------- 1 | class StoreHash::Pricing 2 | def initialize 3 | generate_prices_hash 4 | generate_prices_items_hash 5 | end 6 | 7 | def prices_for(item_id) 8 | @prices_hash[item_id] 9 | end 10 | 11 | def item_for(price_id) 12 | @prices_item_hash[price_id] 13 | end 14 | 15 | def items 16 | Rails.cache.fetch("softlayer/package-46-items", expires_in: 12.hours) do 17 | package = Softlayer::Product::Package.find(46) 18 | items_mask = 'mask[conflictCount,conflicts,globalCategoryConflictCount,globalCategoryConflicts,locationConflictCount,locationConflicts,prices[pricingLocationGroup]]' 19 | package.mask(items_mask).get_items 20 | end 21 | end 22 | 23 | private 24 | def generate_prices_hash 25 | @prices_hash = {} 26 | items.each do |item| 27 | @prices_hash[item.id] = [] 28 | item.prices.each { |price| @prices_hash[item.id] << price.id } 29 | end 30 | end 31 | 32 | def generate_prices_items_hash 33 | @prices_item_hash = {} 34 | @prices_hash.each_pair do |k, v| 35 | v.each do |price_id| 36 | if @prices_item_hash.has_key? price_id 37 | @prices_item_hash[price_id] << k 38 | else 39 | @prices_item_hash[price_id] = [k] 40 | end 41 | end 42 | end 43 | end 44 | end -------------------------------------------------------------------------------- /app/models/store_hash/region.rb: -------------------------------------------------------------------------------- 1 | class StoreHash::Region 2 | def initialize 3 | generate_dcs_hash 4 | generate_dcs_groups_hash 5 | end 6 | 7 | def standard?(datacenter_id) 8 | dc = datacenters.select { |x| x.id == datacenter_id }.first 9 | return false if dc.groups.select { |x| x.location_group_type_id == 82 && x.id = 1 }.empty? 10 | true 11 | end 12 | 13 | def datacenter_with_id(datacenter_id) 14 | datacenters.select { |x| x.id == datacenter_id }.first 15 | end 16 | 17 | def datacenters_for(group_id) 18 | @dcs_groups_hash[group_id] 19 | end 20 | 21 | def datacenters_conflicts_for(group_id) 22 | return @dcs_hash.keys if datacenters_for(group_id) == nil 23 | @dcs_hash.keys - datacenters_for(group_id) 24 | end 25 | 26 | def datacenters 27 | Rails.cache.fetch("softlayer/datacenters", expires_in: 12.hours) do 28 | Softlayer::Location::Datacenter.mask('mask[groups]').get_datacenters 29 | end 30 | end 31 | 32 | def datacenters_ids 33 | @dcs_hash.keys 34 | end 35 | 36 | private 37 | def generate_dcs_hash 38 | @dcs_hash = {} 39 | datacenters.each do |dc| 40 | @dcs_hash[dc.id] = dc.groups.map { |x| x.id } 41 | end 42 | end 43 | 44 | def generate_dcs_groups_hash 45 | @dcs_groups_hash = {} 46 | @dcs_hash.each_pair do |k, v| 47 | v.each do |group_id| 48 | if @dcs_groups_hash.has_key? group_id 49 | @dcs_groups_hash[group_id] << k 50 | else 51 | @dcs_groups_hash[group_id] = [k] 52 | end 53 | end 54 | end 55 | end 56 | end -------------------------------------------------------------------------------- /app/models/virtual_machine.rb: -------------------------------------------------------------------------------- 1 | class VirtualMachine 2 | include ActiveModel::Model 3 | attr_reader :id 4 | 5 | attr_accessor :hostname, :domain, :hourly, :datacenter 6 | 7 | # system configuration 8 | attr_accessor :guest_core, :ram, :os, :guest_disk0, :guest_disk1, :guest_disk2, :guest_disk3, :guest_disk4 9 | 10 | # network options 11 | attr_accessor :bandwidth, :port_speed, :sec_ip_addresses, :pri_ipv6_addresses, :static_ipv6_addresses 12 | 13 | # system addons 14 | attr_accessor :os_addon, :cdp_backup, :control_panel, :database, :firewall, :av_spyware_protection 15 | attr_accessor :intrusion_protection, :monitoring_package 16 | 17 | # storage addons 18 | attr_accessor :evault 19 | 20 | # service addons 21 | attr_accessor :monitoring, :response, :bc_insurance 22 | 23 | # default 24 | attr_accessor :vpn_management, :vulnerability_scanner, :pri_ip_addresses, :notification, :remote_management 25 | 26 | # other 27 | attr_accessor :new_customer_setup, :premium, :managed_resource, :storage_backend_upgrade, :evault_plugin, :web_analytics 28 | 29 | delegate :fully_qualified_domain_name, :power_on, :power_off, :primary_ip_address, to: :softlayer_object 30 | delegate :primary_backend_ip_address, :provision_date, to: :softlayer_object 31 | 32 | def self.all 33 | objects = Softlayer::Account.mask('mask[powerState,status,activeTransactionCount,activeTransactions]').get_virtual_guests 34 | objects.map { |softlayer_object| self.build_from_softlayer_object(softlayer_object) } 35 | end 36 | 37 | def self.find(id) 38 | vm = self.new 39 | vm.softlayer_object = Softlayer::Virtual::Guest.mask('mask[powerState,status,activeTransactionCount,activeTransactions]').find(id) 40 | vm 41 | end 42 | 43 | def self.warm_cache 44 | vm = self.new 45 | vm.send(:datacenters) 46 | vm.send(:create_options) 47 | vm.send(:package) 48 | vm.send(:configuration) 49 | vm.send(:product_categories) 50 | end 51 | 52 | def self.build_from_softlayer_object(softlayer_object) 53 | vm = self.new 54 | vm.instance_variable_set(:@softlayer_object, softlayer_object) 55 | vm.instance_variable_set(:@id, softlayer_object.id) 56 | vm 57 | end 58 | 59 | def categories 60 | product_categories.map { |x| x.category_code } 61 | end 62 | 63 | def groups_for(category) 64 | product_categories.select { |x| x.category_code == category }.first.groups.map { |x| x.title } 65 | end 66 | 67 | def options_for_datacenter 68 | datacenters.map { |x| [x.long_name, x.id, { 69 | 'data-standard-prices-flag': x.groups.select { |x| x.location_group_type_id == 82 && x.id = 1 }.empty? ? 1 : 0, 70 | 'data-datacenter-id': x.id 71 | }] } 72 | end 73 | 74 | def form_options_for(category) 75 | Rails.cache.fetch("softlayer/46-form-options-for-#{category}", expires_in: 12.hours) do 76 | array = [] 77 | return options_for(category, nil) if groups_for(category)[0] == nil 78 | product_categories.select { |x| x.category_code == category }.each do |category| 79 | category.groups.each do |group| 80 | options = group.prices.map { |x| [x.item.description, x.id, { 81 | 'data-location-dependent-flag': (x.location_group_id.nil? ? 0 : 1), 82 | 'data-item-id': x.item.id, 83 | 'data-recurringfee': (x.recurring_fee || nil), 84 | 'data-nonrecurringfee': "0", 85 | 'data-hourlyfee': (x.hourly_recurring_fee || nil), 86 | 'data-ispriceflag': "1", 87 | 'data-item-description': x.item.description 88 | }] } 89 | array << [group.title, options] 90 | end 91 | end 92 | array 93 | end 94 | end 95 | 96 | def default_options 97 | default_items = product_categories.map do |preset| 98 | config = preset.preset_configurations 99 | if config.is_a? Array 100 | config.first.price.id 101 | else 102 | config.price.id unless config.price.nil? 103 | end 104 | end 105 | default_items.compact!.concat [1640, 1644, 273] 106 | end 107 | 108 | def components_price 109 | pricing = StoreHash::Pricing.new 110 | prices = {} 111 | prices[:total] = {hourly_fee: BigDecimal.new('0.0'), monthly_fee: BigDecimal.new('0.0')} 112 | prices[:components] = {} 113 | # process the datacenter 114 | unless datacenter.blank? 115 | location = datacenters.select { |x| x.id == datacenter.to_i }.first 116 | prices[:datacenter] = { 117 | name: "Data Center", 118 | item: location.name.upcase 119 | } 120 | end 121 | 122 | # process each component 123 | components.each do |component| 124 | category = product_categories.select { |x| x.category_code == component.to_s }.first 125 | price_id = self.send(component).to_i 126 | item_id = pricing.item_for(price_id).try(:first) 127 | if item_id 128 | item = pricing.items.select { |x| x.id == item_id }.try(:first) 129 | price = item.prices.select { |x| x.id == price_id }.try(:first) 130 | prices[:components][component] = { 131 | name: category.name, 132 | item: item.description, 133 | hourly_fee: price.hourly_recurring_fee, 134 | monthly_fee: price.recurring_fee 135 | } 136 | prices[:total][:hourly_fee] += BigDecimal.new(price.hourly_recurring_fee.to_s) 137 | prices[:total][:monthly_fee] += BigDecimal.new(price.recurring_fee.to_s) 138 | end 139 | end 140 | puts prices.inspect 141 | prices 142 | end 143 | 144 | def template_hash 145 | template = {} 146 | template['location'] = datacenter 147 | template['packageId'] = 46 148 | template['quantity'] = 1 149 | template['useHourlyPricing'] = !!hourly 150 | template['virtualGuests'] = [{domain: domain, hostname: hostname}] 151 | template['prices'] = [] 152 | components.each do |component| 153 | price_id = self.send(component).to_i 154 | template['prices'] << {id: price_id} if price_id != 0 155 | end 156 | template['prices'].concat [{"id"=>21}, {"id"=>57}, {"id"=>420}, {"id"=>418}, {"id"=>905}] 157 | template 158 | end 159 | 160 | def softlayer_object=(object) 161 | @softlayer_object = object 162 | end 163 | 164 | def reboot 165 | softlayer_object.reboot_hard 166 | end 167 | 168 | def power_state 169 | softlayer_object.power_state.key_name 170 | end 171 | 172 | def status 173 | softlayer_object.status.key_name 174 | end 175 | 176 | def destroy 177 | softlayer_object.delete_object 178 | self.freeze 179 | end 180 | 181 | def running? 182 | return true if power_state == "RUNNING" 183 | false 184 | end 185 | 186 | def active? 187 | return false unless softlayer_object.active_transaction_count == "0" 188 | return false if provision_date.nil? 189 | return true if status == "ACTIVE" 190 | false 191 | end 192 | 193 | private 194 | def softlayer_object 195 | @softlayer_object 196 | end 197 | 198 | def options_for(category, group) 199 | category = product_categories.select { |x| x.category_code == category }.first 200 | group = category.groups.select { |x| x.title == group }.first 201 | group.prices.map { |x| [x.item.description, x.id, { 202 | 'data-location-dependent-flag': (x.location_group_id.nil? ? 0 : 1), 203 | 'data-item-id': x.item.id, 204 | 'data-recurringfee': x.recurring_fee, 205 | 'data-nonrecurringfee': "0", 206 | 'data-hourlyfee': (x.hourly_recurring_fee || 0), 207 | 'data-ispriceflag': "1", 208 | 'data-item-description': x.item.description 209 | }] } 210 | end 211 | 212 | def components 213 | [:guest_core, :ram, :os, :guest_disk0, :guest_disk1, :guest_disk2, :guest_disk3, :guest_disk4, :bandwidth, :port_speed, :sec_ip_addresses, :pri_ipv6_addresses, :static_ipv6_addresses, :os_addon, :cdp_backup, :control_panel, :database, :firewall, :av_spyware_protection, :intrusion_protection, :monitoring_package ,:evault, :monitoring, :response, :bc_insurance] 214 | end 215 | 216 | def datacenters 217 | Rails.cache.fetch("softlayer/datacenters", expires_in: 12.hours) do 218 | Softlayer::Location::Datacenter.mask('mask[groups]').get_datacenters 219 | end 220 | end 221 | 222 | def create_options 223 | Rails.cache.fetch("softlayer/create_options", expires_in: 12.hours) do 224 | Softlayer::Virtual::Guest.get_create_object_options 225 | end 226 | end 227 | 228 | def package 229 | Rails.cache.fetch("softlayer/46-product_package", expires_in: 12.hours) do 230 | Softlayer::Product::Package.find(46) 231 | end 232 | end 233 | 234 | def configuration 235 | Rails.cache.fetch("softlayer/46-product_configuration", expires_in: 12.hours) do 236 | object_mask = 'mask[itemCategory[categoryCode,name,orderOptions]]' 237 | package.mask(object_mask).get_configuration 238 | end 239 | end 240 | 241 | def product_categories 242 | Rails.cache.fetch("softlayer/46-product_categories", expires_in: 12.hours) do 243 | obj_mask = 'mask[orderOptions,packageConfigurations,presetConfigurations]' 244 | package.mask(obj_mask).get_categories 245 | end 246 | end 247 | 248 | def location_ids_for(datacenter) 249 | datacenters.select { |x| x.name == datacenter }.first.groups.map { |x| x.id } 250 | end 251 | end 252 | -------------------------------------------------------------------------------- /app/models/virtual_machine/pricing.rb: -------------------------------------------------------------------------------- 1 | class VirtualMachine::Pricing 2 | class << self 3 | def price_for(vm) 4 | end 5 | 6 | def groups_for_datacenter(datacenter) 7 | datacenter = location_groups.select { |x| x.name == datacenter }.first 8 | datacenter.groups.map { |x| x.id } 9 | end 10 | 11 | def location_groups 12 | Rails.cache.fetch("softlayer/location_groups", expires_in: 12.hours) do 13 | Softlayer::Location::Datacenter.mask(location_object_mask).get_datacenters 14 | end 15 | end 16 | 17 | def price_options 18 | end 19 | end 20 | end -------------------------------------------------------------------------------- /app/views/application/_navbar.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 31 | -------------------------------------------------------------------------------- /app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stratos 8 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 9 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 10 | <%= csrf_meta_tags %> 11 | 12 | 13 | 14 | 18 | 19 | 20 |
21 | <%= render partial: 'navbar' %> 22 | <%= flash_messages %> 23 | <%= yield %> 24 |
25 | <%= insert_paloma_hook %> 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /app/views/layouts/login.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Stratos 8 | <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> 9 | <%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> 10 | <%= csrf_meta_tags %> 11 | 12 | 13 | 14 | 18 | 19 | 20 | <%= flash_messages %> 21 | <%= yield %> 22 | 23 | -------------------------------------------------------------------------------- /app/views/login/new.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | 22 |
23 |
24 | -------------------------------------------------------------------------------- /app/views/shared/form_helper/_error_tag.html.erb: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 | -------------------------------------------------------------------------------- /app/views/virtual_machines/_form.html.erb: -------------------------------------------------------------------------------- 1 | <%= simple_form_for(@form) do |f| %> 2 | <%= f.error_notification %> 3 | <%= f.input :hostname %> 4 | <%= f.input :domain %> 5 |
6 |
7 |

Hourly

8 | 9 |
10 |
11 | <%= f.input :hourly, label: "Hourly Instance", as: :boolean %> 12 |
13 |
14 |
15 |
16 |

Location

17 | 18 |
19 |
20 | <%= f.input :datacenter, label: "Data Center", collection: @form.model.options_for_datacenter, include_blank: true, input_html: { data: { 'resource': "datacenter" }} %> 21 |
22 |
23 |
24 |
25 |

System Configuration

26 | 27 |
28 |
29 | <%= f.input :guest_core, label: 'Computing Instance', collection: @form.model.form_options_for('guest_core'), as: :grouped_select, group_method: :last, include_blank: false %> 30 | <%= f.input :ram, label: 'RAM', collection: @form.model.form_options_for('ram'), include_blank: false %> 31 | <%= f.input :os, label: 'Operating System', collection: @form.model.form_options_for('os'), as: :grouped_select, group_method: :last %> 32 | <%= f.input :guest_disk0, label: 'First Disk', collection: @form.model.form_options_for('guest_disk0'), as: :grouped_select, group_method: :last, include_blank: false %> 33 | <%= f.input :guest_disk1, label: 'Second Disk', collection: @form.model.form_options_for('guest_disk1'), as: :grouped_select, group_method: :last %> 34 | <%= f.input :guest_disk2, label: 'Third Disk', collection: @form.model.form_options_for('guest_disk2'), as: :grouped_select, group_method: :last %> 35 | <%= f.input :guest_disk3, label: 'Fourth Disk', collection: @form.model.form_options_for('guest_disk3'), as: :grouped_select, group_method: :last %> 36 | <%= f.input :guest_disk4, label: 'Fifth Disk', collection: @form.model.form_options_for('guest_disk4'), as: :grouped_select, group_method: :last %> 37 |
38 |
39 |
40 |
41 |

Network Options

42 | 43 |
44 |
45 | <%= f.input :bandwidth, label: 'Public Bandwidth', collection: @form.model.form_options_for('bandwidth'), as: :grouped_select, group_method: :last, include_blank: false %> 46 | <%= f.input :port_speed, label: 'Uplink Port Speeds', collection: @form.model.form_options_for('port_speed'), as: :grouped_select, group_method: :last, include_blank: false %> 47 | <%= f.input :sec_ip_addresses, label: 'Public Secondary IP Addresses', collection: @form.model.form_options_for('sec_ip_addresses') %> 48 | <%= f.input :pri_ipv6_addresses, label: 'Primary IPv6 Addresses', collection: @form.model.form_options_for('pri_ipv6_addresses') %> 49 | <%= f.input :static_ipv6_addresses, label: 'Public Static IPv6 Addresses', collection: @form.model.form_options_for('static_ipv6_addresses') %> 50 |
51 |
52 |
53 |
54 |

System Addons

55 | 56 |
57 |
58 | <%= f.input :os_addon, label: 'OS-Specific Addon', collection: @form.model.form_options_for('os_addon'), as: :grouped_select, group_method: :last %> 59 | <%= f.input :cdp_backup, label: 'CDP Addon', collection: @form.model.form_options_for('cdp_backup') %> 60 | <%= f.input :control_panel, label: 'Control Panel Software', collection: @form.model.form_options_for('control_panel'), as: :grouped_select, group_method: :last %> 61 | <%= f.input :database, label: 'Database Software', collection: @form.model.form_options_for('database'), as: :grouped_select, group_method: :last %> 62 | <%= f.input :firewall, label: 'Hardware & Software Firewalls', collection: @form.model.form_options_for('firewall'), as: :grouped_select, group_method: :last %> 63 | <%= f.input :av_spyware_protection, label: 'Anti-Virus & Spyware Protection', collection: @form.model.form_options_for('av_spyware_protection') %> 64 | <%= f.input :intrusion_protection, label: 'Intrusion Detection & Protection', collection: @form.model.form_options_for('intrusion_protection') %> 65 | <%= f.input :monitoring_package, label: 'Advanced Monitoring', collection: @form.model.form_options_for('monitoring_package') %> 66 |
67 |
68 |
69 |
70 |

Storage Addons

71 | 72 |
73 |
74 | <%= f.input :evault, label: 'EVault', collection: @form.model.form_options_for('evault') %> 75 |
76 |
77 |
78 |
79 |

Service Addons

80 | 81 |
82 |
83 | <%= f.input :monitoring, label: 'Monitoring', collection: @form.model.form_options_for('monitoring'), include_blank: false %> 84 | <%= f.input :response, label: 'Response', collection: @form.model.form_options_for('response'), include_blank: false %> 85 | <%= f.input :bc_insurance, label: 'Insurance', collection: @form.model.form_options_for('bc_insurance') %> 86 |
87 |
88 | <%= f.button :submit, class: 'btn-success' %> 89 | <% end %> 90 | 91 | -------------------------------------------------------------------------------- /app/views/virtual_machines/_price_box.html.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 |

<%= number_to_currency(@prices[:total][:monthly_fee]) %>/mo.

4 |

<%= number_to_currency(@prices[:total][:hourly_fee]) %>/ho.

5 |

+ $0.00 in one-time fees

6 |
1
7 |
8 |
9 | 10 |
11 |
12 |

Configuration

13 |
14 |
15 | <% if @prices.has_key? :datacenter %> 16 |
17 |
18 | Data Center 19 |
20 |
21 |
22 |
<%= @prices[:datacenter][:item] %>
23 |
24 |
25 |
26 |
27 |
28 | <% end %> 29 | <% @prices[:components].each_pair do |k, v| %> 30 |
31 |
32 | <%= v[:name] %> 33 |
34 |
35 |
36 |
<%= v[:item] %>
37 |
38 | <%= number_to_currency(v[:monthly_fee]) %>/mo. 39 |
40 |
41 |
42 |
43 | <% end %> 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /app/views/virtual_machines/_vm.html.erb: -------------------------------------------------------------------------------- 1 | 2 | <%= vm.fully_qualified_domain_name %> 3 | <%= vm.primary_ip_address %> 4 | <%= vm.primary_backend_ip_address %> 5 | <%= vm.provision_date.nil? ? '-' : vm.provision_date.to_date %> 6 | 7 | 23 | 24 | -------------------------------------------------------------------------------- /app/views/virtual_machines/destroy.js.erb: -------------------------------------------------------------------------------- 1 | $('li.dropdown.open').removeClass('open'); 2 | $('.container nav.navbar').after(''); 3 | -------------------------------------------------------------------------------- /app/views/virtual_machines/index.html.erb: -------------------------------------------------------------------------------- 1 | Virtual Machines 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% @virtual_machines.each do |vm| %> 15 | <%= render partial: 'vm', locals: { vm: vm } %> 16 | <% end %> 17 | 18 |
NamePublic IPPrivate IPStart Date
19 | 20 | <%= link_to "New Virtual Machine", new_virtual_machine_path, class: "btn btn-success", role: 'button', data: { loading_message: 'Loading Virtual Machine Options..' } %> 21 | -------------------------------------------------------------------------------- /app/views/virtual_machines/new.html.erb: -------------------------------------------------------------------------------- 1 |

New Virtual Machine

2 | 3 |
4 |
5 | <%= render 'form' %> 6 |
7 |
8 | <%= render 'price_box' %> 9 |
10 |
11 | 12 | <%= link_to 'Back', virtual_machines_path %> 13 | -------------------------------------------------------------------------------- /app/views/virtual_machines/power_cycle.js.erb: -------------------------------------------------------------------------------- 1 | $('li.dropdown.open').removeClass('open'); 2 | $('.container nav.navbar').after(''); 3 | -------------------------------------------------------------------------------- /app/views/virtual_machines/price_box.js.erb: -------------------------------------------------------------------------------- 1 | $('#price_box').html("<%= j render(partial: 'price_box') %>") 2 | -------------------------------------------------------------------------------- /app/views/virtual_machines/reboot.js.erb: -------------------------------------------------------------------------------- 1 | $('li.dropdown.open').removeClass('open'); 2 | $('.container nav.navbar').after(''); 3 | -------------------------------------------------------------------------------- /bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 3 | load Gem.bin_path('bundler', 'bundle') 4 | -------------------------------------------------------------------------------- /bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | APP_PATH = File.expand_path('../../config/application', __FILE__) 7 | require_relative '../config/boot' 8 | require 'rails/commands' 9 | -------------------------------------------------------------------------------- /bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require_relative '../config/boot' 7 | require 'rake' 8 | Rake.application.run 9 | -------------------------------------------------------------------------------- /bin/rspec: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | begin 3 | load File.expand_path("../spring", __FILE__) 4 | rescue LoadError 5 | end 6 | require 'bundler/setup' 7 | load Gem.bin_path('rspec-core', 'rspec') 8 | -------------------------------------------------------------------------------- /bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'pathname' 3 | 4 | # path to your application root. 5 | APP_ROOT = Pathname.new File.expand_path('../../', __FILE__) 6 | 7 | Dir.chdir APP_ROOT do 8 | # This script is a starting point to setup your application. 9 | # Add necessary setup steps to this file: 10 | 11 | puts "== Installing dependencies ==" 12 | system "gem install bundler --conservative" 13 | system "bundle check || bundle install" 14 | 15 | # puts "\n== Copying sample files ==" 16 | # unless File.exist?("config/database.yml") 17 | # system "cp config/database.yml.sample config/database.yml" 18 | # end 19 | 20 | puts "\n== Preparing database ==" 21 | system "bin/rake db:setup" 22 | 23 | puts "\n== Removing old logs and tempfiles ==" 24 | system "rm -f log/*" 25 | system "rm -rf tmp/cache" 26 | 27 | puts "\n== Restarting application server ==" 28 | system "touch tmp/restart.txt" 29 | end 30 | -------------------------------------------------------------------------------- /bin/spring: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # This file loads spring without using Bundler, in order to be fast 4 | # It gets overwritten when you run the `spring binstub` command 5 | 6 | unless defined?(Spring) 7 | require "rubygems" 8 | require "bundler" 9 | 10 | if match = Bundler.default_lockfile.read.match(/^GEM$.*?^ (?: )*spring \((.*?)\)$.*?^$/m) 11 | ENV["GEM_PATH"] = ([Bundler.bundle_path.to_s] + Gem.path).join(File::PATH_SEPARATOR) 12 | ENV["GEM_HOME"] = "" 13 | Gem.paths = ENV 14 | 15 | gem "spring", match[1] 16 | require "spring/binstub" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require ::File.expand_path('../config/environment', __FILE__) 4 | run Rails.application 5 | -------------------------------------------------------------------------------- /config/application.rb: -------------------------------------------------------------------------------- 1 | require File.expand_path('../boot', __FILE__) 2 | 3 | require 'rails/all' 4 | 5 | # Require the gems listed in Gemfile, including any gems 6 | # you've limited to :test, :development, or :production. 7 | Bundler.require(*Rails.groups) 8 | 9 | module Stratos 10 | class Application < Rails::Application 11 | # Use the responders controller from the responders gem 12 | config.app_generators.scaffold_controller :responders_controller 13 | 14 | config.filter_parameters += [:password, :password_confirmation, :api_key] 15 | # Settings in config/environments/* take precedence over those specified here. 16 | # Application configuration should go into files in config/initializers 17 | # -- all .rb files in that directory are automatically loaded. 18 | 19 | # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone. 20 | # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC. 21 | # config.time_zone = 'Central Time (US & Canada)' 22 | 23 | # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded. 24 | # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s] 25 | # config.i18n.default_locale = :de 26 | 27 | # Do not swallow errors in after_commit/after_rollback callbacks. 28 | config.active_record.raise_in_transactional_callbacks = true 29 | end 30 | end 31 | -------------------------------------------------------------------------------- /config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', __FILE__) 2 | 3 | require 'bundler/setup' # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite version 3.x 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem 'sqlite3' 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: 5 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require File.expand_path('../application', __FILE__) 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /config/environments/development.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | config.action_mailer.delivery_method = :letter_opener 3 | # Settings specified here will take precedence over those in config/application.rb. 4 | 5 | # In the development environment your application's code is reloaded on 6 | # every request. This slows down response time but is perfect for development 7 | # since you don't have to restart the web server when you make code changes. 8 | config.cache_classes = false 9 | 10 | # Do not eager load code on boot. 11 | config.eager_load = false 12 | 13 | # Show full error reports and disable caching. 14 | config.consider_all_requests_local = true 15 | config.action_controller.perform_caching = false 16 | 17 | # Don't care if the mailer can't send. 18 | config.action_mailer.raise_delivery_errors = false 19 | 20 | # Print deprecation notices to the Rails logger. 21 | config.active_support.deprecation = :log 22 | 23 | # Raise an error on page load if there are pending migrations. 24 | config.active_record.migration_error = :page_load 25 | 26 | # Debug mode disables concatenation and preprocessing of assets. 27 | # This option may cause significant delays in view rendering with a large 28 | # number of complex assets. 29 | config.assets.debug = true 30 | 31 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 32 | # yet still be able to expire them through the digest params. 33 | config.assets.digest = true 34 | 35 | # Adds additional error checking when serving assets at runtime. 36 | # Checks for improperly declared sprockets dependencies. 37 | # Raises helpful error messages. 38 | config.assets.raise_runtime_errors = true 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/environments/production.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # Code is not reloaded between requests. 5 | config.cache_classes = true 6 | 7 | # Eager load code on boot. This eager loads most of Rails and 8 | # your application in memory, allowing both threaded web servers 9 | # and those relying on copy on write to perform better. 10 | # Rake tasks automatically ignore this option for performance. 11 | config.eager_load = true 12 | 13 | # Full error reports are disabled and caching is turned on. 14 | config.consider_all_requests_local = false 15 | config.action_controller.perform_caching = true 16 | 17 | # Enable Rack::Cache to put a simple HTTP cache in front of your application 18 | # Add `rack-cache` to your Gemfile before enabling this. 19 | # For large-scale production use, consider using a caching reverse proxy like 20 | # NGINX, varnish or squid. 21 | # config.action_dispatch.rack_cache = true 22 | 23 | # Disable serving static files from the `/public` folder by default since 24 | # Apache or NGINX already handles this. 25 | config.serve_static_files = ENV['RAILS_SERVE_STATIC_FILES'].present? 26 | 27 | # Compress JavaScripts and CSS. 28 | config.assets.js_compressor = :uglifier 29 | # config.assets.css_compressor = :sass 30 | 31 | # Do not fallback to assets pipeline if a precompiled asset is missed. 32 | config.assets.compile = false 33 | 34 | # Asset digests allow you to set far-future HTTP expiration dates on all assets, 35 | # yet still be able to expire them through the digest params. 36 | config.assets.digest = true 37 | 38 | # `config.assets.precompile` and `config.assets.version` have moved to config/initializers/assets.rb 39 | 40 | # Specifies the header that your server uses for sending files. 41 | # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache 42 | # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX 43 | 44 | # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. 45 | # config.force_ssl = true 46 | 47 | # Use the lowest log level to ensure availability of diagnostic information 48 | # when problems arise. 49 | config.log_level = :debug 50 | 51 | # Prepend all log lines with the following tags. 52 | # config.log_tags = [ :subdomain, :uuid ] 53 | 54 | # Use a different logger for distributed setups. 55 | # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) 56 | 57 | # Use a different cache store in production. 58 | # config.cache_store = :mem_cache_store 59 | 60 | # Enable serving of images, stylesheets, and JavaScripts from an asset server. 61 | # config.action_controller.asset_host = 'http://assets.example.com' 62 | 63 | # Ignore bad email addresses and do not raise email delivery errors. 64 | # Set this to true and configure the email server for immediate delivery to raise delivery errors. 65 | # config.action_mailer.raise_delivery_errors = false 66 | 67 | # Enable locale fallbacks for I18n (makes lookups for any locale fall back to 68 | # the I18n.default_locale when a translation cannot be found). 69 | config.i18n.fallbacks = true 70 | 71 | # Send deprecation notices to registered listeners. 72 | config.active_support.deprecation = :notify 73 | 74 | # Use default logging formatter so that PID and timestamp are not suppressed. 75 | config.log_formatter = ::Logger::Formatter.new 76 | 77 | # Do not dump schema after migrations. 78 | config.active_record.dump_schema_after_migration = false 79 | end 80 | -------------------------------------------------------------------------------- /config/environments/test.rb: -------------------------------------------------------------------------------- 1 | Rails.application.configure do 2 | # Settings specified here will take precedence over those in config/application.rb. 3 | 4 | # The test environment is used exclusively to run your application's 5 | # test suite. You never need to work with it otherwise. Remember that 6 | # your test database is "scratch space" for the test suite and is wiped 7 | # and recreated between test runs. Don't rely on the data there! 8 | config.cache_classes = true 9 | 10 | # Do not eager load code on boot. This avoids loading your whole application 11 | # just for the purpose of running a single test. If you are using a tool that 12 | # preloads Rails for running tests, you may have to set it to true. 13 | config.eager_load = false 14 | 15 | # Configure static file server for tests with Cache-Control for performance. 16 | config.serve_static_files = true 17 | config.static_cache_control = 'public, max-age=3600' 18 | 19 | # Show full error reports and disable caching. 20 | config.consider_all_requests_local = true 21 | config.action_controller.perform_caching = false 22 | 23 | # Raise exceptions instead of rendering exception templates. 24 | config.action_dispatch.show_exceptions = false 25 | 26 | # Disable request forgery protection in test environment. 27 | config.action_controller.allow_forgery_protection = false 28 | 29 | # Tell Action Mailer not to deliver emails to the real world. 30 | # The :test delivery method accumulates sent emails in the 31 | # ActionMailer::Base.deliveries array. 32 | config.action_mailer.delivery_method = :test 33 | 34 | # Randomize the order test cases are executed. 35 | config.active_support.test_order = :random 36 | 37 | # Print deprecation notices to the stderr. 38 | config.active_support.deprecation = :stderr 39 | 40 | # Raises error for missing translations 41 | # config.action_view.raise_on_missing_translations = true 42 | end 43 | -------------------------------------------------------------------------------- /config/initializers/assets.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Version of your assets, change this if you want to expire all your assets. 4 | Rails.application.config.assets.version = '1.0' 5 | 6 | # Add additional assets to the asset load path 7 | # Rails.application.config.assets.paths << Emoji.images_path 8 | 9 | # Precompile additional assets. 10 | # application.js, application.css, and all non-JS/CSS in app/assets folder are already added. 11 | # Rails.application.config.assets.precompile += %w( search.js ) 12 | -------------------------------------------------------------------------------- /config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.action_dispatch.cookies_serializer = :json 4 | -------------------------------------------------------------------------------- /config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure sensitive parameters which will be filtered from the log file. 4 | Rails.application.config.filter_parameters += [:password] 5 | -------------------------------------------------------------------------------- /config/initializers/inflections.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new inflection rules using the following format. Inflections 4 | # are locale specific, and you may define rules for as many different 5 | # locales as you wish. All of these examples are active by default: 6 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 7 | # inflect.plural /^(ox)$/i, '\1en' 8 | # inflect.singular /^(ox)en/i, '\1' 9 | # inflect.irregular 'person', 'people' 10 | # inflect.uncountable %w( fish sheep ) 11 | # end 12 | 13 | # These inflection rules are supported but not enabled by default: 14 | # ActiveSupport::Inflector.inflections(:en) do |inflect| 15 | # inflect.acronym 'RESTful' 16 | # end 17 | -------------------------------------------------------------------------------- /config/initializers/mime_types.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Add new mime types for use in respond_to blocks: 4 | # Mime::Type.register "text/richtext", :rtf 5 | -------------------------------------------------------------------------------- /config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: '_stratos_session' 4 | -------------------------------------------------------------------------------- /config/initializers/simple_form.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | # Wrappers are used by the form builder to generate a 4 | # complete input. You can remove any component from the 5 | # wrapper, change the order or even add your own to the 6 | # stack. The options given below are used to wrap the 7 | # whole input. 8 | config.wrappers :default, class: :input, 9 | hint_class: :field_with_hint, error_class: :field_with_errors do |b| 10 | ## Extensions enabled by default 11 | # Any of these extensions can be disabled for a 12 | # given input by passing: `f.input EXTENSION_NAME => false`. 13 | # You can make any of these extensions optional by 14 | # renaming `b.use` to `b.optional`. 15 | 16 | # Determines whether to use HTML5 (:email, :url, ...) 17 | # and required attributes 18 | b.use :html5 19 | 20 | # Calculates placeholders automatically from I18n 21 | # You can also pass a string as f.input placeholder: "Placeholder" 22 | b.use :placeholder 23 | 24 | ## Optional extensions 25 | # They are disabled unless you pass `f.input EXTENSION_NAME => true` 26 | # to the input. If so, they will retrieve the values from the model 27 | # if any exists. If you want to enable any of those 28 | # extensions by default, you can change `b.optional` to `b.use`. 29 | 30 | # Calculates maxlength from length validations for string inputs 31 | b.optional :maxlength 32 | 33 | # Calculates pattern from format validations for string inputs 34 | b.optional :pattern 35 | 36 | # Calculates min and max from length validations for numeric inputs 37 | b.optional :min_max 38 | 39 | # Calculates readonly automatically from readonly attributes 40 | b.optional :readonly 41 | 42 | ## Inputs 43 | b.use :label_input 44 | b.use :hint, wrap_with: { tag: :span, class: :hint } 45 | b.use :error, wrap_with: { tag: :span, class: :error } 46 | 47 | ## full_messages_for 48 | # If you want to display the full error message for the attribute, you can 49 | # use the component :full_error, like: 50 | # 51 | # b.use :full_error, wrap_with: { tag: :span, class: :error } 52 | end 53 | 54 | # The default wrapper to be used by the FormBuilder. 55 | config.default_wrapper = :default 56 | 57 | # Define the way to render check boxes / radio buttons with labels. 58 | # Defaults to :nested for bootstrap config. 59 | # inline: input + label 60 | # nested: label > input 61 | config.boolean_style = :nested 62 | 63 | # Default class for buttons 64 | config.button_class = 'btn' 65 | 66 | # Method used to tidy up errors. Specify any Rails Array method. 67 | # :first lists the first message for each field. 68 | # Use :to_sentence to list all errors for each field. 69 | # config.error_method = :first 70 | 71 | # Default tag used for error notification helper. 72 | config.error_notification_tag = :div 73 | 74 | # CSS class to add for error notification helper. 75 | config.error_notification_class = 'error_notification' 76 | 77 | # ID to add for error notification helper. 78 | # config.error_notification_id = nil 79 | 80 | # Series of attempts to detect a default label method for collection. 81 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] 82 | 83 | # Series of attempts to detect a default value method for collection. 84 | # config.collection_value_methods = [ :id, :to_s ] 85 | 86 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. 87 | # config.collection_wrapper_tag = nil 88 | 89 | # You can define the class to use on all collection wrappers. Defaulting to none. 90 | # config.collection_wrapper_class = nil 91 | 92 | # You can wrap each item in a collection of radio/check boxes with a tag, 93 | # defaulting to :span. Please note that when using :boolean_style = :nested, 94 | # SimpleForm will force this option to be a label. 95 | # config.item_wrapper_tag = :span 96 | 97 | # You can define a class to use in all item wrappers. Defaulting to none. 98 | # config.item_wrapper_class = nil 99 | 100 | # How the label text should be generated altogether with the required text. 101 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } 102 | 103 | # You can define the class to use on all labels. Default is nil. 104 | # config.label_class = nil 105 | 106 | # You can define the default class to be used on forms. Can be overriden 107 | # with `html: { :class }`. Defaulting to none. 108 | # config.default_form_class = nil 109 | 110 | # You can define which elements should obtain additional classes 111 | # config.generate_additional_classes_for = [:wrapper, :label, :input] 112 | 113 | # Whether attributes are required by default (or not). Default is true. 114 | # config.required_by_default = true 115 | 116 | # Tell browsers whether to use the native HTML5 validations (novalidate form option). 117 | # These validations are enabled in SimpleForm's internal config but disabled by default 118 | # in this configuration, which is recommended due to some quirks from different browsers. 119 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, 120 | # change this configuration to true. 121 | config.browser_validations = false 122 | 123 | # Collection of methods to detect if a file type was given. 124 | # config.file_methods = [ :mounted_as, :file?, :public_filename ] 125 | 126 | # Custom mappings for input types. This should be a hash containing a regexp 127 | # to match as key, and the input type that will be used when the field name 128 | # matches the regexp as value. 129 | # config.input_mappings = { /count/ => :integer } 130 | 131 | # Custom wrappers for input types. This should be a hash containing an input 132 | # type as key and the wrapper that will be used for all inputs with specified type. 133 | # config.wrapper_mappings = { string: :prepend } 134 | 135 | # Namespaces where SimpleForm should look for custom input classes that 136 | # override default inputs. 137 | # config.custom_inputs_namespaces << "CustomInputs" 138 | 139 | # Default priority for time_zone inputs. 140 | # config.time_zone_priority = nil 141 | 142 | # Default priority for country inputs. 143 | # config.country_priority = nil 144 | 145 | # When false, do not use translations for labels. 146 | # config.translate_labels = true 147 | 148 | # Automatically discover new inputs in Rails' autoload path. 149 | # config.inputs_discovery = true 150 | 151 | # Cache SimpleForm inputs discovery 152 | # config.cache_discovery = !Rails.env.development? 153 | 154 | # Default class for inputs 155 | # config.input_class = nil 156 | 157 | # Define the default class of the input wrapper of the boolean input. 158 | config.boolean_label_class = 'checkbox' 159 | 160 | # Defines if the default input wrapper class should be included in radio 161 | # collection wrappers. 162 | # config.include_default_input_wrapper_class = true 163 | 164 | # Defines which i18n scope will be used in Simple Form. 165 | # config.i18n_scope = 'simple_form' 166 | end 167 | -------------------------------------------------------------------------------- /config/initializers/simple_form_bootstrap.rb: -------------------------------------------------------------------------------- 1 | # Use this setup block to configure all options available in SimpleForm. 2 | SimpleForm.setup do |config| 3 | config.error_notification_class = 'alert alert-danger' 4 | config.button_class = 'btn btn-default' 5 | config.boolean_label_class = nil 6 | 7 | config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 8 | b.use :html5 9 | b.use :placeholder 10 | b.optional :maxlength 11 | b.optional :pattern 12 | b.optional :min_max 13 | b.optional :readonly 14 | b.use :label, class: 'control-label' 15 | 16 | b.use :input, class: 'form-control' 17 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 18 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 19 | end 20 | 21 | config.wrappers :vertical_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 22 | b.use :html5 23 | b.use :placeholder 24 | b.optional :maxlength 25 | b.optional :readonly 26 | b.use :label, class: 'control-label' 27 | 28 | b.use :input 29 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 30 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 31 | end 32 | 33 | config.wrappers :vertical_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 34 | b.use :html5 35 | b.optional :readonly 36 | 37 | b.wrapper tag: 'div', class: 'checkbox' do |ba| 38 | ba.use :label_input 39 | end 40 | 41 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 42 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 43 | end 44 | 45 | config.wrappers :vertical_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 46 | b.use :html5 47 | b.optional :readonly 48 | b.use :label, class: 'control-label' 49 | b.use :input 50 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 51 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 52 | end 53 | 54 | config.wrappers :horizontal_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 55 | b.use :html5 56 | b.use :placeholder 57 | b.optional :maxlength 58 | b.optional :pattern 59 | b.optional :min_max 60 | b.optional :readonly 61 | b.use :label, class: 'col-sm-3 control-label' 62 | 63 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 64 | ba.use :input, class: 'form-control' 65 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 66 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 67 | end 68 | end 69 | 70 | config.wrappers :horizontal_file_input, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 71 | b.use :html5 72 | b.use :placeholder 73 | b.optional :maxlength 74 | b.optional :readonly 75 | b.use :label, class: 'col-sm-3 control-label' 76 | 77 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 78 | ba.use :input 79 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 80 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 81 | end 82 | end 83 | 84 | config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 85 | b.use :html5 86 | b.optional :readonly 87 | 88 | b.wrapper tag: 'div', class: 'col-sm-offset-3 col-sm-9' do |wr| 89 | wr.wrapper tag: 'div', class: 'checkbox' do |ba| 90 | ba.use :label_input 91 | end 92 | 93 | wr.use :error, wrap_with: { tag: 'span', class: 'help-block' } 94 | wr.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 95 | end 96 | end 97 | 98 | config.wrappers :horizontal_radio_and_checkboxes, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 99 | b.use :html5 100 | b.optional :readonly 101 | 102 | b.use :label, class: 'col-sm-3 control-label' 103 | 104 | b.wrapper tag: 'div', class: 'col-sm-9' do |ba| 105 | ba.use :input 106 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 107 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 108 | end 109 | end 110 | 111 | config.wrappers :inline_form, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 112 | b.use :html5 113 | b.use :placeholder 114 | b.optional :maxlength 115 | b.optional :pattern 116 | b.optional :min_max 117 | b.optional :readonly 118 | b.use :label, class: 'sr-only' 119 | 120 | b.use :input, class: 'form-control' 121 | b.use :error, wrap_with: { tag: 'span', class: 'help-block' } 122 | b.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 123 | end 124 | 125 | config.wrappers :multi_select, tag: 'div', class: 'form-group', error_class: 'has-error' do |b| 126 | b.use :html5 127 | b.optional :readonly 128 | b.use :label, class: 'control-label' 129 | b.wrapper tag: 'div', class: 'form-inline' do |ba| 130 | ba.use :input, class: 'form-control' 131 | ba.use :error, wrap_with: { tag: 'span', class: 'help-block' } 132 | ba.use :hint, wrap_with: { tag: 'p', class: 'help-block' } 133 | end 134 | end 135 | # Wrappers for forms and inputs using the Bootstrap toolkit. 136 | # Check the Bootstrap docs (http://getbootstrap.com) 137 | # to learn about the different styles for forms and inputs, 138 | # buttons and other elements. 139 | config.default_wrapper = :vertical_form 140 | config.wrapper_mappings = { 141 | check_boxes: :vertical_radio_and_checkboxes, 142 | radio_buttons: :vertical_radio_and_checkboxes, 143 | file: :vertical_file_input, 144 | boolean: :vertical_boolean, 145 | datetime: :multi_select, 146 | date: :multi_select, 147 | time: :multi_select 148 | } 149 | end 150 | -------------------------------------------------------------------------------- /config/initializers/softlayer.rb: -------------------------------------------------------------------------------- 1 | Softlayer.configure do |config| 2 | # API User and Key will be set on login 3 | # config.username = 4 | # config.api_key = 5 | config.open_timeout = 30 # if you want specify timeout (default 5) 6 | config.read_timeout = 30 # if you want specify timeout (default 5) 7 | end 8 | -------------------------------------------------------------------------------- /config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] if respond_to?(:wrap_parameters) 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t 'hello' 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t('hello') %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # To learn more, please read the Rails Internationalization guide 20 | # available at http://guides.rubyonrails.org/i18n.html. 21 | 22 | en: 23 | hello: "Hello world" 24 | -------------------------------------------------------------------------------- /config/locales/responders.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | flash: 3 | actions: 4 | create: 5 | notice: '%{resource_name} was successfully created.' 6 | # alert: '%{resource_name} could not be created.' 7 | update: 8 | notice: '%{resource_name} was successfully updated.' 9 | # alert: '%{resource_name} could not be updated.' 10 | destroy: 11 | notice: '%{resource_name} was successfully destroyed.' 12 | alert: '%{resource_name} could not be destroyed.' 13 | -------------------------------------------------------------------------------- /config/locales/simple_form.en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | simple_form: 3 | "yes": 'Yes' 4 | "no": 'No' 5 | required: 6 | text: 'required' 7 | mark: '*' 8 | # You can uncomment the line below if you need to overwrite the whole required html. 9 | # When using html, text and mark won't be used. 10 | # html: '*' 11 | error_notification: 12 | default_message: "Please review the problems below:" 13 | # Examples 14 | # labels: 15 | # defaults: 16 | # password: 'Password' 17 | # user: 18 | # new: 19 | # email: 'E-mail to sign in.' 20 | # edit: 21 | # email: 'E-mail.' 22 | # hints: 23 | # defaults: 24 | # username: 'User name to sign in.' 25 | # password: 'No special characters, please.' 26 | # include_blanks: 27 | # defaults: 28 | # age: 'Rather not say' 29 | # prompts: 30 | # defaults: 31 | # age: 'Select your age' 32 | -------------------------------------------------------------------------------- /config/routes.rb: -------------------------------------------------------------------------------- 1 | Rails.application.routes.draw do 2 | get '/login', as: :login, controller: 'login', action: 'new' 3 | get '/logout', as: :logout, controller: 'login', action: 'destroy' 4 | post '/login', as: :new_login, controller: 'login', action: 'create' 5 | resources :virtual_machines do 6 | collection do 7 | post :price_box 8 | end 9 | member do 10 | get :reboot 11 | get :power_cycle 12 | end 13 | end 14 | root to: 'virtual_machines#index' 15 | end 16 | -------------------------------------------------------------------------------- /config/secrets.yml: -------------------------------------------------------------------------------- 1 | development: 2 | secret_key_base: 32a148de8860f1027ab2e7db6a38dcac0af794beac49821c8e01d68e13f6b72b7fd1331fcd1a9da97429f7497431dcda03f2f8fcdc8f8f034743fd0ad77fbf03 3 | 4 | test: 5 | secret_key_base: 32a148de8860f1027ab2e7db6a38dcac0af794beac49821c8e01d68e13f6b72b7fd1331fcd1a9da97429f7497431dcda03f2f8fcdc8f8f034743fd0ad77fbf03 6 | 7 | production: 8 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 9 | -------------------------------------------------------------------------------- /db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the rake db:seed (or created alongside the db with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # cities = City.create([{ name: 'Chicago' }, { name: 'Copenhagen' }]) 7 | # Mayor.create(name: 'Emanuel', city: cities.first) 8 | -------------------------------------------------------------------------------- /lib/application_responder.rb: -------------------------------------------------------------------------------- 1 | class ApplicationResponder < ActionController::Responder 2 | include Responders::FlashResponder 3 | include Responders::HttpCacheResponder 4 | 5 | # Redirects resources to the collection path (index action) instead 6 | # of the resource path (show action) for POST/PUT/DELETE requests. 7 | # include Responders::CollectionResponder 8 | end 9 | -------------------------------------------------------------------------------- /lib/assets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/lib/assets/.keep -------------------------------------------------------------------------------- /lib/tasks/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/lib/tasks/.keep -------------------------------------------------------------------------------- /lib/tasks/custom_seed.rake: -------------------------------------------------------------------------------- 1 | namespace :db do 2 | namespace :seed do 3 | Dir[File.join(Rails.root, 'db', 'seeds', '*.rb')].each do |filename| 4 | task_name = File.basename(filename, '.rb').intern 5 | task task_name => :environment do 6 | load(filename) if File.exist?(filename) 7 | end 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /lib/templates/haml/scaffold/_form.html.haml: -------------------------------------------------------------------------------- 1 | = simple_form_for(@<%= singular_table_name %>) do |f| 2 | = f.error_notification 3 | 4 | .form-inputs 5 | <%- attributes.each do |attribute| -%> 6 | = f.<%= attribute.reference? ? :association : :input %> :<%= attribute.name %> 7 | <%- end -%> 8 | 9 | .form-actions 10 | = f.button :submit 11 | -------------------------------------------------------------------------------- /public/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The page you were looking for doesn't exist (404) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The page you were looking for doesn't exist.

62 |

You may have mistyped the address or the page may have moved.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/422.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | The change you wanted was rejected (422) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

The change you wanted was rejected.

62 |

Maybe you tried to change something you didn't have access to.

63 |
64 |

If you are the application owner check the logs for more information.

65 |
66 | 67 | 68 | -------------------------------------------------------------------------------- /public/500.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | We're sorry, but something went wrong (500) 5 | 6 | 55 | 56 | 57 | 58 | 59 |
60 |
61 |

We're sorry, but something went wrong.

62 |
63 |

If you are the application owner check the logs for more information.

64 |
65 | 66 | 67 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/public/favicon.ico -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # See http://www.robotstxt.org/robotstxt.html for documentation on how to use the robots.txt file 2 | # 3 | # To ban all spiders from the entire site uncomment the next two lines: 4 | # User-agent: * 5 | # Disallow: / 6 | -------------------------------------------------------------------------------- /spec/rails_helper.rb: -------------------------------------------------------------------------------- 1 | # This file is copied to spec/ when you run 'rails generate rspec:install' 2 | ENV['RAILS_ENV'] ||= 'test' 3 | require 'spec_helper' 4 | require File.expand_path('../../config/environment', __FILE__) 5 | require 'rspec/rails' 6 | # Add additional requires below this line. Rails is not loaded until this point! 7 | 8 | # Requires supporting ruby files with custom matchers and macros, etc, in 9 | # spec/support/ and its subdirectories. Files matching `spec/**/*_spec.rb` are 10 | # run as spec files by default. This means that files in spec/support that end 11 | # in _spec.rb will both be required and run as specs, causing the specs to be 12 | # run twice. It is recommended that you do not name files matching this glob to 13 | # end with _spec.rb. You can configure this pattern with the --pattern 14 | # option on the command line or in ~/.rspec, .rspec or `.rspec-local`. 15 | # 16 | # The following line is provided for convenience purposes. It has the downside 17 | # of increasing the boot-up time by auto-requiring all files in the support 18 | # directory. Alternatively, in the individual `*_spec.rb` files, manually 19 | # require only the support files necessary. 20 | # 21 | # Dir[Rails.root.join('spec/support/**/*.rb')].each { |f| require f } 22 | 23 | # Checks for pending migrations before tests are run. 24 | # If you are not using ActiveRecord, you can remove this line. 25 | ActiveRecord::Migration.maintain_test_schema! 26 | 27 | RSpec.configure do |config| 28 | # Remove this line if you're not using ActiveRecord or ActiveRecord fixtures 29 | config.fixture_path = "#{::Rails.root}/spec/fixtures" 30 | 31 | # If you're not using ActiveRecord, or you'd prefer not to run each of your 32 | # examples within a transaction, remove the following line or assign false 33 | # instead of true. 34 | config.use_transactional_fixtures = true 35 | 36 | # RSpec Rails can automatically mix in different behaviours to your tests 37 | # based on their file location, for example enabling you to call `get` and 38 | # `post` in specs under `spec/controllers`. 39 | # 40 | # You can disable this behaviour by removing the line below, and instead 41 | # explicitly tag your specs with their type, e.g.: 42 | # 43 | # RSpec.describe UsersController, :type => :controller do 44 | # # ... 45 | # end 46 | # 47 | # The different available types are documented in the features, such as in 48 | # https://relishapp.com/rspec/rspec-rails/docs 49 | config.infer_spec_type_from_file_location! 50 | end 51 | -------------------------------------------------------------------------------- /spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | # Load turnip steps 2 | require 'turnip/rspec' 3 | require 'turnip/capybara' 4 | Dir.glob("spec/steps/**/*steps.rb") { |f| load f, true } 5 | 6 | # This file was generated by the `rails generate rspec:install` command. Conventionally, all 7 | # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`. 8 | # The generated `.rspec` file contains `--require spec_helper` which will cause 9 | # this file to always be loaded, without a need to explicitly require it in any 10 | # files. 11 | # 12 | # Given that it is always loaded, you are encouraged to keep this file as 13 | # light-weight as possible. Requiring heavyweight dependencies from this file 14 | # will add to the boot time of your test suite on EVERY test run, even for an 15 | # individual file that may not need all of that loaded. Instead, consider making 16 | # a separate helper file that requires the additional dependencies and performs 17 | # the additional setup, and require it from the spec files that actually need 18 | # it. 19 | # 20 | # The `.rspec` file also contains a few flags that are not defaults but that 21 | # users commonly want. 22 | # 23 | # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration 24 | RSpec.configure do |config| 25 | # rspec-expectations config goes here. You can use an alternate 26 | # assertion/expectation library such as wrong or the stdlib/minitest 27 | # assertions if you prefer. 28 | config.expect_with :rspec do |expectations| 29 | # This option will default to `true` in RSpec 4. It makes the `description` 30 | # and `failure_message` of custom matchers include text for helper methods 31 | # defined using `chain`, e.g.: 32 | # be_bigger_than(2).and_smaller_than(4).description 33 | # # => "be bigger than 2 and smaller than 4" 34 | # ...rather than: 35 | # # => "be bigger than 2" 36 | expectations.include_chain_clauses_in_custom_matcher_descriptions = true 37 | end 38 | 39 | # rspec-mocks config goes here. You can use an alternate test double 40 | # library (such as bogus or mocha) by changing the `mock_with` option here. 41 | config.mock_with :rspec do |mocks| 42 | # Prevents you from mocking or stubbing a method that does not exist on 43 | # a real object. This is generally recommended, and will default to 44 | # `true` in RSpec 4. 45 | mocks.verify_partial_doubles = true 46 | end 47 | 48 | # The settings below are suggested to provide a good initial experience 49 | # with RSpec, but feel free to customize to your heart's content. 50 | =begin 51 | # These two settings work together to allow you to limit a spec run 52 | # to individual examples or groups you care about by tagging them with 53 | # `:focus` metadata. When nothing is tagged with `:focus`, all examples 54 | # get run. 55 | config.filter_run :focus 56 | config.run_all_when_everything_filtered = true 57 | 58 | # Limits the available syntax to the non-monkey patched syntax that is 59 | # recommended. For more details, see: 60 | # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax 61 | # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/ 62 | # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching 63 | config.disable_monkey_patching! 64 | 65 | # Many RSpec users commonly either run the entire suite or an individual 66 | # file, and it's useful to allow more verbose output when running an 67 | # individual spec file. 68 | if config.files_to_run.one? 69 | # Use the documentation formatter for detailed output, 70 | # unless a formatter has already been configured 71 | # (e.g. via a command-line flag). 72 | config.default_formatter = 'doc' 73 | end 74 | 75 | # Print the 10 slowest examples and example groups at the 76 | # end of the spec run, to help surface which specs are running 77 | # particularly slow. 78 | config.profile_examples = 10 79 | 80 | # Run specs in random order to surface order dependencies. If you find an 81 | # order dependency and want to debug it, you can fix the order by providing 82 | # the seed, which is printed after each run. 83 | # --seed 1234 84 | config.order = :random 85 | 86 | # Seed global randomization in this process using the `--seed` CLI option. 87 | # Setting this allows you to use `--seed` to deterministically reproduce 88 | # test failures related to randomization by passing the same `--seed` value 89 | # as the one that triggered the failure. 90 | Kernel.srand config.seed 91 | =end 92 | end 93 | -------------------------------------------------------------------------------- /test/controllers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/controllers/.keep -------------------------------------------------------------------------------- /test/fixtures/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/fixtures/.keep -------------------------------------------------------------------------------- /test/helpers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/helpers/.keep -------------------------------------------------------------------------------- /test/integration/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/integration/.keep -------------------------------------------------------------------------------- /test/mailers/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/mailers/.keep -------------------------------------------------------------------------------- /test/models/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/test/models/.keep -------------------------------------------------------------------------------- /test/test_helper.rb: -------------------------------------------------------------------------------- 1 | ENV['RAILS_ENV'] ||= 'test' 2 | require File.expand_path('../../config/environment', __FILE__) 3 | require 'rails/test_help' 4 | 5 | class ActiveSupport::TestCase 6 | # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order. 7 | fixtures :all 8 | 9 | # Add more helper methods to be used by all tests here... 10 | end 11 | -------------------------------------------------------------------------------- /vendor/assets/javascripts/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/vendor/assets/javascripts/.keep -------------------------------------------------------------------------------- /vendor/assets/stylesheets/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/softlayer/stratos/3c2c8aecba8e625538ff912fac15b8036669d662/vendor/assets/stylesheets/.keep --------------------------------------------------------------------------------