CloudyScripts 0.0.11 → 0.0.12

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.
@@ -1,206 +1,148 @@
1
- require "help/script_execution_state"
2
- require "scripts/ec2/ec2_script"
3
- require "help/remote_command_handler"
4
- require "help/dm_crypt_helper"
5
- require "AWS"
6
-
7
- # Script to Encrypt an EC2 Storage (aka Elastic Block Storage)
8
- #
9
- class DmEncrypt < Ec2Script
10
- # dependencies: tools that need to be installed to make things work
11
- TOOLS = ["cryptsetup"]
12
- # the parameters for which
13
- CHECK = ["cryptsetup"]
14
-
15
- # Input parameters
16
- # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
17
- # * aws_secret_key => the Amazon AWS Secret Key
18
- # * ip_address => IP Address of the machine to connect to
19
- # * ssh_key_file => Path of the keyfile used to connect to the machine (optional, otherwise: ssh_key_data)
20
- # * ssh_key_data => Key information (optional, otherwise: ssh_key_file)
21
- # * device => Path of the device to encrypt
22
- # * device_name => Name of the Device to encrypt
23
- # * storage_path => Path on which the encrypted device is mounted
24
- # * paraphrase => paraphrase used for encryption
25
- # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
26
- # * ec2_api_handler => object that allows to access the EC2 API (optional)
27
- # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
28
- #
29
-
30
- def initialize(input_params)
31
- super(input_params)
32
- end
33
-
34
- # Executes the script.
35
- def start_script
36
- begin
37
- # optional parameters and initialization
38
- if @input_params[:ec2_api_server] == nil
39
- @input_params[:ec2_api_server] = "us-east-1.ec2.amazonaws.com"
40
- end
41
- if @input_params[:remote_command_handler] == nil
42
- @input_params[:remote_command_handler] = RemoteCommandHandler.new
43
- end
44
- if @input_params[:ec2_api_handler] == nil
45
- @input_params[:ec2_api_handler] = AWS::EC2::Base.new(:access_key_id => @input_params[:aws_access_key],
46
- :secret_access_key => @input_params[:aws_secret_key], :server => @input_params[:ec2_api_server])
47
- end
48
- @input_params[:script] = self
49
- # start state machine
50
- current_state = DmEncryptState.load_state(@input_params)
51
- @state_change_listeners.each() {|listener|
52
- current_state.register_state_change_listener(listener)
53
- }
54
- end_state = current_state.start_state_machine()
55
- if end_state.failed?
56
- @result[:failed] = true
57
- @result[:failure_reason] = current_state.end_state.failure_reason
58
- @result[:end_state] = current_state.end_state
59
- else
60
- @result[:failed] = false
61
- end
62
- rescue Exception => e
63
- @logger.warn "exception during encryption: #{e}"
64
- @logger.info e.backtrace.join("\n")
65
- err = e.to_s
66
- err += " (in #{current_state.end_state.to_s})" unless current_state == nil
67
- @result[:failed] = true
68
- @result[:failure_reason] = err
69
- @result[:end_state] = current_state.end_state unless current_state == nil
70
- ensure
71
- begin
72
- @input_params[:remote_command_handler].disconnect
73
- rescue Exception => e2
74
- end
75
- end
76
- #
77
- @result[:done] = true
78
- end
79
-
80
- # Returns a hash with the following information:
81
- # :done => if execution is done
82
- #
83
- def get_execution_result
84
- @result
85
- end
86
-
87
- private
88
-
89
- # Here begins the state machine implementation
90
- class DmEncryptState < ScriptExecutionState
91
-
92
- def self.load_state(context)
93
- InitialState.new(context)
94
- end
95
- end
96
-
97
- # Starting state. Tries to connect via ssh.
98
- class InitialState < DmEncryptState
99
- def enter
100
- connect()
101
- end
102
-
103
- private
104
-
105
- def connect()
106
- @context[:script].post_message("going to connect to #{@context[:ip_address]}...")
107
- @logger.debug "InitialState.connect"
108
- if @context[:ssh_key_file] != nil
109
- @context[:remote_command_handler].connect_with_keyfile(@context[:ip_address], @context[:ssh_key_file])
110
- elsif @context[:ssh_key_data] != nil
111
- @context[:remote_command_handler].connect(@context[:ip_address], "root", @context[:ssh_key_data])
112
- else
113
- raise Exception.new("no key information specified")
114
- end
115
- @context[:result][:os] = @context[:remote_command_handler].retrieve_os()
116
- @context[:script].post_message("connection successful, OS = #{@context[:result][:os]}")
117
- ConnectedState.new(@context)
118
- end
119
- end
120
-
121
- # Connected via SSH. Tries to install dm-encrypt.#TODO: depends on OS
122
- class ConnectedState < DmEncryptState
123
- def enter
124
- install_tools()
125
- end
126
-
127
- private
128
- def install_tools
129
- @context[:script].post_message("check if the system has the cryptset-package installed")
130
- @logger.debug "ConnectedState.install_tools"
131
- if !tools_installed?
132
- @context[:script].post_message("cryptset-package not installed. Going to install it...")
133
- TOOLS.each() {|tool|
134
- @context[:remote_command_handler].install(tool)
135
- }
136
- end
137
- if !@context[:remote_command_handler].remote_execute("modprobe dm_crypt")
138
- raise Exception.new("dm-crypt module missing")
139
- end
140
- if tools_installed?
141
- @context[:script].post_message("cryptset-package is available")
142
- @logger.debug "system says that tools are installed"
143
- ToolInstalledState.new(@context)
144
- else
145
- FailedState.new(@context, "Installation of Tools failed", ConnectedState.new(@context))
146
- end
147
- end
148
-
149
- def tools_installed?
150
- CHECK.each() {|tool|
151
- if !@context[:remote_command_handler].tools_installed?(tool)
152
- return false
153
- end
154
- }
155
- true
156
- end
157
- end
158
-
159
- # Connected and Tools installed. Start encryption.
160
- class ToolInstalledState < DmEncryptState
161
- def enter
162
- create_encrypted_volume()
163
- end
164
-
165
- private
166
- def create_encrypted_volume
167
- @context[:script].post_message("going to encrypt device #{@context[:device]} "+
168
- "named '#{@context[:device_name]}' and mount it as #{@context[:storage_path]}...")
169
- @logger.debug "ToolInstalledState.create_encrypted_volume"
170
- @context[:remote_command_handler].encrypt_storage(@context[:device_name],
171
- @context[:paraphrase], @context[:device], @context[:storage_path])
172
- @context[:script].post_message("device #{@context[:device]} is encrypted and mounted")
173
- MountedAndActivatedState.new(@context)
174
- end
175
-
176
- def calc_device_name
177
- dev = @context[:device_name].gsub(/[-]/,"--")
178
- "/dev/mapper/vg--#{dev}-lv--#{dev}"
179
- end
180
-
181
- end
182
-
183
- # The encrypted storages is mounted and activated. Cleanup and done.
184
- class MountedAndActivatedState < DmEncryptState
185
- def enter
186
- cleanup()
187
- end
188
-
189
- private
190
- def cleanup()
191
- @context[:script].post_message("disconnecting...")
192
- @logger.debug "MountedAndActivatedState.cleanup"
193
- @context[:remote_command_handler].disconnect()
194
- @context[:script].post_message("done")
195
- DoneState.new(@context)
196
- end
197
-
198
- end
199
-
200
- class DoneState < DmEncryptState
201
- def done?
202
- true
203
- end
204
- end
205
-
1
+ require "help/script_execution_state"
2
+ require "scripts/ec2/ec2_script"
3
+ require "help/remote_command_handler"
4
+ require "help/dm_crypt_helper"
5
+ require "AWS"
6
+
7
+ # Script to Encrypt an EC2 Storage (aka Elastic Block Storage)
8
+ #
9
+ class DmEncrypt < Ec2Script
10
+ # dependencies: tools that need to be installed to make things work
11
+ TOOLS = ["cryptsetup"]
12
+ # the parameters for which
13
+ CHECK = ["cryptsetup"]
14
+
15
+ # Input parameters
16
+ # * aws_access_key => the Amazon AWS Access Key (see Your Account -> Security Credentials)
17
+ # * aws_secret_key => the Amazon AWS Secret Key
18
+ # * ip_address => IP Address of the machine to connect to
19
+ # * ssh_key_file => Path of the keyfile used to connect to the machine (optional, otherwise: ssh_key_data)
20
+ # * ssh_key_data => Key information (optional, otherwise: ssh_key_file)
21
+ # * device => Path of the device to encrypt
22
+ # * device_name => Name of the Device to encrypt
23
+ # * storage_path => Path on which the encrypted device is mounted
24
+ # * paraphrase => paraphrase used for encryption
25
+ # * remote_command_handler => object that allows to connect via ssh and execute commands (optional)
26
+ # * ec2_api_handler => object that allows to access the EC2 API (optional)
27
+ # * ec2_api_server => server to connect to (option, default is us-east-1.ec2.amazonaws.com)
28
+ #
29
+
30
+ def initialize(input_params)
31
+ super(input_params)
32
+ end
33
+
34
+ def check_input_parameters()
35
+ if @input_params[:ec2_api_server] == nil
36
+ @input_params[:ec2_api_server] = "us-east-1.ec2.amazonaws.com"
37
+ end
38
+ if @input_params[:remote_command_handler] == nil
39
+ @input_params[:remote_command_handler] = RemoteCommandHandler.new
40
+ end
41
+ if @input_params[:ec2_api_handler] == nil
42
+ @input_params[:ec2_api_handler] = AWS::EC2::Base.new(:access_key_id => @input_params[:aws_access_key],
43
+ :secret_access_key => @input_params[:aws_secret_key], :server => @input_params[:ec2_api_server])
44
+ end
45
+ end
46
+
47
+ def load_initial_state()
48
+ DmEncryptState.load_state(@input_params)
49
+ end
50
+
51
+ private
52
+
53
+ # Here begins the state machine implementation
54
+ class DmEncryptState < ScriptExecutionState
55
+
56
+ def self.load_state(context)
57
+ InitialState.new(context)
58
+ end
59
+ end
60
+
61
+ # Starting state. Tries to connect via ssh.
62
+ class InitialState < DmEncryptState
63
+ def enter
64
+ connect()
65
+ install_tools()
66
+ end
67
+
68
+ private
69
+
70
+ def install_tools
71
+ @context[:script].post_message("check if the system has the cryptset-package installed")
72
+ @logger.debug "ConnectedState.install_tools"
73
+ if !tools_installed?
74
+ @context[:script].post_message("cryptset-package not installed. Going to install it...")
75
+ TOOLS.each() {|tool|
76
+ @context[:remote_command_handler].install(tool)
77
+ }
78
+ end
79
+ if !@context[:remote_command_handler].remote_execute("modprobe dm_crypt")
80
+ raise Exception.new("dm-crypt module missing")
81
+ end
82
+ if tools_installed?
83
+ @context[:script].post_message("cryptset-package is available")
84
+ @logger.debug "system says that tools are installed"
85
+ ToolInstalledState.new(@context)
86
+ else
87
+ FailedState.new(@context, "Installation of Tools failed", ConnectedState.new(@context))
88
+ end
89
+ end
90
+
91
+ def tools_installed?
92
+ CHECK.each() {|tool|
93
+ if !@context[:remote_command_handler].tools_installed?(tool)
94
+ return false
95
+ end
96
+ }
97
+ true
98
+ end
99
+ end
100
+
101
+ # Connected and Tools installed. Start encryption.
102
+ class ToolInstalledState < DmEncryptState
103
+ def enter
104
+ create_encrypted_volume()
105
+ end
106
+
107
+ private
108
+ def create_encrypted_volume
109
+ @context[:script].post_message("going to encrypt device #{@context[:device]} "+
110
+ "named '#{@context[:device_name]}' and mount it as #{@context[:storage_path]}...")
111
+ @logger.debug "ToolInstalledState.create_encrypted_volume"
112
+ @context[:remote_command_handler].encrypt_storage(@context[:device_name],
113
+ @context[:paraphrase], @context[:device], @context[:storage_path])
114
+ @context[:script].post_message("device #{@context[:device]} is encrypted and mounted")
115
+ MountedAndActivatedState.new(@context)
116
+ end
117
+
118
+ def calc_device_name
119
+ dev = @context[:device_name].gsub(/[-]/,"--")
120
+ "/dev/mapper/vg--#{dev}-lv--#{dev}"
121
+ end
122
+
123
+ end
124
+
125
+ # The encrypted storages is mounted and activated. Cleanup and done.
126
+ class MountedAndActivatedState < DmEncryptState
127
+ def enter
128
+ cleanup()
129
+ end
130
+
131
+ private
132
+ def cleanup()
133
+ @context[:script].post_message("disconnecting...")
134
+ @logger.debug "MountedAndActivatedState.cleanup"
135
+ @context[:remote_command_handler].disconnect()
136
+ @context[:script].post_message("done")
137
+ DoneState.new(@context)
138
+ end
139
+
140
+ end
141
+
142
+ class DoneState < DmEncryptState
143
+ def done?
144
+ true
145
+ end
146
+ end
147
+
206
148
  end
