ext_backup 5.0.0.beta.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +19 -0
  3. data/README.md +33 -0
  4. data/bin/backup +5 -0
  5. data/bin/docker_test +24 -0
  6. data/lib/backup.rb +140 -0
  7. data/lib/backup/archive.rb +169 -0
  8. data/lib/backup/binder.rb +18 -0
  9. data/lib/backup/cleaner.rb +112 -0
  10. data/lib/backup/cli.rb +370 -0
  11. data/lib/backup/cloud_io/base.rb +38 -0
  12. data/lib/backup/cloud_io/cloud_files.rb +296 -0
  13. data/lib/backup/cloud_io/s3.rb +253 -0
  14. data/lib/backup/compressor/base.rb +32 -0
  15. data/lib/backup/compressor/bzip2.rb +35 -0
  16. data/lib/backup/compressor/custom.rb +49 -0
  17. data/lib/backup/compressor/gzip.rb +73 -0
  18. data/lib/backup/config.rb +128 -0
  19. data/lib/backup/config/dsl.rb +102 -0
  20. data/lib/backup/config/helpers.rb +137 -0
  21. data/lib/backup/database/base.rb +86 -0
  22. data/lib/backup/database/mongodb.rb +186 -0
  23. data/lib/backup/database/mysql.rb +191 -0
  24. data/lib/backup/database/openldap.rb +93 -0
  25. data/lib/backup/database/postgresql.rb +132 -0
  26. data/lib/backup/database/redis.rb +176 -0
  27. data/lib/backup/database/riak.rb +79 -0
  28. data/lib/backup/database/sqlite.rb +55 -0
  29. data/lib/backup/encryptor/base.rb +27 -0
  30. data/lib/backup/encryptor/gpg.rb +737 -0
  31. data/lib/backup/encryptor/open_ssl.rb +74 -0
  32. data/lib/backup/errors.rb +53 -0
  33. data/lib/backup/logger.rb +197 -0
  34. data/lib/backup/logger/console.rb +48 -0
  35. data/lib/backup/logger/fog_adapter.rb +25 -0
  36. data/lib/backup/logger/logfile.rb +131 -0
  37. data/lib/backup/logger/syslog.rb +114 -0
  38. data/lib/backup/model.rb +472 -0
  39. data/lib/backup/notifier/base.rb +126 -0
  40. data/lib/backup/notifier/campfire.rb +61 -0
  41. data/lib/backup/notifier/command.rb +99 -0
  42. data/lib/backup/notifier/datadog.rb +104 -0
  43. data/lib/backup/notifier/flowdock.rb +99 -0
  44. data/lib/backup/notifier/hipchat.rb +116 -0
  45. data/lib/backup/notifier/http_post.rb +114 -0
  46. data/lib/backup/notifier/mail.rb +232 -0
  47. data/lib/backup/notifier/nagios.rb +65 -0
  48. data/lib/backup/notifier/pagerduty.rb +79 -0
  49. data/lib/backup/notifier/prowl.rb +68 -0
  50. data/lib/backup/notifier/pushover.rb +71 -0
  51. data/lib/backup/notifier/ses.rb +123 -0
  52. data/lib/backup/notifier/slack.rb +147 -0
  53. data/lib/backup/notifier/twitter.rb +55 -0
  54. data/lib/backup/notifier/zabbix.rb +60 -0
  55. data/lib/backup/package.rb +51 -0
  56. data/lib/backup/packager.rb +106 -0
  57. data/lib/backup/pipeline.rb +120 -0
  58. data/lib/backup/splitter.rb +73 -0
  59. data/lib/backup/storage/base.rb +66 -0
  60. data/lib/backup/storage/cloud_files.rb +156 -0
  61. data/lib/backup/storage/cycler.rb +70 -0
  62. data/lib/backup/storage/dropbox.rb +206 -0
  63. data/lib/backup/storage/ftp.rb +116 -0
  64. data/lib/backup/storage/local.rb +61 -0
  65. data/lib/backup/storage/qiniu.rb +65 -0
  66. data/lib/backup/storage/rsync.rb +246 -0
  67. data/lib/backup/storage/s3.rb +155 -0
  68. data/lib/backup/storage/scp.rb +65 -0
  69. data/lib/backup/storage/sftp.rb +80 -0
  70. data/lib/backup/syncer/base.rb +67 -0
  71. data/lib/backup/syncer/cloud/base.rb +176 -0
  72. data/lib/backup/syncer/cloud/cloud_files.rb +81 -0
  73. data/lib/backup/syncer/cloud/local_file.rb +97 -0
  74. data/lib/backup/syncer/cloud/s3.rb +109 -0
  75. data/lib/backup/syncer/rsync/base.rb +50 -0
  76. data/lib/backup/syncer/rsync/local.rb +27 -0
  77. data/lib/backup/syncer/rsync/pull.rb +47 -0
  78. data/lib/backup/syncer/rsync/push.rb +201 -0
  79. data/lib/backup/template.rb +41 -0
  80. data/lib/backup/utilities.rb +233 -0
  81. data/lib/backup/version.rb +3 -0
  82. data/lib/ext_backup.rb +5 -0
  83. data/lib/ext_backup/version.rb +5 -0
  84. data/templates/cli/archive +28 -0
  85. data/templates/cli/compressor/bzip2 +4 -0
  86. data/templates/cli/compressor/custom +7 -0
  87. data/templates/cli/compressor/gzip +4 -0
  88. data/templates/cli/config +123 -0
  89. data/templates/cli/databases/mongodb +15 -0
  90. data/templates/cli/databases/mysql +18 -0
  91. data/templates/cli/databases/openldap +24 -0
  92. data/templates/cli/databases/postgresql +16 -0
  93. data/templates/cli/databases/redis +16 -0
  94. data/templates/cli/databases/riak +17 -0
  95. data/templates/cli/databases/sqlite +11 -0
  96. data/templates/cli/encryptor/gpg +27 -0
  97. data/templates/cli/encryptor/openssl +9 -0
  98. data/templates/cli/model +26 -0
  99. data/templates/cli/notifier/zabbix +15 -0
  100. data/templates/cli/notifiers/campfire +12 -0
  101. data/templates/cli/notifiers/command +32 -0
  102. data/templates/cli/notifiers/datadog +57 -0
  103. data/templates/cli/notifiers/flowdock +16 -0
  104. data/templates/cli/notifiers/hipchat +16 -0
  105. data/templates/cli/notifiers/http_post +32 -0
  106. data/templates/cli/notifiers/mail +24 -0
  107. data/templates/cli/notifiers/nagios +13 -0
  108. data/templates/cli/notifiers/pagerduty +12 -0
  109. data/templates/cli/notifiers/prowl +11 -0
  110. data/templates/cli/notifiers/pushover +11 -0
  111. data/templates/cli/notifiers/ses +15 -0
  112. data/templates/cli/notifiers/slack +22 -0
  113. data/templates/cli/notifiers/twitter +13 -0
  114. data/templates/cli/splitter +7 -0
  115. data/templates/cli/storages/cloud_files +11 -0
  116. data/templates/cli/storages/dropbox +20 -0
  117. data/templates/cli/storages/ftp +13 -0
  118. data/templates/cli/storages/local +8 -0
  119. data/templates/cli/storages/qiniu +12 -0
  120. data/templates/cli/storages/rsync +17 -0
  121. data/templates/cli/storages/s3 +16 -0
  122. data/templates/cli/storages/scp +15 -0
  123. data/templates/cli/storages/sftp +15 -0
  124. data/templates/cli/syncers/cloud_files +22 -0
  125. data/templates/cli/syncers/rsync_local +20 -0
  126. data/templates/cli/syncers/rsync_pull +28 -0
  127. data/templates/cli/syncers/rsync_push +28 -0
  128. data/templates/cli/syncers/s3 +27 -0
  129. data/templates/general/links +3 -0
  130. data/templates/general/version.erb +2 -0
  131. data/templates/notifier/mail/failure.erb +16 -0
  132. data/templates/notifier/mail/success.erb +16 -0
  133. data/templates/notifier/mail/warning.erb +16 -0
  134. data/templates/storage/dropbox/authorization_url.erb +6 -0
  135. data/templates/storage/dropbox/authorized.erb +4 -0
  136. data/templates/storage/dropbox/cache_file_written.erb +10 -0
  137. metadata +506 -0
