phoebo 0.2.4 → 0.3.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/lib/phoebo/config.rb +23 -10
- data/lib/phoebo/config/image.rb +6 -2
- data/lib/phoebo/config/image_commands/add.rb +2 -6
- data/lib/phoebo/config/image_commands/create.rb +19 -0
- data/lib/phoebo/config/image_commands/run.rb +2 -2
- data/lib/phoebo/docker/image_builder.rb +96 -36
- data/lib/phoebo/request.rb +16 -1
- data/lib/phoebo/version.rb +1 -1
- data/lib/phoebo/worker.rb +1 -1
- data/spec/phoebo/config_spec.rb +1 -1
- data/spec/phoebo/docker/image_builder_spec.rb +1 -1
- data/spec/phoebo/request_spec.rb +20 -16
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99090a0ea219f65bfefe343d797e5569d01ed9e2
|
4
|
+
data.tar.gz: 48f00da413d5e5923906bbcd4b04a3dd5350cd73
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 40abf6542d1aaed1cfb89246a87e909be330066fef1ee2ec04cb03d3626b5e914e1fa5c9b904a7a4c53c28277f117e4c96659a4ed5e40be26ab202f9e380cb0e
|
7
|
+
data.tar.gz: 82a50760a0b290e2eed500d92480d0ae0c641a883735addccc2f973aa5228db76a02603d40ea4f67827940f6aad874522128a84aa44193de3a5661ed690b75a3
|
data/lib/phoebo/config.rb
CHANGED
@@ -6,10 +6,10 @@ module Phoebo
|
|
6
6
|
attr_accessor :images, :tasks
|
7
7
|
|
8
8
|
# Loads config from file
|
9
|
-
|
10
|
-
def self.new_from_file(file_path)
|
9
|
+
def self.new_from_file(file_path, request = nil)
|
11
10
|
begin
|
12
11
|
@instance = nil
|
12
|
+
@args = [ request, file_path ]
|
13
13
|
Kernel.load file_path, true
|
14
14
|
@instance
|
15
15
|
|
@@ -18,20 +18,25 @@ module Phoebo
|
|
18
18
|
end
|
19
19
|
end
|
20
20
|
|
21
|
+
# @see Phoebo.configure()
|
21
22
|
def self.new_from_block(block)
|
22
|
-
|
23
|
+
args = @args || [ nil, nil ]
|
24
|
+
@args = nil
|
25
|
+
|
26
|
+
@instance = self.new(*args)
|
23
27
|
@instance.dsl_eval(block)
|
24
28
|
end
|
25
29
|
|
26
30
|
# Instance initialization
|
27
|
-
def initialize
|
31
|
+
def initialize(request = nil, config_path = nil)
|
32
|
+
@request = request
|
28
33
|
@images = []
|
29
34
|
@tasks = []
|
30
35
|
end
|
31
36
|
|
32
37
|
# Evaluate block within DSL context
|
33
38
|
def dsl_eval(block)
|
34
|
-
@dsl ||= DSL.new(self)
|
39
|
+
@dsl ||= DSL.new(self, @request)
|
35
40
|
@dsl.instance_eval(&block)
|
36
41
|
|
37
42
|
# Finish config
|
@@ -51,8 +56,13 @@ module Phoebo
|
|
51
56
|
|
52
57
|
# Private DSL
|
53
58
|
class DSL
|
54
|
-
def initialize(config)
|
55
|
-
@config
|
59
|
+
def initialize(config, request)
|
60
|
+
@config = config
|
61
|
+
@request = request
|
62
|
+
end
|
63
|
+
|
64
|
+
def secrets
|
65
|
+
@request ? @request.secrets : {}
|
56
66
|
end
|
57
67
|
|
58
68
|
def image(name, options, &block)
|
@@ -90,13 +100,11 @@ module Phoebo
|
|
90
100
|
raise Phoebo::SyntaxError.new("Unexpected parameter #{options.keys.first} for service #{name}.")
|
91
101
|
end
|
92
102
|
|
93
|
-
puts task.inspect
|
94
|
-
|
95
103
|
@config.tasks << task
|
96
104
|
task
|
97
105
|
end
|
98
106
|
|
99
|
-
def task(name,
|
107
|
+
def task(name, options = {})
|
100
108
|
_task_definition_check('service', name, options)
|
101
109
|
|
102
110
|
task = {
|
@@ -105,6 +113,11 @@ module Phoebo
|
|
105
113
|
|
106
114
|
_apply_task_options(task, options)
|
107
115
|
|
116
|
+
if options[:on_demand]
|
117
|
+
task[:on_demand] = options[:on_demand] ? true : false
|
118
|
+
options.delete(:on_demand)
|
119
|
+
end
|
120
|
+
|
108
121
|
unless options.empty?
|
109
122
|
raise Phoebo::SyntaxError.new("Unexpected parameter #{options.keys.first} for task #{name}.")
|
110
123
|
end
|
data/lib/phoebo/config/image.rb
CHANGED
@@ -47,10 +47,14 @@ module Phoebo
|
|
47
47
|
|
48
48
|
# Define action methods for all commands
|
49
49
|
ImageCommands.commands.each do |id, command_class|
|
50
|
-
define_method(id) do |*args|
|
51
|
-
@image.actions << command_class.send(:action, *args)
|
50
|
+
define_method(id) do |*args, &block|
|
51
|
+
@image.actions << command_class.send(:action, *args, &block)
|
52
52
|
end
|
53
53
|
end
|
54
|
+
|
55
|
+
def method_missing(name, args, block)
|
56
|
+
raise Phoebo::SyntaxError.new("No such build command #{name} for image #{@image.name}")
|
57
|
+
end
|
54
58
|
end
|
55
59
|
|
56
60
|
end
|
@@ -5,12 +5,8 @@ module Phoebo::Config::ImageCommands
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def self.action(src, dest)
|
8
|
-
return Proc.new do |
|
9
|
-
|
10
|
-
virtual = 'project/' + src
|
11
|
-
files[virtual] = src
|
12
|
-
|
13
|
-
dockerfile << 'ADD ' + virtual + ' ' + dest
|
8
|
+
return Proc.new do |build|
|
9
|
+
build.copy(build.base_path + src, dest)
|
14
10
|
end
|
15
11
|
end
|
16
12
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Phoebo::Config::ImageCommands
|
2
|
+
class Create
|
3
|
+
def self.id
|
4
|
+
:create
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.action(destination, content = nil, &block)
|
8
|
+
return Proc.new do |build|
|
9
|
+
if block
|
10
|
+
build.create(destination, &block)
|
11
|
+
else
|
12
|
+
build.create(destination) do |out_stream|
|
13
|
+
out_stream.write(content)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -5,9 +5,9 @@ module Phoebo::Config::ImageCommands
|
|
5
5
|
end
|
6
6
|
|
7
7
|
def self.action(cmd, *args)
|
8
|
-
return Proc.new do |
|
8
|
+
return Proc.new do |build|
|
9
9
|
# TODO: decide which exec method we will use and enforce escaping
|
10
|
-
|
10
|
+
build << "RUN #{cmd} #{args.join(' ')}"
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -17,49 +17,20 @@ module Phoebo
|
|
17
17
|
|
18
18
|
if image.from.first == :base_image
|
19
19
|
dockerfile << "FROM #{image.from[1]}"
|
20
|
-
|
21
|
-
# Apply all defined actions
|
22
|
-
image.actions.each do |action|
|
23
|
-
action.call(dockerfile, project_files)
|
24
|
-
end
|
25
20
|
end
|
26
21
|
|
27
|
-
# TODO: Honor file mode
|
28
22
|
tar_stream = StringIO.new
|
29
23
|
Gem::Package::TarWriter.new(tar_stream) do |tar|
|
30
|
-
tar.add_file('Dockerfile', 0640) { |out_stream| out_stream.write(dockerfile.join("\n")) }
|
31
|
-
tar.mkdir('project', 0750)
|
32
|
-
|
33
|
-
# Copy project file into virtual destination
|
34
|
-
while !project_files.empty? do
|
35
|
-
virtual, relative = project_files.shift
|
36
|
-
real = @base_path + relative
|
37
24
|
|
38
|
-
|
39
|
-
real.each_entry do |child|
|
40
|
-
next if child.fnmatch?('..') or child.fnmatch?('.')
|
41
|
-
if child.directory?
|
42
|
-
tar.mkdir("#{virtual}/#{child}", 0750)
|
43
|
-
end
|
25
|
+
image_build = Build.new(@base_path, dockerfile, tar)
|
44
26
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
elsif real.file?
|
50
|
-
|
51
|
-
# 'file.txt' -> 'dest/'
|
52
|
-
if virtual.end_with?('/')
|
53
|
-
dest += real.basename.to_s
|
54
|
-
end
|
55
|
-
|
56
|
-
# Read file to our TAR output stream
|
57
|
-
tar.add_file(virtual, 0640) do |out_stream|
|
58
|
-
in_stream = real.open('r')
|
59
|
-
IO.copy_stream(in_stream, out_stream)
|
60
|
-
end
|
61
|
-
end
|
27
|
+
# Apply all defined actions
|
28
|
+
image.actions.each do |action|
|
29
|
+
action.call(image_build)
|
62
30
|
end
|
31
|
+
|
32
|
+
# Create Dockerfile
|
33
|
+
tar.add_file('Dockerfile', 0640) { |out_stream| out_stream.write(dockerfile.join("\n")) }
|
63
34
|
end
|
64
35
|
|
65
36
|
begin
|
@@ -86,6 +57,95 @@ module Phoebo
|
|
86
57
|
raise DockerError, e.message
|
87
58
|
end
|
88
59
|
end
|
60
|
+
|
61
|
+
class Build
|
62
|
+
attr_reader :base_path, :dockerfile, :tar
|
63
|
+
|
64
|
+
def initialize(base_path, dockerfile, tar)
|
65
|
+
@base_path = base_path
|
66
|
+
@dockerfile = dockerfile
|
67
|
+
@tar = tar
|
68
|
+
|
69
|
+
@dirs = { }
|
70
|
+
end
|
71
|
+
|
72
|
+
# Add Dockerfile instruction
|
73
|
+
def <<(str)
|
74
|
+
@dockerfile << str
|
75
|
+
end
|
76
|
+
|
77
|
+
# Create new file by block
|
78
|
+
def create(destination_path, mode = 640, &block)
|
79
|
+
basename = Pathname.new(destination_path).basename.to_s
|
80
|
+
random = random_dir
|
81
|
+
|
82
|
+
# Add Dockerfile instruction
|
83
|
+
virtual = "#{random}/#{basename}"
|
84
|
+
self << 'ADD ' + virtual + ' ' + destination_path
|
85
|
+
|
86
|
+
# Create directory for this instruction
|
87
|
+
tar.mkdir(random, 750)
|
88
|
+
|
89
|
+
# Add file with yielded block
|
90
|
+
@tar.add_file(virtual, mode, &block)
|
91
|
+
end
|
92
|
+
|
93
|
+
# Copy files to docker image
|
94
|
+
def copy(source, destination_path)
|
95
|
+
# TODO: Honor file mode
|
96
|
+
|
97
|
+
source = Pathname.new(source) unless source.is_a?(Pathname)
|
98
|
+
random = random_dir
|
99
|
+
|
100
|
+
# Add Dockerfile instruction
|
101
|
+
if source.directory?
|
102
|
+
self << 'ADD ' + random + ' ' + destination_path
|
103
|
+
files = [ [ source, random ] ]
|
104
|
+
else
|
105
|
+
self << 'ADD ' + random + '/' + source.basename.to_s + ' ' + destination_path
|
106
|
+
files = [ [ source, random + '/' ] ]
|
107
|
+
end
|
108
|
+
|
109
|
+
# Create directory for this instruction
|
110
|
+
tar.mkdir(random, 750)
|
111
|
+
|
112
|
+
# Add all the files recursively
|
113
|
+
while !files.empty? do
|
114
|
+
source, destination_path = files.shift
|
115
|
+
|
116
|
+
# Directory
|
117
|
+
if source.directory?
|
118
|
+
source.each_entry do |child|
|
119
|
+
next if child.fnmatch?('..') or child.fnmatch?('.')
|
120
|
+
@tar.mkdir("#{destination_path}/#{child}", 0750) if child.directory?
|
121
|
+
files << [ source + child, "#{destination_path}/#{child}" ]
|
122
|
+
end
|
123
|
+
|
124
|
+
# File
|
125
|
+
elsif source.file?
|
126
|
+
# If we are adding 'file.txt' to 'dest/': we need to append filename
|
127
|
+
destination_path += source.basename.to_s if destination_path.end_with?('/')
|
128
|
+
|
129
|
+
# Add file copy
|
130
|
+
@tar.add_file(destination_path, 0640) do |out_stream|
|
131
|
+
in_stream = source.open('r')
|
132
|
+
IO.copy_stream(in_stream, out_stream)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
|
140
|
+
def random_dir
|
141
|
+
begin
|
142
|
+
random = SecureRandom.hex
|
143
|
+
end while @dirs.key?(random)
|
144
|
+
|
145
|
+
@dirs[random] = true
|
146
|
+
random
|
147
|
+
end
|
148
|
+
end
|
89
149
|
end
|
90
150
|
end
|
91
151
|
end
|
data/lib/phoebo/request.rb
CHANGED
@@ -36,6 +36,21 @@ module Phoebo
|
|
36
36
|
IO.write(@ssh_public_file, key_content)
|
37
37
|
end
|
38
38
|
|
39
|
+
# Secrets (default: empty hash)
|
40
|
+
def secrets
|
41
|
+
@secrets ||= {}
|
42
|
+
end
|
43
|
+
|
44
|
+
# Secrets validation on set
|
45
|
+
def secrets=(hash)
|
46
|
+
hash.each do |key, value|
|
47
|
+
raise InvalidRequestError, "Invalid format for request secret #{key.inspect}" \
|
48
|
+
unless value.is_a? String or value.is_a? Numeric
|
49
|
+
end
|
50
|
+
|
51
|
+
@secrets = hash
|
52
|
+
end
|
53
|
+
|
39
54
|
# Loads request with data from hash
|
40
55
|
def load_from_hash!(hash)
|
41
56
|
hash.each do |k, v|
|
@@ -50,7 +65,7 @@ module Phoebo
|
|
50
65
|
# Loads request from JSON string
|
51
66
|
def load_from_json!(raw_data)
|
52
67
|
begin
|
53
|
-
hash = JSON.parse(raw_data)
|
68
|
+
hash = JSON.parse(raw_data, symbolize_names: true)
|
54
69
|
rescue JSON::ParserError => e
|
55
70
|
raise InvalidRequestError, "Malformed JSON data."
|
56
71
|
end
|
data/lib/phoebo/version.rb
CHANGED
data/lib/phoebo/worker.rb
CHANGED
data/spec/phoebo/config_spec.rb
CHANGED
@@ -48,7 +48,7 @@ describe Phoebo::Config do
|
|
48
48
|
|
49
49
|
it 'processes images' do
|
50
50
|
image = instance_double(Phoebo::Config::Image)
|
51
|
-
expect(Phoebo::Config::Image).to receive(:new).with('image-name', 'base-image-name', image_dsl_block).and_return(image)
|
51
|
+
expect(Phoebo::Config::Image).to receive(:new).with('image-name', { from: 'base-image-name' }, image_dsl_block).and_return(image)
|
52
52
|
|
53
53
|
subject.dsl_eval(dsl)
|
54
54
|
expect(subject.images).to include(image)
|
@@ -24,7 +24,7 @@ describe Phoebo::Docker::ImageBuilder do
|
|
24
24
|
|
25
25
|
image = instance_double(Phoebo::Config::Image)
|
26
26
|
allow(image).to receive(:name).and_return('image-name')
|
27
|
-
allow(image).to receive(:from).and_return('debian')
|
27
|
+
allow(image).to receive(:from).and_return([ :base_image, 'debian'])
|
28
28
|
allow(image).to receive(:actions).and_return(actions)
|
29
29
|
|
30
30
|
image
|
data/spec/phoebo/request_spec.rb
CHANGED
@@ -85,7 +85,10 @@ describe Phoebo::Request do
|
|
85
85
|
let(:json) do
|
86
86
|
<<-EOS
|
87
87
|
{
|
88
|
-
"repo_url": "ssh://somehost.tld/user/repo.git"
|
88
|
+
"repo_url": "ssh://somehost.tld/user/repo.git",
|
89
|
+
"secrets": {
|
90
|
+
"dbpassword": "somesecretpassword"
|
91
|
+
}
|
89
92
|
}
|
90
93
|
EOS
|
91
94
|
end
|
@@ -106,6 +109,7 @@ describe Phoebo::Request do
|
|
106
109
|
it 'applies arguments' do
|
107
110
|
subject.load_from_json!(json)
|
108
111
|
expect(subject.repo_url).to eql('ssh://somehost.tld/user/repo.git')
|
112
|
+
expect(subject.secrets[:dbpassword]).to eql('somesecretpassword')
|
109
113
|
end
|
110
114
|
end
|
111
115
|
|
@@ -123,19 +127,19 @@ describe Phoebo::Request do
|
|
123
127
|
end
|
124
128
|
end
|
125
129
|
|
126
|
-
# TODO: cover all possible states
|
127
|
-
context 'loading from url' do
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
end
|
130
|
+
# TODO: cover all possible states and use some HTTP mocking library
|
131
|
+
# context 'loading from url' do
|
132
|
+
# let(:http_response) do
|
133
|
+
# response = double(Net::HTTPOK)
|
134
|
+
# allow(response).to receive(:code).and_return(200)
|
135
|
+
# allow(response).to receive(:body).and_return(json)
|
136
|
+
# response
|
137
|
+
# end
|
138
|
+
|
139
|
+
# it 'loads data' do
|
140
|
+
# allow(Net::HTTP).to receive(:start).and_return(http_response)
|
141
|
+
# expect(subject).to receive(:load_from_json!).with(json)
|
142
|
+
# subject.load_from_url!('http://test')
|
143
|
+
# end
|
144
|
+
# end
|
141
145
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: phoebo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Staněk
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-04-
|
11
|
+
date: 2015-04-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: colorize
|
@@ -129,6 +129,7 @@ files:
|
|
129
129
|
- lib/phoebo/config/image.rb
|
130
130
|
- lib/phoebo/config/image_commands.rb
|
131
131
|
- lib/phoebo/config/image_commands/add.rb
|
132
|
+
- lib/phoebo/config/image_commands/create.rb
|
132
133
|
- lib/phoebo/config/image_commands/run.rb
|
133
134
|
- lib/phoebo/console.rb
|
134
135
|
- lib/phoebo/docker.rb
|