@@ -0,0 +1,153 @@
1
+ require "help/script_execution_state"
2
+ require "scripts/ec2/ec2_script"
3
+ require "help/remote_command_handler"
4
+ require "help/dm_crypt_helper"
5
+ require "AWS"
6
+
7
+ # Script to download a specific snapshot as ZIP
8
+ # * create a specific instance (with Apache Server),
9
+ # * create a volume based on the snapshot
10
+ # * attach the volume
11
+ # * create a XSF-file-system
12
+ # * freeze the file-system
13
+ # * zip the file-system and copy it to the apache folder
14
+ # * wait 5 minutes (now the zip-file can be downloaded)
15
+ # * alternatively: copy it to S3 and make it downloadable
16
+ # * alternatively: copy it to an FTP server
17
+ #
18
+ class DownloadSnapshot < Ec2Script
19
+ # context information needed
20
+ # * the EC2 credentials (see #Ec2Script)
21
+ # * ami_id: the ID of the AMI to be started to perform the operations and to run the web-server for download
22
+ # * security_group_name => name of the security group used to start the AMI (should open ports for SSH and HTTP)
23
+ # * ssh_key_data => Key information for the security group that starts the AMI [if not set, use ssh_key_files]
24
+ # * ssh_key_files => Key information for the security group that starts the AMI
25
+ # * snapshot_id => The ID of the snapshot to be downloaded
26
+ # * wait_time (optional, default = 300) => time in sec during which the zipped snapshot is downloadable
27
+ # * zip_file_dest (optional, default = '/var/www/html') => path of directory where the zipped volume is copied to
28
+ # * zip_file_name (option, default = 'download') => name of the zip-file to download
29
+ def initialize(input_params)
30
+ super(input_params)
31
+ end
32
+
33
+ def check_input_parameters()
34
+ if @input_params[:temp_device_name] == nil
35
+ @input_params[:temp_device_name] = "/dev/sdj"
36
+ end
37
+ if @input_params[:zip_file_dest] == nil
38
+ @input_params[:zip_file_dest] = "/var/www/html/"
39
+ end
40
+ if @input_params[:zip_file_name] == nil
41
+ @input_params[:zip_file_name] = "download"
42
+ end
43
+ if @input_params[:wait_time] == nil
44
+ @input_params[:wait_time] = 300
45
+ end
46
+ end
47
+
48
+ # Load the initial state for the script.
49
+ # Abstract method to be implemented by extending classes.
50
+ def load_initial_state()
51
+ DownloadSnapshotState.load_state(@input_params)
52
+ end
53
+
54
+ private
55
+
56
+ # Here begins the state machine implementation
57
+ class DownloadSnapshotState < ScriptExecutionState
58
+
59
+ def self.load_state(context)
60
+ InitialState.new(context)
61
+ end
62
+ end
63
+
64
+ #Connected.
65
+ # Start state. First thing to do is to launch the instance.
66
+ class InitialState < DownloadSnapshotState
67
+ def enter
68
+ launch_instance()
69
+ InstanceLaunchedState.new(context)
70
+ end
71
+ end
72
+
73
+ # Instance Launched. Create a volume based on the snapshot.
74
+ class InstanceLaunchedState < DownloadSnapshotState
75
+ def enter
76
+ create_volume_from_snapshot()
77
+ VolumeCreated.new(@context)
78
+ end
79
+
80
+ end
81
+
82
+ # Volume created. Attach it.
83
+ class VolumeCreated < DownloadSnapshotState
84
+ def enter
85
+ attach_volume()
86
+ VolumeAttached.new(@context)
87
+ end
88
+ end
89
+
90
+ # Volume attached. Create a file-system and mount it.
91
+ class VolumeAttached < DownloadSnapshotState
92
+ def enter
93
+ connect()
94
+ create_fs()
95
+ FileSystemCreated.new(@context)
96
+ end
97
+ end
98
+
99
+ # File system created. Mount it.
100
+ class FileSystemCreated < DownloadSnapshotState
101
+ def enter
102
+ mount_fs()
103
+ FileSystemMounted.new(@context)
104
+ end
105
+
106
+ end
107
+
108
+ # File System mounted. Zip the complete directory on the EBS.
109
+ class FileSystemMounted < DownloadSnapshotState
110
+ def enter
111
+ zip_volume()
112
+ VolumeZippedAndDownloadableState.new(@context)
113
+ end
114
+
115
+ end
116
+
117
+ # Volume is zipped and downloadable. Wait 5 minutes.
118
+ class VolumeZippedAndDownloadableState < DownloadSnapshotState
119
+ def enter
120
+ wait_some_time()
121
+ end
122
+
123
+ def get_link
124
+ "http://#{@context[:dns_name]}/#{@context[:zip_file_name]}.zip"
125
+ end
126
+
127
+ private
128
+
129
+ def wait_some_time
130
+ @context[:script].post_message("The snapshot can be downloaded during #{@context[:wait_time]} seconds from link: #{get_link()}")
131
+ sleep(@context[:wait_time])
132
+ DownloadStoppedState.new(@context)
133
+ end
134
+ end
135
+
136
+ # Snapshot can no longer be downloaded. Shut down the instance.
137
+ class DownloadStoppedState < DownloadSnapshotState
138
+ def enter
139
+ shut_down_instance()
140
+ InstanceShutDown.new(@context)
141
+ end
142
+
143
+ end
144
+
145
+ # Instance is shut down. Delete the volume created.
146
+ class InstanceShutDown < DownloadSnapshotState
147
+ def enter
148
+ delete_volume()
149
+ Done.new(@context)
150
+ end
151
+ end
152
+
153
+ end