@@ -0,0 +1,102 @@
1
+ module Backup
2
+ module Config
3
+ # Context for loading user config.rb and model files.
4
+ class DSL
5
+ class Error < Backup::Error; end
6
+ Model = Backup::Model
7
+
8
+ class << self
9
+ private
10
+
11
+ # List the available database, storage, syncer, compressor, encryptor
12
+ # and notifier constants. These are used to define constant names within
13
+ # Backup::Config::DSL so that users may use a constant instead of a string.
14
+ # Nested namespaces are represented using Hashs. Deep nesting supported.
15
+ #
16
+ # Example, instead of:
17
+ # database "MySQL" do |mysql|
18
+ # sync_with "RSync::Local" do |rsync|
19
+ #
20
+ # You can do:
21
+ # database MySQL do |mysql|
22
+ # sync_with RSync::Local do |rsync|
23
+ #
24
+ def add_dsl_constants
25
+ create_modules(
26
+ DSL,
27
+ [ # Databases
28
+ ["MySQL", "PostgreSQL", "MongoDB", "Redis", "Riak", "OpenLDAP", "SQLite"],
29
+ # Storages
30
+ ["S3", "CloudFiles", "Dropbox", "FTP",
31
+ "SFTP", "SCP", "RSync", "Local", "Qiniu"],
32
+ # Compressors
33
+ ["Gzip", "Bzip2", "Custom"],
34
+ # Encryptors
35
+ ["OpenSSL", "GPG"],
36
+ # Syncers
37
+ [
38
+ { "Cloud" => ["CloudFiles", "S3"] },
39
+ { "RSync" => ["Push", "Pull", "Local"] }
40
+ ],
41
+ # Notifiers
42
+ ["Mail", "Twitter", "Campfire", "Prowl",
43
+ "Hipchat", "PagerDuty", "Pushover", "HttpPost", "Nagios",
44
+ "Slack", "FlowDock", "Zabbix", "Ses", "DataDog", "Command"]
45
+ ]
46
+ )
47
+ end
48
+
49
+ def create_modules(scope, names)
50
+ names.flatten.each do |name|
51
+ if name.is_a?(Hash)
52
+ name.each do |key, val|
53
+ create_modules(get_or_create_empty_module(scope, key), [val])
54
+ end
55
+ else
56
+ get_or_create_empty_module(scope, name)
57
+ end
58
+ end
59
+ end
60
+
61
+ def get_or_create_empty_module(scope, const)
62
+ if scope.const_defined?(const)
63
+ scope.const_get(const)
64
+ else
65
+ scope.const_set(const, Module.new)
66
+ end
67
+ end
68
+ end
69
+
70
+ add_dsl_constants # add constants on load
71
+
72
+ attr_reader :_config_options
73
+
74
+ def initialize
75
+ @_config_options = {}
76
+ end
77
+
78
+ # Allow users to set command line path options in config.rb
79
+ [:root_path, :data_path, :tmp_path].each do |name|
80
+ define_method name do |path|
81
+ _config_options[name] = path
82
+ end
83
+ end
84
+
85
+ # Allows users to create preconfigured models.
86
+ def preconfigure(name, &block)
87
+ unless name.is_a?(String) && name =~ /^[A-Z]/
88
+ raise Error, "Preconfigured model names must be given as a string " \
89
+ "and start with a capital letter."
90
+ end
91
+
92
+ if DSL.const_defined?(name)
93
+ raise Error, "'#{name}' is already in use " \
94
+ "and can not be used for a preconfigured model."
95
+ end
96
+
97
+ DSL.const_set(name, Class.new(Model))
98
+ DSL.const_get(name).preconfigure(&block)
99
+ end
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,137 @@
1
+ require "ostruct"
2
+
3
+ module Backup
4
+ module Config
5
+ module Helpers
6
+ def self.included(klass)
7
+ klass.extend ClassMethods
8
+ end
9
+
10
+ module ClassMethods
11
+ def defaults
12
+ @defaults ||= Config::Defaults.new
13
+
14
+ if block_given?
15
+ yield @defaults
16
+ else
17
+ @defaults
18
+ end
19
+ end
20
+
21
+ # Used only within the specs
22
+ def clear_defaults!
23
+ defaults.reset!
24
+ end
25
+
26
+ def deprecations
27
+ @deprecations ||= {}
28
+ end
29
+
30
+ def log_deprecation_warning(name, deprecation)
31
+ msg = "#{self}##{name} has been deprecated as of " \
32
+ "backup v.#{deprecation[:version]}"
33
+ msg << "\n#{deprecation[:message]}" if deprecation[:message]
34
+ Logger.warn Config::Error.new(<<-EOS)
35
+ [DEPRECATION WARNING]
36
+ #{msg}
37
+ EOS
38
+ end
39
+
40
+ protected
41
+
42
+ ##
43
+ # Method to deprecate an attribute.
44
+ #
45
+ # :version
46
+ # Must be set to the backup version which will first
47
+ # introduce the deprecation.
48
+ #
49
+ # :action
50
+ # If set, this Proc will be called with a reference to the
51
+ # class instance and the value set on the deprecated accessor.
52
+ # e.g. deprecation[:action].call(klass, value)
53
+ # This should perform whatever action is neccessary, such as
54
+ # transferring the value to a new accessor.
55
+ #
56
+ # :message
57
+ # If set, this will be appended to #log_deprecation_warning
58
+ #
59
+ # Note that this replaces the `attr_accessor` method, or other
60
+ # method previously used to set the accessor being deprecated.
61
+ # #method_missing will handle any calls to `name=`.
62
+ #
63
+ def attr_deprecate(name, args = {})
64
+ deprecations[name] = {
65
+ version: nil,
66
+ message: nil,
67
+ action: nil
68
+ }.merge(args)
69
+ end
70
+ end # ClassMethods
71
+
72
+ private
73
+
74
+ ##
75
+ # Sets any pre-configured default values.
76
+ # If a default value was set for an invalid accessor,
77
+ # this will raise a NameError.
78
+ def load_defaults!
79
+ self.class.defaults._attributes.each do |name|
80
+ val = self.class.defaults.send(name)
81
+ val = val.dup rescue val
82
+ send(:"#{ name }=", val)
83
+ end
84
+ end
85
+
86
+ ##
87
+ # Check missing methods for deprecated attribute accessors.
88
+ #
89
+ # If a value is set on an accessor that has been deprecated
90
+ # using #attr_deprecate, a warning will be issued and any
91
+ # :action (Proc) specified will be called with a reference to
92
+ # the class instance and the value set on the deprecated accessor.
93
+ # See #attr_deprecate and #log_deprecation_warning
94
+ #
95
+ # Note that OpenStruct (used for setting defaults) does not allow
96
+ # multiple arguments when assigning values for members.
97
+ # So, we won't allow it here either, even though an attr_accessor
98
+ # will accept and convert them into an Array. Therefore, setting
99
+ # an option value using multiple values, whether as a default or
100
+ # directly on the class' accessor, should not be supported.
101
+ # i.e. if an option will accept being set as an Array, then it
102
+ # should be explicitly set as such. e.g. option = [val1, val2]
103
+ #
104
+ def method_missing(name, *args)
105
+ deprecation = nil
106
+ if method = name.to_s.chomp!("=")
107
+ if (len = args.count) != 1
108
+ raise ArgumentError,
109
+ "wrong number of arguments (#{len} for 1)", caller(1)
110
+ end
111
+ deprecation = self.class.deprecations[method.to_sym]
112
+ end
113
+
114
+ if deprecation
115
+ self.class.log_deprecation_warning(method, deprecation)
116
+ deprecation[:action].call(self, args[0]) if deprecation[:action]
117
+ else
118
+ super
119
+ end
120
+ end
121
+ end # Helpers
122
+
123
+ # Store for pre-configured defaults.
124
+ class Defaults < OpenStruct
125
+ # Returns an Array of all attribute method names
126
+ # that default values were set for.
127
+ def _attributes
128
+ @table.keys
129
+ end
130
+
131
+ # Used only within the specs
132
+ def reset!
133
+ @table.clear
134
+ end
135
+ end
136
+ end
137
+ end
@@ -0,0 +1,86 @@
1
+ module Backup
2
+ module Database
3
+ class Error < Backup::Error; end
4
+
5
+ class Base
6
+ include Utilities::Helpers
7
+ include Config::Helpers
8
+
9
+ attr_reader :model, :database_id, :dump_path
10
+
11
+ ##
12
+ # If given, +database_id+ will be appended to the #dump_filename.
13
+ # This is required if multiple Databases of the same class are added to
14
+ # the model.
15
+ def initialize(model, database_id = nil)
16
+ @model = model
17
+ @database_id = database_id.to_s.gsub(/\W/, "_") if database_id
18
+ @dump_path = File.join(Config.tmp_path, model.trigger, "databases")
19
+ load_defaults!
20
+ end
21
+
22
+ def perform!
23
+ log!(:started)
24
+ prepare!
25
+ end
26
+
27
+ private
28
+
29
+ def prepare!
30
+ FileUtils.mkdir_p(dump_path)
31
+ end
32
+
33
+ ##
34
+ # Sets the base filename for the final dump file to be saved in +dump_path+,
35
+ # based on the class name. e.g. databases/MySQL.sql
36
+ #
37
+ # +database_id+ will be appended if it is defined.
38
+ # e.g. databases/MySQL-database_id.sql
39
+ #
40
+ # If multiple Databases of the same class are defined and no +database_id+
41
+ # is defined, the user will be warned and one will be auto-generated.
42
+ #
43
+ # Model#initialize calls this method *after* all defined databases have
44
+ # been initialized so `backup check` can report these warnings.
45
+ def dump_filename
46
+ @dump_filename ||=
47
+ begin
48
+ unless database_id
49
+ if model.databases.select { |d| d.class == self.class }.count > 1
50
+ sleep 1
51
+ @database_id = Time.now.to_i.to_s[-5, 5]
52
+ Logger.warn Error.new(<<-EOS)
53
+ Database Identifier Missing
54
+ When multiple Databases are configured in a single Backup Model
55
+ that have the same class (MySQL, PostgreSQL, etc.), the optional
56
+ +database_id+ must be specified to uniquely identify each instance.
57
+ e.g. database MySQL, :database_id do |db|
58
+ This will result in an output file in your final backup package like:
59
+ databases/MySQL-database_id.sql
60
+
61
+ Backup has auto-generated an identifier (#{database_id}) for this
62
+ database dump and will now continue.
63
+ EOS
64
+ end
65
+ end
66
+
67
+ self.class.name.split("::").last + (database_id ? "-#{database_id}" : "")
68
+ end
69
+ end
70
+
71
+ def database_name
72
+ @database_name ||= self.class.to_s.sub("Backup::", "") +
73
+ (database_id ? " (#{database_id})" : "")
74
+ end
75
+
76
+ def log!(action)
77
+ msg =
78
+ case action
79
+ when :started then "Started..."
80
+ when :finished then "Finished!"
81
+ end
82
+ Logger.info "#{database_name} #{msg}"
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,186 @@
1
+ module Backup
2
+ module Database
3
+ class MongoDB < Base
4
+ class Error < Backup::Error; end
5
+
6
+ ##
7
+ # Name of the database that needs to get dumped
8
+ attr_accessor :name
9
+
10
+ ##
11
+ # Credentials for the specified database
12
+ attr_accessor :username, :password, :authdb
13
+
14
+ ##
15
+ # Connectivity options
16
+ attr_accessor :host, :port
17
+
18
+ ##
19
+ # IPv6 support (disabled by default)
20
+ attr_accessor :ipv6
21
+
22
+ ##
23
+ # Collections to dump, collections that aren't specified won't get dumped
24
+ attr_accessor :only_collections
25
+
26
+ ##
27
+ # Additional "mongodump" options
28
+ attr_accessor :additional_options
29
+
30
+ ##
31
+ # Forces mongod to flush all pending write operations to the disk and
32
+ # locks the entire mongod instance to prevent additional writes until the
33
+ # dump is complete.
34
+ #
35
+ # Note that if Profiling is enabled, this will disable it and will not
36
+ # re-enable it after the dump is complete.
37
+ attr_accessor :lock
38
+
39
+ ##
40
+ # Creates a dump of the database that includes an oplog, to create a
41
+ # point-in-time snapshot of the state of a mongod instance.
42
+ #
43
+ # If this option is used, you would not use the `lock` option.
44
+ #
45
+ # This will only work against nodes that maintain a oplog.
46
+ # This includes all members of a replica set, as well as master nodes in
47
+ # master/slave replication deployments.
48
+ attr_accessor :oplog
49
+
50
+ def initialize(model, database_id = nil, &block)
51
+ super
52
+ instance_eval(&block) if block_given?
53
+ end
54
+
55
+ def perform!
56
+ super
57
+
58
+ lock_database if @lock
59
+ dump!
60
+ package!
61
+ ensure
62
+ unlock_database if @lock
63
+ end
64
+
65
+ private
66
+
67
+ ##
68
+ # Performs all required mongodump commands, dumping the output files
69
+ # into the +dump_packaging_path+ directory for packaging.
70
+ def dump!
71
+ FileUtils.mkdir_p dump_packaging_path
72
+
73
+ collections = Array(only_collections)
74
+ if collections.empty?
75
+ run(mongodump)
76
+ else
77
+ collections.each do |collection|
78
+ run("#{mongodump} --collection='#{collection}'")
79
+ end
80
+ end
81
+ end
82
+
83
+ ##
84
+ # Creates a tar archive of the +dump_packaging_path+ directory
85
+ # and stores it in the +dump_path+ using +dump_filename+.
86
+ #
87
+ # <trigger>/databases/MongoDB[-<database_id>].tar[.gz]
88
+ #
89
+ # If successful, +dump_packaging_path+ is removed.
90
+ def package!
91
+ pipeline = Pipeline.new
92
+ dump_ext = "tar"
93
+
94
+ pipeline << "#{utility(:tar)} -cf - " \
95
+ "-C '#{dump_path}' '#{dump_filename}'"
96
+
97
+ if model.compressor
98
+ model.compressor.compress_with do |command, ext|
99
+ pipeline << command
100
+ dump_ext << ext
101
+ end
102
+ end
103
+
104
+ pipeline << "#{utility(:cat)} > " \
105
+ "'#{File.join(dump_path, dump_filename)}.#{dump_ext}'"
106
+
107
+ pipeline.run
108
+ if pipeline.success?
109
+ FileUtils.rm_rf dump_packaging_path
110
+ log!(:finished)
111
+ else
112
+ raise Error, "Dump Failed!\n#{pipeline.error_messages}"
113
+ end
114
+ end
115
+
116
+ def dump_packaging_path
117
+ File.join(dump_path, dump_filename)
118
+ end
119
+
120
+ def mongodump
121
+ "#{utility(:mongodump)} #{name_option} #{credential_options} " \
122
+ "#{connectivity_options} #{ipv6_option} #{oplog_option} " \
123
+ "#{user_options} --out='#{dump_packaging_path}'"
124
+ end
125
+
126
+ def name_option
127
+ return unless name
128
+ "--db='#{name}'"
129
+ end
130
+
131
+ def credential_options
132
+ opts = []
133
+ opts << "--username='#{username}'" if username
134
+ opts << "--password='#{password}'" if password
135
+ opts << "--authenticationDatabase='#{authdb}'" if authdb
136
+ opts.join(" ")
137
+ end
138
+
139
+ def connectivity_options
140
+ opts = []
141
+ opts << "--host='#{host}'" if host
142
+ opts << "--port='#{port}'" if port
143
+ opts.join(" ")
144
+ end
145
+
146
+ def ipv6_option
147
+ "--ipv6" if ipv6
148
+ end
149
+
150
+ def oplog_option
151
+ "--oplog" if oplog
152
+ end
153
+
154
+ def user_options
155
+ Array(additional_options).join(" ")
156
+ end
157
+
158
+ def lock_database
159
+ lock_command = <<-EOS.gsub(/^ +/, "")
160
+ echo 'use admin
161
+ db.setProfilingLevel(0)
162
+ db.fsyncLock()' | #{mongo_shell}
163
+ EOS
164
+
165
+ run(lock_command)
166
+ end
167
+
168
+ def unlock_database
169
+ unlock_command = <<-EOS.gsub(/^ +/, "")
170
+ echo 'use admin
171
+ db.fsyncUnlock()' | #{mongo_shell}
172
+ EOS
173
+
174
+ run(unlock_command)
175
+ end
176
+
177
+ def mongo_shell
178
+ cmd = "#{utility(:mongo)} #{connectivity_options}".rstrip
179
+ cmd << " #{credential_options}".rstrip
180
+ cmd << " #{ipv6_option}".rstrip
181
+ cmd << " '#{name}'" if name
182
+ cmd
183
+ end
184
+ end
185
+ end
186
+ end