orats 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +11 -4
- data/lib/orats/cli.rb +34 -23
- data/lib/orats/commands/common.rb +82 -0
- data/lib/orats/commands/new/ansible.rb +105 -0
- data/lib/orats/commands/new/exec.rb +54 -0
- data/lib/orats/commands/new/foreman.rb +55 -0
- data/lib/orats/commands/new/rails.rb +107 -0
- data/lib/orats/commands/nuke.rb +72 -0
- data/lib/orats/commands/outdated/compare.rb +100 -0
- data/lib/orats/commands/outdated/exec.rb +46 -0
- data/lib/orats/commands/outdated/parse.rb +62 -0
- data/lib/orats/commands/play.rb +34 -0
- data/lib/orats/commands/ui.rb +52 -0
- data/lib/orats/templates/auth.rb +1 -3
- data/lib/orats/templates/base.rb +243 -11
- data/lib/orats/templates/includes/Galaxyfile +1 -1
- data/lib/orats/templates/includes/Gemfile +5 -1
- data/lib/orats/templates/includes/inventory/group_vars/all.yml +14 -9
- data/lib/orats/templates/play.rb +0 -3
- data/lib/orats/version.rb +1 -1
- metadata +13 -6
- data/lib/orats/command.rb +0 -107
- data/lib/orats/foreman.rb +0 -54
- data/lib/orats/shell.rb +0 -503
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ed2be672732a97ee0adf810bdef6be8e40df6415
|
4
|
+
data.tar.gz: caa247df80d369533b424a261ba57b254501b579
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f26035196b05988cd3eda4a894cbd651aedb8a33a6da75eae97fb5e0d43b1df49e066945f928b2b8e7b1b21a9df1d005dbf926688ae40ecce4b70e19f81f86f
|
7
|
+
data.tar.gz: 67cbd89f2b3eb6a93e1a099e7b5b910f05c288a1d8f811fdbf8f8297af40727ed738ad6b18e2acf7f7509609c8f2a8a5415e33326b9297004d973385969bf2ae
|
data/README.md
CHANGED
@@ -6,6 +6,8 @@ It stands for opinionated rails application templates. The templates include sol
|
|
6
6
|
projects. It handles creating a rails application with a bunch of opinions and optionally an ansible playbook so you can
|
7
7
|
deploy your apps quickly.
|
8
8
|
|
9
|
+
You can also optionally include custom rails templates to append to any template you create with orats.
|
10
|
+
|
9
11
|
Everything is accessed through the [orats gem](#installation).
|
10
12
|
|
11
13
|
## What version of Rails and Ruby are you targeting?
|
@@ -62,7 +64,7 @@ Here is an overview of the available commands. You can find out more information
|
|
62
64
|
running `orats <command name> help` from your terminal. You can also type `orats` on its own to see a list of all commands.
|
63
65
|
|
64
66
|
- Create a new orats project
|
65
|
-
- `orats new <
|
67
|
+
- `orats new <TARGET_PATH> --pg-password <development postgres db password>`
|
66
68
|
- Configuration:
|
67
69
|
- Optionally takes: `--pg-location [localhost]`
|
68
70
|
- Optionally takes: `--pg-username [postgres]`
|
@@ -70,6 +72,7 @@ running `orats <command name> help` from your terminal. You can also type `orats
|
|
70
72
|
- Optionally takes: `--redis-password []`
|
71
73
|
- Template features:
|
72
74
|
- Optionally takes: `--auth [false]`
|
75
|
+
- Optionally takes: `--template []`
|
73
76
|
- Project features:
|
74
77
|
- Optionally takes: `--skip-extras [false]`
|
75
78
|
- Optionally takes: `--skip-foreman-start [false]`
|
@@ -78,10 +81,12 @@ running `orats <command name> help` from your terminal. You can also type `orats
|
|
78
81
|
- Optionally takes: `--skip-galaxy [false]`
|
79
82
|
|
80
83
|
- Create an ansible playbook
|
81
|
-
- `orats play <
|
84
|
+
- `orats play <TARGET_PATH>`
|
85
|
+
- Template features:
|
86
|
+
- Optionally takes: `--template []`
|
82
87
|
|
83
88
|
- Delete the directory and optionally all data associated to it
|
84
|
-
- `orats nuke <
|
89
|
+
- `orats nuke <TARGET_PATH>`
|
85
90
|
- Optionally takes: `--skip-data [false]`
|
86
91
|
|
87
92
|
- Detect whether or not orats, the playbook or inventory is outdated
|
@@ -124,10 +129,12 @@ it includes these features and when I do not want a specific thing it is much qu
|
|
124
129
|
- Create development, staging and production environments.
|
125
130
|
- Use environment variables for things that are likely to change per environment.
|
126
131
|
- Use environment variables for anything that is sensitive and should not be included into version control.
|
132
|
+
- Add environment variables for google analytics UI, disqus short name and S3 in addition to a bunch of typical rails values.
|
127
133
|
- Use redis as the cache backend.
|
128
134
|
- Use sidekiq as a background worker.
|
129
135
|
- Use puma as the server with settings capable of doing phased restarts.
|
130
136
|
- Use foreman in development mode to manage starting both the rails server using puma and sidekiq.
|
137
|
+
- Add a rake task to handle upgrades using the `backup` gem.
|
131
138
|
- Set the production asset precompiler to include fonts and png files.
|
132
139
|
- Set the production logger to rotate the logs daily.
|
133
140
|
- Set the timezone to EST.
|
@@ -140,7 +147,7 @@ it includes these features and when I do not want a specific thing it is much qu
|
|
140
147
|
- Add 3 view helpers to easily set a page's title, meta description and page heading. All of which are optional.
|
141
148
|
- Bootstrap ~3 layout file with conditionally loaded `html5shiv`, `json3` and `respondjs` libs for IE < 9 support.
|
142
149
|
- Separate the navigation, navigation links, flash messages and footer partials.
|
143
|
-
- Add partials
|
150
|
+
- Add partials for both google analytics and disqus.
|
144
151
|
- Public 404, 422, 500 and 502 pages so they can be served directly from your web server.
|
145
152
|
- Use sass and coffeescript.
|
146
153
|
- jquery 1.10.x loaded through a CDN.
|
data/lib/orats/cli.rb
CHANGED
@@ -1,21 +1,25 @@
|
|
1
1
|
require 'thor'
|
2
|
-
require 'orats/
|
2
|
+
require 'orats/commands/new/exec'
|
3
|
+
require 'orats/commands/outdated/exec'
|
4
|
+
require 'orats/commands/play'
|
5
|
+
require 'orats/commands/nuke'
|
3
6
|
|
4
7
|
module Orats
|
5
8
|
class CLI < Thor
|
6
|
-
option :pg_location, default: 'localhost'
|
7
|
-
option :pg_username, default: 'postgres'
|
8
|
-
option :pg_password, required: true
|
9
|
-
option :redis_location, default: 'localhost'
|
10
|
-
option :redis_password, default: ''
|
9
|
+
option :pg_location, default: 'localhost', aliases: '-l'
|
10
|
+
option :pg_username, default: 'postgres', aliases: '-u'
|
11
|
+
option :pg_password, required: true, aliases: '-p'
|
12
|
+
option :redis_location, default: 'localhost', aliases: '-n'
|
13
|
+
option :redis_password, default: '', aliases: '-d'
|
11
14
|
option :auth, type: :boolean, default: false, aliases: '-a'
|
15
|
+
option :template, default: '', aliases: '-m'
|
12
16
|
option :skip_extras, type: :boolean, default: false, aliases: '-E'
|
13
17
|
option :skip_foreman_start, type: :boolean, default: false, aliases: '-F'
|
14
|
-
option :sudo_password, default: ''
|
18
|
+
option :sudo_password, default: '', aliases: '-s'
|
15
19
|
option :skip_galaxy, type: :boolean, default: false, aliases: '-G'
|
16
|
-
desc 'new
|
20
|
+
desc 'new TARGET_PATH [options]', ''
|
17
21
|
long_desc <<-D
|
18
|
-
`orats new
|
22
|
+
`orats new target_path --pg-password supersecret` will create a new rails project and it will also create an ansible inventory to go with it by default.
|
19
23
|
|
20
24
|
You must supply at least this flag:
|
21
25
|
|
@@ -35,6 +39,8 @@ module Orats
|
|
35
39
|
|
36
40
|
`--auth` will include authentication and authorization [false]
|
37
41
|
|
42
|
+
`--template` will let you supply a custom template, a url or file is ok but urls must start with http or https []
|
43
|
+
|
38
44
|
Project features:
|
39
45
|
|
40
46
|
`--skip-extras` skip creating the services directory and ansible inventory/secrets [false]
|
@@ -47,33 +53,38 @@ module Orats
|
|
47
53
|
|
48
54
|
`--skip-galaxy` skip automatically installing roles from the galaxy [false]
|
49
55
|
D
|
50
|
-
def new(
|
51
|
-
|
56
|
+
def new(target_path)
|
57
|
+
Commands::New::Exec.new(target_path, options).init
|
52
58
|
end
|
53
59
|
|
54
|
-
|
60
|
+
option :template, default: '', aliases: '-m'
|
61
|
+
desc 'play PATH [options]', ''
|
55
62
|
long_desc <<-D
|
56
|
-
`orats play
|
63
|
+
`orats play target_path` will create an ansible playbook.
|
64
|
+
|
65
|
+
Template features:
|
66
|
+
|
67
|
+
`--template` will let you supply a custom template, a url or file is ok but urls must start with http or https []
|
57
68
|
D
|
58
|
-
def play(
|
59
|
-
|
69
|
+
def play(target_path)
|
70
|
+
Commands::Play.new(target_path, options).init
|
60
71
|
end
|
61
72
|
|
62
73
|
option :skip_data, type: :boolean, default: false, aliases: '-D'
|
63
|
-
desc 'nuke
|
74
|
+
desc 'nuke TARGET_PATH [options]', ''
|
64
75
|
long_desc <<-D
|
65
|
-
`orats nuke
|
76
|
+
`orats nuke target_path` will delete the directory and optionally all data associated to it.
|
66
77
|
|
67
78
|
Options:
|
68
79
|
|
69
80
|
`--skip-data` will skip deleting app specific postgres databases and redis namespaces [false]
|
70
81
|
D
|
71
|
-
def nuke(
|
72
|
-
|
82
|
+
def nuke(target_path)
|
83
|
+
Commands::Nuke.new(target_path, options).init
|
73
84
|
end
|
74
85
|
|
75
|
-
option :playbook, default: ''
|
76
|
-
option :inventory, default: ''
|
86
|
+
option :playbook, default: '', aliases: '-p'
|
87
|
+
option :inventory, default: '', aliases: '-i'
|
77
88
|
desc 'outdated [options]', ''
|
78
89
|
long_desc <<-D
|
79
90
|
`orats outdated` will run various comparisons on orats and your ansible files.
|
@@ -91,7 +102,7 @@ module Orats
|
|
91
102
|
`--inventory` to supply an inventory file for comparison []
|
92
103
|
D
|
93
104
|
def outdated
|
94
|
-
|
105
|
+
Commands::Outdated::Exec.new(nil, options).init
|
95
106
|
end
|
96
107
|
|
97
108
|
desc 'version', ''
|
@@ -99,7 +110,7 @@ module Orats
|
|
99
110
|
`orats version` will print the current version.
|
100
111
|
D
|
101
112
|
def version
|
102
|
-
|
113
|
+
puts "Orats version #{VERSION}"
|
103
114
|
end
|
104
115
|
map %w(-v --version) => :version
|
105
116
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'orats/commands/ui'
|
2
|
+
require 'orats/commands/outdated/parse'
|
3
|
+
|
4
|
+
module Orats
|
5
|
+
module Commands
|
6
|
+
class Common
|
7
|
+
include Thor::Base
|
8
|
+
include Thor::Shell
|
9
|
+
include Thor::Actions
|
10
|
+
include UI
|
11
|
+
include Outdated::Parse
|
12
|
+
|
13
|
+
RELATIVE_PATHS = {
|
14
|
+
galaxyfile: 'templates/includes/Galaxyfile',
|
15
|
+
hosts: 'templates/includes/inventory/hosts',
|
16
|
+
inventory: 'templates/includes/inventory/group_vars/all.yml',
|
17
|
+
playbook: 'templates/play.rb',
|
18
|
+
version: 'version.rb'
|
19
|
+
}
|
20
|
+
|
21
|
+
attr_accessor :remote_gem_version, :remote_paths, :local_paths
|
22
|
+
|
23
|
+
def initialize(target_path = '', options = {})
|
24
|
+
@target_path = target_path
|
25
|
+
@options = options
|
26
|
+
@active_path = @target_path
|
27
|
+
|
28
|
+
@local_paths = {}
|
29
|
+
@remote_paths = {}
|
30
|
+
|
31
|
+
build_common_paths
|
32
|
+
|
33
|
+
self.destination_root = Dir.pwd
|
34
|
+
@behavior = :invoke
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
def base_path
|
40
|
+
File.join(File.expand_path(File.dirname(__FILE__)), '..')
|
41
|
+
end
|
42
|
+
|
43
|
+
def repo_path
|
44
|
+
%w(https://raw.githubusercontent.com/nickjj/orats lib/orats)
|
45
|
+
end
|
46
|
+
|
47
|
+
def select_branch(branch, value)
|
48
|
+
"#{repo_path[0]}/#{branch}/#{repo_path[1]}/#{value}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_common_paths
|
52
|
+
@remote_paths[:version] = select_branch 'master', RELATIVE_PATHS[:version]
|
53
|
+
@remote_gem_version = gem_version
|
54
|
+
|
55
|
+
RELATIVE_PATHS.each_pair do |key, value|
|
56
|
+
@local_paths[key] = "#{base_path}/#{value}"
|
57
|
+
@remote_paths[key] = select_branch @remote_gem_version, value
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def url_to_string(url)
|
62
|
+
begin
|
63
|
+
open(url).read
|
64
|
+
rescue *[OpenURI::HTTPError, SocketError] => ex
|
65
|
+
log_error 'error', "Error accessing URL #{url}",
|
66
|
+
'message', ex
|
67
|
+
exit 1
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def file_to_string(path)
|
72
|
+
if File.exist?(path) && File.file?(path)
|
73
|
+
IO.read(path)
|
74
|
+
else
|
75
|
+
log_error 'error', 'Error finding file',
|
76
|
+
'message', path
|
77
|
+
exit 1
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
|
3
|
+
module Orats
|
4
|
+
module Commands
|
5
|
+
module New
|
6
|
+
module Ansible
|
7
|
+
def ansible_extras
|
8
|
+
create_inventory
|
9
|
+
|
10
|
+
secrets_path = "#{@target_path}/secrets"
|
11
|
+
create_secrets secrets_path
|
12
|
+
|
13
|
+
log_thor_task 'shell', 'Modifying secrets path in group_vars/all.yml'
|
14
|
+
gsub_file "#{@target_path}/#{fix_path_for_user(Commands::Common::RELATIVE_PATHS[:inventory])}",
|
15
|
+
'~/tmp/testproj/secrets/', File.expand_path(secrets_path)
|
16
|
+
|
17
|
+
log_thor_task 'shell', 'Modifying the place holder app name in group_vars/all.yml'
|
18
|
+
gsub_file "#{@target_path}/#{fix_path_for_user(Commands::Common::RELATIVE_PATHS[:inventory])}",
|
19
|
+
'testproj', File.basename(@target_path)
|
20
|
+
|
21
|
+
log_thor_task 'shell', 'Creating ssh keypair'
|
22
|
+
run "ssh-keygen -t rsa -P '' -f #{secrets_path}/id_rsa"
|
23
|
+
|
24
|
+
log_thor_task 'shell', 'Creating self signed ssl certificates'
|
25
|
+
run create_rsa_certificate(secrets_path, 'sslkey.key', 'sslcert.crt')
|
26
|
+
|
27
|
+
log_thor_task 'shell', 'Creating monit pem file'
|
28
|
+
run "#{create_rsa_certificate(secrets_path,
|
29
|
+
'monit.pem', 'monit.pem')} && openssl gendh 512 >> #{secrets_path}/monit.pem"
|
30
|
+
|
31
|
+
install_role_dependencies unless @options[:skip_galaxy]
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
|
36
|
+
def create_inventory
|
37
|
+
log_thor_task 'shell', 'Creating ansible inventory'
|
38
|
+
run "mkdir -p #{@target_path}/inventory/group_vars"
|
39
|
+
|
40
|
+
local_to_user Commands::Common::RELATIVE_PATHS[:hosts]
|
41
|
+
local_to_user Commands::Common::RELATIVE_PATHS[:inventory]
|
42
|
+
end
|
43
|
+
|
44
|
+
def local_to_user(file)
|
45
|
+
fixed_file = fix_path_for_user(file)
|
46
|
+
|
47
|
+
log_thor_task 'shell', "Creating #{fixed_file}"
|
48
|
+
run "cp #{base_path}/#{file} #{@target_path}/#{fixed_file}"
|
49
|
+
end
|
50
|
+
|
51
|
+
def create_secrets(secrets_path)
|
52
|
+
log_thor_task 'shell', 'Creating ansible secrets'
|
53
|
+
run "mkdir #{secrets_path}"
|
54
|
+
|
55
|
+
if @options[:redis_password].empty?
|
56
|
+
run "touch #{secrets_path}/redis_password"
|
57
|
+
else
|
58
|
+
save_secret_string "#{secrets_path}/redis_password"
|
59
|
+
gsub_file "#{@target_path}/#{fix_path_for_user(Commands::Common::RELATIVE_PATHS[:inventory])}",
|
60
|
+
'redis_password: false', 'redis_password: true'
|
61
|
+
end
|
62
|
+
|
63
|
+
save_secret_string "#{secrets_path}/postgres_password"
|
64
|
+
save_secret_string "#{secrets_path}/mail_password"
|
65
|
+
save_secret_string "#{secrets_path}/rails_token"
|
66
|
+
save_secret_string "#{secrets_path}/devise_token"
|
67
|
+
save_secret_string "#{secrets_path}/devise_pepper_token"
|
68
|
+
end
|
69
|
+
|
70
|
+
def save_secret_string(file)
|
71
|
+
File.open(file, 'w+') { |f| f.write(SecureRandom.hex(64)) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_rsa_certificate(secrets_path, keyout, out)
|
75
|
+
"openssl req -new -newkey rsa:2048 -days 365 -nodes -x509 -subj '/C=US/ST=Foo/L=Bar/O=Baz/CN=qux.com' -keyout #{secrets_path}/#{keyout} -out #{secrets_path}/#{out}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def install_role_dependencies
|
79
|
+
log_thor_task 'shell', 'Updating ansible roles from the galaxy'
|
80
|
+
|
81
|
+
galaxy_install =
|
82
|
+
"ansible-galaxy install -r #{base_path}/#{Commands::Common::RELATIVE_PATHS[:galaxyfile]} --force"
|
83
|
+
|
84
|
+
galaxy_out = run(galaxy_install, capture: true)
|
85
|
+
|
86
|
+
if galaxy_out.include?('you do not have permission')
|
87
|
+
if @options[:sudo_password].empty?
|
88
|
+
sudo_galaxy_command = 'sudo'
|
89
|
+
else
|
90
|
+
sudo_galaxy_command = "echo #{@options[:sudo_password]} | sudo -S"
|
91
|
+
end
|
92
|
+
|
93
|
+
run("#{sudo_galaxy_command} #{galaxy_install}")
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
private
|
98
|
+
|
99
|
+
def fix_path_for_user(file)
|
100
|
+
file.sub('templates/includes/', '')
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'orats/commands/common'
|
2
|
+
require 'orats/commands/new/ansible'
|
3
|
+
require 'orats/commands/new/rails'
|
4
|
+
require 'orats/commands/new/foreman'
|
5
|
+
|
6
|
+
module Orats
|
7
|
+
module Commands
|
8
|
+
module New
|
9
|
+
class Exec < Commands::Common
|
10
|
+
include Ansible
|
11
|
+
include Rails
|
12
|
+
include Foreman
|
13
|
+
|
14
|
+
def initialize(target_path = '', options = {})
|
15
|
+
super
|
16
|
+
|
17
|
+
@active_path = services_path
|
18
|
+
end
|
19
|
+
|
20
|
+
def init
|
21
|
+
rails_template 'base' do
|
22
|
+
gsub_postgres_info
|
23
|
+
gsub_redis_info unless @options[:redis_password].empty?
|
24
|
+
gsub_project_path
|
25
|
+
|
26
|
+
bundle_install
|
27
|
+
bundle_binstubs
|
28
|
+
spring_binstub
|
29
|
+
|
30
|
+
create_and_migrate_database
|
31
|
+
end
|
32
|
+
|
33
|
+
if @options[:auth]
|
34
|
+
rails_template 'auth', '--skip ' do
|
35
|
+
run_rake 'db:migrate db:seed'
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
ansible_extras unless @options[:skip_extras]
|
40
|
+
|
41
|
+
custom_rails_template unless @options[:template].empty?
|
42
|
+
|
43
|
+
foreman_start unless @options[:skip_foreman_start]
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def services_path
|
49
|
+
@options[:skip_extras] ? @target_path : "#{@target_path}/services/#{File.basename @target_path}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'socket'
|
2
|
+
require 'timeout'
|
3
|
+
|
4
|
+
module Orats
|
5
|
+
module Commands
|
6
|
+
module New
|
7
|
+
module Foreman
|
8
|
+
def foreman_start
|
9
|
+
@options[:skip_foreman_start] ? message = 'Start your' : message = 'Starting'
|
10
|
+
|
11
|
+
puts '', '='*80
|
12
|
+
log_status_top 'action', "#{message} server with the following commands", :cyan
|
13
|
+
log_status_bottom 'command', "cd #{@active_path}", :magenta, true
|
14
|
+
log_status_bottom 'command', 'bundle exec foreman start', :magenta
|
15
|
+
puts '='*80, ''
|
16
|
+
|
17
|
+
attempt_to_start
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def attempt_to_start
|
23
|
+
while port_taken? do
|
24
|
+
log_status_top 'error', "Another application is using port 3000\n", :red
|
25
|
+
|
26
|
+
exit 1 if no?('Would you like to try running the server again? (y/N)', :cyan)
|
27
|
+
end
|
28
|
+
|
29
|
+
puts
|
30
|
+
|
31
|
+
run_from @active_path, 'bundle exec foreman start'
|
32
|
+
end
|
33
|
+
|
34
|
+
def port_taken?
|
35
|
+
begin
|
36
|
+
Timeout::timeout(5) do
|
37
|
+
begin
|
38
|
+
s = TCPSocket.new('localhost', 3000)
|
39
|
+
s.close
|
40
|
+
|
41
|
+
return true
|
42
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
43
|
+
return false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
rescue Timeout::Error
|
47
|
+
false
|
48
|
+
end
|
49
|
+
|
50
|
+
false
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|