forked from remind101/empire
-
Notifications
You must be signed in to change notification settings - Fork 0
/
registry.go
141 lines (116 loc) · 3.34 KB
/
registry.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package empire
import (
"errors"
"fmt"
"golang.org/x/net/context"
"github.com/remind101/empire/pkg/image"
"github.com/remind101/empire/pkg/jsonmessage"
"github.com/remind101/empire/procfile"
)
// Example instance: Procfile doesn't exist
type ProcfileError struct {
Err error
}
func (e *ProcfileError) Error() string {
return fmt.Sprintf("Procfile not found: %s", e.Err)
}
// Procfile is the name of the Procfile file that Empire will use to
// determine the process formation.
const Procfile = "Procfile"
// ProcfileExtractor represents something that can extract a Procfile from an image.
type ProcfileExtractor interface {
// ExtractProcfile should return extracted a Procfile from an image, returning
// it's YAML representation.
ExtractProcfile(context.Context, image.Image, *jsonmessage.Stream) ([]byte, error)
}
// ProcfileExtractorFunc implements the ProcfileExtractor interface.
type ProcfileExtractorFunc func(context.Context, image.Image, *jsonmessage.Stream) ([]byte, error)
func (fn ProcfileExtractorFunc) ExtractProcfile(ctx context.Context, image image.Image, w *jsonmessage.Stream) ([]byte, error) {
return fn(ctx, image, w)
}
// ImageRegistry represents something that can interact with container images.
type ImageRegistry interface {
ProcfileExtractor
// Resolve should resolve an image to an "immutable" reference of the
// image.
Resolve(context.Context, image.Image, *jsonmessage.Stream) (image.Image, error)
}
func formationFromProcfile(p procfile.Procfile) (Formation, error) {
switch p := p.(type) {
case procfile.StandardProcfile:
return formationFromStandardProcfile(p)
case procfile.ExtendedProcfile:
return formationFromExtendedProcfile(p)
default:
return nil, &ProcfileError{
Err: errors.New("unknown Procfile format"),
}
}
}
func formationFromStandardProcfile(p procfile.StandardProcfile) (Formation, error) {
f := make(Formation)
for name, command := range p {
cmd, err := ParseCommand(command)
if err != nil {
return nil, err
}
f[name] = Process{
Command: cmd,
}
}
return f, nil
}
func formationFromExtendedProcfile(p procfile.ExtendedProcfile) (Formation, error) {
f := make(Formation)
for name, process := range p {
var cmd Command
var err error
switch command := process.Command.(type) {
case string:
cmd, err = ParseCommand(command)
if err != nil {
return nil, err
}
case []interface{}:
for _, v := range command {
cmd = append(cmd, v.(string))
}
default:
return nil, errors.New("unknown command format")
}
var ports []Port
for _, port := range process.Ports {
protocol := port.Protocol
if protocol == "" {
protocol = protocolFromPort(port.Host)
}
ports = append(ports, Port{
Host: port.Host,
Container: port.Container,
Protocol: protocol,
})
}
f[name] = Process{
Command: cmd,
Cron: process.Cron,
NoService: process.NoService,
Ports: ports,
Environment: process.Environment,
ECS: process.ECS,
}
}
return f, nil
}
// protocolFromPort attempts to automatically determine what protocol a port
// should use. For example, port 80 is well known to be http, so we can assume
// that http should be used. Defaults to "tcp" if unknown.
func protocolFromPort(port int) string {
switch port {
case 80, 8080:
return "http"
case 443:
return "https"
default:
return "tcp"
}
}