aws_minecraft 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,23 @@
1
+ require_relative 'mine_config'
2
+ require 'net/scp'
3
+
4
+ module AWSMine
5
+ # Main wrapper for Uploading files and the world
6
+ class UploadHelper
7
+ def initialize
8
+ @config = MineConfig.new
9
+ @logger = Logger.new(STDOUT)
10
+ @logger.level = Logger.const_get(@config.loglevel)
11
+ end
12
+
13
+ def upload_files(ip)
14
+ Net::SCP.start(ip, 'ec2-user') do |scp|
15
+ scp.upload!(@config.upload_path,
16
+ '/home/ec2-user/data',
17
+ recursive: true) do |_, name, sent, total|
18
+ @logger.info("#{name}: #{sent}/#{total}")
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,5 @@
1
+ module AWSMine
2
+ class AWSMine
3
+ VERSION = '0.1.0'.freeze
4
+ end
5
+ end
@@ -0,0 +1,98 @@
1
+ require 'aws_minecraft/aws_helper'
2
+ require 'fakefs/spec_helpers'
3
+ require 'spec_helper'
4
+ require 'aws-sdk'
5
+
6
+ describe AWSMine::AWSHelper do
7
+ include_context 'with aws minecraft'
8
+ let(:ec2_client) { instance_double(Aws::EC2::Client) }
9
+ let(:ec2_resource) { instance_double(Aws::EC2::Resource) }
10
+ let(:sg) { instance_double(Aws::EC2::SecurityGroup) }
11
+ let(:ec2) { instance_double(Aws::EC2::Instance) }
12
+ let(:ec2s) { instance_double(Aws::EC2::Instances) }
13
+ let(:client) { instance_double(Aws::Client) }
14
+ let(:state) { instance_double(Aws::EC2::Types::InstanceState) }
15
+
16
+ subject do |s|
17
+ s = described_class.new
18
+ s.ec2_client = ec2_client
19
+ s.ec2_resource = ec2_resource
20
+ s
21
+ end
22
+
23
+ describe '#initialize' do
24
+ it 'should be an instance of MineConfig' do
25
+ expect(subject).instance_of? AWSMine::AWSHelper
26
+ end
27
+ end
28
+
29
+ describe '#create_ec2' do
30
+ it 'should create an ec2 instance' do
31
+ expect(ec2_client).to receive(:describe_key_pairs).with(key_names: ['minecraft_keys'])
32
+ expect(ec2_resource).to receive(:create_security_group).with(dry_run: false,
33
+ group_name: 'mine_group',
34
+ description: 'minecraft_group')
35
+ .and_return(sg)
36
+ expect(sg).to receive(:authorize_ingress)
37
+ expect(sg).to receive(:id).and_return('sg-1')
38
+ expect(ec2_resource).to receive(:create_instances)
39
+ .with(dry_run: false,
40
+ image_id: 'ami-ea26ce85',
41
+ key_name: 'minecraft_keys',
42
+ min_count: 1,
43
+ max_count: 1,
44
+ instance_type: 't2.nano',
45
+ monitoring: { enabled: true },
46
+ security_group_ids: ['sg-1'],
47
+ user_data: "ICAgICAgICAgICEjL2Jpbi9iYXNo\n")
48
+ .and_return([ec2])
49
+ expect(ec2_resource).to receive(:client).and_return(client)
50
+ expect(ec2).to receive(:id).exactly(4).times.and_return('ec2-id')
51
+ expect(client).to receive(:wait_until).with(:instance_status_ok, instance_ids: ['ec2-id'])
52
+ expect(ec2_resource).to receive(:instances).with(instance_ids: ['ec2-id']).and_return([ec2])
53
+ expect(ec2).to receive(:public_ip_address).twice.and_return('1.2.3.4')
54
+ expect(subject.create_ec2).to eq(['1.2.3.4', 'ec2-id'])
55
+ end
56
+ end
57
+
58
+ describe '#terminate_ec2' do
59
+ it 'should terminate an ec2 instance' do
60
+ expect(ec2_client).to receive(:terminate_instances).with(dry_run: false,
61
+ instance_ids: ['ec2-id'])
62
+ expect(ec2_resource).to receive(:client).and_return(client)
63
+ expect(client).to receive(:wait_until).with(:instance_terminated, instance_ids: ['ec2-id'])
64
+ subject.terminate_ec2('ec2-id')
65
+ end
66
+ end
67
+
68
+ describe '#stop_ec2' do
69
+ it 'should stop an ec2 instance' do
70
+ expect(ec2_client).to receive(:stop_instances).with(dry_run: false,
71
+ instance_ids: ['ec2-id'])
72
+ expect(ec2_resource).to receive(:client).and_return(client)
73
+ expect(client).to receive(:wait_until).with(:instance_stopped, instance_ids: ['ec2-id'])
74
+ subject.stop_ec2('ec2-id')
75
+ end
76
+ end
77
+
78
+ describe '#start_ec2' do
79
+ it 'should start an ec2 instance' do
80
+ expect(ec2_client).to receive(:start_instances).with(dry_run: false,
81
+ instance_ids: ['ec2-id'])
82
+ expect(ec2_resource).to receive(:client).and_return(client)
83
+ expect(client).to receive(:wait_until).with(:instance_running, instance_ids: ['ec2-id'])
84
+ expect(ec2_resource).to receive(:instances).with(instance_ids: ['ec2-id']).and_return([ec2])
85
+ expect(ec2).to receive(:public_ip_address).twice.and_return('1.2.3.4')
86
+ expect(subject.start_ec2('ec2-id')).to eq('1.2.3.4')
87
+ end
88
+ end
89
+
90
+ describe '#state' do
91
+ it 'should return the state of an existing instance' do
92
+ expect(ec2_resource).to receive(:instances).with(instance_ids: ['ec2-id']).and_return([ec2])
93
+ expect(ec2).to receive(:state).and_return(state)
94
+ expect(state).to receive(:name).and_return('running')
95
+ expect(subject.state('ec2-id')).to eq('running')
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,134 @@
1
+ require 'aws_minecraft'
2
+ require 'fakefs/spec_helpers'
3
+ require 'spec_helper'
4
+
5
+ describe AWSMine::AWSMine, fakefs: true do
6
+ include_context 'with aws minecraft'
7
+ let(:db) { instance_double(AWSMine::DBHelper) }
8
+ let(:aws) { instance_double(AWSMine::AWSHelper) }
9
+ let(:ssh) { instance_double(AWSMine::SSHHelper) }
10
+ let(:upload) { instance_double(AWSMine::UploadHelper) }
11
+ subject do |s|
12
+ s = described_class.new
13
+ s.aws_helper = aws
14
+ s.db_helper = db
15
+ s.upload_helper = upload
16
+ s.ssh_helper = ssh
17
+ s
18
+ end
19
+
20
+ describe '#create_instance' do
21
+ it 'should create an instance if it does not exists' do
22
+ expect(db).to receive(:instance_exists?).and_return(false)
23
+ expect(aws).to receive(:create_ec2).and_return(['1.2.3.4', 'i-asdf'])
24
+ expect(db).to receive(:store_instance).with('1.2.3.4', 'i-asdf')
25
+ subject.create_instance
26
+ end
27
+ it 'should return status and ip of instance if it already exists' do
28
+ expect(db).to receive(:instance_exists?).and_return(true)
29
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
30
+ expect(aws).to receive(:state).and_return('running')
31
+ subject.create_instance
32
+ end
33
+ end
34
+
35
+ describe '#start_instance' do
36
+ it 'should start an instance if it exists' do
37
+ expect(db).to receive(:instance_exists?).and_return(true)
38
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
39
+ expect(aws).to receive(:start_ec2).with('i-asdf').and_return('2.3.4.5')
40
+ expect(db).to receive(:update_instance).with('2.3.4.5', 'i-asdf')
41
+ subject.start_instance
42
+ end
43
+ it 'should return if instance does not exist' do
44
+ expect(db).to receive(:instance_exists?).and_return(false)
45
+ subject.start_instance
46
+ end
47
+ end
48
+
49
+ describe '#stop_instance' do
50
+ it 'should stop an instance if it exists' do
51
+ expect(db).to receive(:instance_exists?).and_return(true)
52
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
53
+ expect(aws).to receive(:stop_ec2).with('i-asdf').and_return('2.3.4.5')
54
+ subject.stop_instance
55
+ end
56
+ it 'should return if instance does not exist' do
57
+ expect(db).to receive(:instance_exists?).and_return(false)
58
+ subject.stop_instance
59
+ end
60
+ end
61
+
62
+ describe '#terminate_instance' do
63
+ it 'should terminate an instance if it exists and delete it from the db' do
64
+ expect(db).to receive(:instance_exists?).and_return(true)
65
+ allow($stdin).to receive(:gets) { 'y' }
66
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
67
+ expect(aws).to receive(:terminate_ec2).with('i-asdf')
68
+ expect(db).to receive(:remove_instance)
69
+ subject.terminate_instance
70
+ end
71
+ it 'should return if user chooses to not to terminate the instance' do
72
+ expect(db).to receive(:instance_exists?).and_return(true)
73
+ allow($stdin).to receive(:gets) { 'n' }
74
+ subject.terminate_instance
75
+ end
76
+ it 'should return if there are no instances' do
77
+ expect(db).to receive(:instance_exists?).and_return(false)
78
+ subject.terminate_instance
79
+ end
80
+ end
81
+
82
+ describe '#start_server' do
83
+ it 'should start a server' do
84
+ name = 'dunny'
85
+ cmd = "cd /home/ec2-user/data && ../tmux-2.2/tmux new -d -s #{AWSMine::AWSMine::MINECRAFT_SESSION_NAME} " \
86
+ "'echo eula=true > eula.txt && java -jar #{name} nogui'"
87
+ expect(subject).to receive(:remote_exec).with(cmd)
88
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
89
+ subject.start_server(name)
90
+ end
91
+ end
92
+
93
+ describe '#attach_to_server' do
94
+ it 'should attach to a running server' do
95
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
96
+ expect(ssh).to receive(:attach_to_server).with('1.2.3.4')
97
+ subject.attach_to_server
98
+ end
99
+
100
+ # TODO: There are a lot more things to cover here. Like, ssh expection.
101
+ # Or if the db doesn't exists. Or the server is not running.
102
+ end
103
+
104
+ describe '#init_db' do
105
+ it 'should initialize the db' do
106
+ expect(db).to receive(:init_db)
107
+ subject.init_db
108
+ end
109
+ end
110
+
111
+ describe '#upload_files' do
112
+ it 'should upload files from the specified location in the config.yml file' do
113
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
114
+ expect(upload).to receive(:upload_files).with('1.2.3.4')
115
+ subject.upload_files
116
+ end
117
+ end
118
+
119
+ describe '#remote_exec' do
120
+ it 'should be able to exectue cmd on an instance' do
121
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
122
+ expect(ssh).to receive(:remote_exec).with('1.2.3.4', 'test_cmd')
123
+ subject.remote_exec('test_cmd')
124
+ end
125
+ end
126
+
127
+ describe '#ssh' do
128
+ it 'should be able to ssh into a running instance' do
129
+ expect(db).to receive(:instance_details).and_return(['1.2.3.4', 'i-asdf'])
130
+ expect(ssh).to receive(:ssh).with('1.2.3.4')
131
+ subject.ssh
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,18 @@
1
+ require 'aws_minecraft/mine_config'
2
+ require 'fakefs/spec_helpers'
3
+ require 'spec_helper'
4
+
5
+ describe AWSMine::MineConfig do
6
+ include_context 'with aws minecraft'
7
+ describe '#initialize', fakefs: true do
8
+ let(:mineconfig) { AWSMine::MineConfig.new }
9
+ it 'should be an instance of MineConfig' do
10
+ expect(mineconfig).instance_of? AWSMine::MineConfig
11
+ end
12
+
13
+ it 'correctly setup variables which are loaded from the config file' do
14
+ expect(mineconfig.loglevel).to eq('ERROR')
15
+ expect(mineconfig.upload_path).to eq('/drop')
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,100 @@
1
+ # Require pp must be before fakefs. Otherwise there is an error:'superclass mismatch for class File'
2
+ require 'pp'
3
+ require 'fakefs/spec_helpers'
4
+ require 'aws-sdk'
5
+
6
+ RSpec.configure do |config|
7
+ config.include FakeFS::SpecHelpers, fakefs: true
8
+ end
9
+
10
+ shared_examples 'with aws minecraft' do
11
+ before(:all) do
12
+ # Loading metadata for AWS before FakeFS kicks in.
13
+ RSpec::Mocks.with_temporary_scope do
14
+ Aws::SharedCredentials.new
15
+ Aws::EC2::Client.new
16
+ Aws::EC2::Resource.new
17
+ end
18
+ end
19
+ include FakeFS::SpecHelpers
20
+
21
+ before :each do
22
+ FakeFS.activate!
23
+ FakeFS::FileSystem.clone(__dir__)
24
+ FakeFS do
25
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
26
+ File.open(File.join(__dir__, '../cfg/config.yml'), 'w') do |f|
27
+ f.puts('loglevel: ERROR')
28
+ f.puts('upload_path: /drop')
29
+ end
30
+
31
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
32
+ File.open(File.join(__dir__, '../cfg/ec2_conf.json'), 'w') do |f|
33
+ f.puts <<-FILE
34
+ {
35
+ "dry_run": false,
36
+ "image_id": "ami-ea26ce85",
37
+ "key_name": "minecraft_keys",
38
+ "min_count": 1,
39
+ "max_count": 1,
40
+ "instance_type": "t2.nano",
41
+ "monitoring": {
42
+ "enabled": true
43
+ }
44
+ }
45
+ FILE
46
+ end
47
+
48
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
49
+ File.open(File.join(__dir__, '../cfg/instances.sql'), 'w') do |f|
50
+ f.puts <<-FILE
51
+ create table instances (
52
+ ip varchar(100),
53
+ id varchar(100),
54
+ PRIMARY KEY (id)
55
+ );
56
+ FILE
57
+ end
58
+
59
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
60
+ File.open(File.join(__dir__, '../cfg/sg_config.json'), 'w') do |f|
61
+ f.puts <<-FILE
62
+ {
63
+ "ip_permissions": [
64
+ {
65
+ "ip_protocol": "tcp",
66
+ "from_port": 22,
67
+ "to_port": 22,
68
+ "ip_ranges": [{
69
+ "cidr_ip": "0.0.0.0/0"
70
+ }]
71
+ },
72
+ {
73
+ "ip_protocol": "tcp",
74
+ "from_port": 25565,
75
+ "to_port": 25565,
76
+ "ip_ranges": [{
77
+ "cidr_ip": "0.0.0.0/0"
78
+ }]
79
+ }
80
+ ]
81
+ }
82
+ FILE
83
+ end
84
+
85
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
86
+ File.open(File.join(__dir__, '../cfg/user_data.sh'), 'w') do |f|
87
+ f.puts <<-FILE
88
+ !#/bin/bash
89
+ FILE
90
+ end
91
+
92
+ FileUtils.mkdir_p(File.join(__dir__, '../cfg'))
93
+ File.open(File.join(__dir__, '../cfg/minecraft.key'), 'w') do |f|
94
+ f.puts <<-FILE
95
+ somekey
96
+ FILE
97
+ end
98
+ end
99
+ end
100
+ end
File without changes
File without changes
metadata ADDED
@@ -0,0 +1,140 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: aws_minecraft
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gergely Brautigam
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-10-03 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: code_stats
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ description: Provisions an EC2. Uploads a world, and deploys it.
70
+ email: skarlso777@gmail.com
71
+ executables:
72
+ - aws_minecraft.rb
73
+ extensions: []
74
+ extra_rdoc_files:
75
+ - README.md
76
+ files:
77
+ - "./cfg/minecraft.key"
78
+ - ".gitignore"
79
+ - ".rspec"
80
+ - ".travis.yml"
81
+ - Gemfile
82
+ - Gemfile.lock
83
+ - LICENSE
84
+ - README.md
85
+ - ROADMAP.md
86
+ - Rakefile
87
+ - aws_minecraft.gemspec
88
+ - bin/aws_minecraft.rb
89
+ - cfg/config.yml
90
+ - cfg/ec2_conf.json
91
+ - cfg/instances.sql
92
+ - cfg/sg_config.json
93
+ - cfg/user_data.sh
94
+ - img/attach-detach.png
95
+ - img/attach_no_session.png
96
+ - img/attached_session.png
97
+ - img/create.png
98
+ - img/create_in_progress.png
99
+ - img/stop_server.png
100
+ - img/terminate.png
101
+ - img/upload.png
102
+ - lib/aws_minecraft.rb
103
+ - lib/aws_minecraft/aws_helper.rb
104
+ - lib/aws_minecraft/db_helper.rb
105
+ - lib/aws_minecraft/mine_config.rb
106
+ - lib/aws_minecraft/ssh_helper.rb
107
+ - lib/aws_minecraft/upload_helper.rb
108
+ - lib/aws_minecraft/version.rb
109
+ - spec/aws_helper_spec.rb
110
+ - spec/awsmine_spec.rb
111
+ - spec/config_spec.rb
112
+ - spec/spec_helper.rb
113
+ - spec/ssh_helper_spec.rb
114
+ - spec/upload_helper_spec.rb
115
+ homepage: https://github.com/Skarlso/aws_minecraft
116
+ licenses:
117
+ - MIT
118
+ metadata: {}
119
+ post_install_message:
120
+ rdoc_options:
121
+ - "--charset=UTF-8"
122
+ require_paths:
123
+ - lib
124
+ required_ruby_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ required_rubygems_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ requirements: []
135
+ rubyforge_project: aws_minecraft
136
+ rubygems_version: 2.5.1
137
+ signing_key:
138
+ specification_version: 4
139
+ summary: A minecraft server provisioner on an AWS EC2 instance.
140
+ test_files: []