implement basic exec [ci skip]

This commit is contained in:
Brad Rydzewski
2019-10-22 15:21:57 -07:00
parent 00df09b842
commit 4d3f9c66af
24 changed files with 304 additions and 60 deletions

View File

@@ -67,7 +67,7 @@ func (c *daemonCommand) run(*kingpin.ParseContext) error {
),
)
engine, err := engine.New(config.Keypair.Public, config.Keypair.Private)
engine, err := engine.NewEnv()
if err != nil {
return err
}

View File

@@ -220,7 +220,7 @@ func (c *execCommand) run(*kingpin.ParseContext) error {
),
)
engine, err := engine.New(c.PublicKey, c.PrivateKey)
engine, err := engine.NewEnv()
if err != nil {
return err
}

View File

@@ -369,6 +369,30 @@ func (c *Compiler) Compile(ctx context.Context, args Args) *engine.Spec {
}
}
// append volumes
for _, v := range args.Pipeline.Volumes {
id := random()
src := new(engine.Volume)
if v.EmptyDir != nil {
src.EmptyDir = &engine.VolumeEmptyDir{
ID: id,
Name: v.Name,
Medium: v.EmptyDir.Medium,
SizeLimit: int64(v.EmptyDir.SizeLimit),
Labels: labels,
}
} else if v.HostPath != nil {
src.HostPath = &engine.VolumeHostPath{
ID: id,
Name: v.Name,
Path: v.HostPath.Path,
}
} else {
continue
}
spec.Volumes = append(spec.Volumes, src)
}
return spec
}

View File

@@ -30,6 +30,6 @@ func setupScriptWindows(src *resource.Step, dst *engine.Step) {
func setupScriptPosix(src *resource.Step, dst *engine.Step) {
dst.Entrypoint = []string{"/bin/sh", "-c"}
dst.Command = []string{"echo $DRONE_SCRIPT | /bin/sh -e"}
dst.Command = []string{`echo "$DRONE_SCRIPT" | /bin/sh`}
dst.Envs["DRONE_SCRIPT"] = shell.Script(src.Commands)
}

View File

@@ -34,9 +34,8 @@ func Script(commands []string) string {
// optionScript is a helper script this is added to the build
// to set shell options, in this case, to exit on error.
const optionScript = `
if [[ ! -z "${DRONE_NETRC_FILE}" ]]; then
if [ ! -z "${DRONE_NETRC_FILE}" ]; then
echo $DRONE_NETRC_FILE > $HOME/.netrc
EOF
fi
unset DRONE_SCRIPT

View File

@@ -43,7 +43,7 @@ func createStep(spec *resource.Pipeline, src *resource.Step) *engine.Step {
Networks: nil, // set in compiler.go
Files: nil, // set below
Volumes: nil, // set below
// Devices: nil, // TODO
Devices: nil, // see below
// Resources: toResources(src), // TODO
}
@@ -55,6 +55,14 @@ func createStep(spec *resource.Pipeline, src *resource.Step) *engine.Step {
})
}
// appends the devices to the container def.
for _, vol := range src.Devices {
dst.Devices = append(dst.Devices, &engine.VolumeDevice{
Name: vol.Name,
DevicePath: vol.DevicePath,
})
}
// appends the settings variables to the
// container definition.
for key, value := range src.Settings {
@@ -82,19 +90,6 @@ func createStep(spec *resource.Pipeline, src *resource.Step) *engine.Step {
}
}
// // if the step specifies shell commands we generate a
// // script. The script is copied to the container at
// // runtime (or mounted as a config map) and then executed
// // as the entrypoint.
// if len(src.Commands) > 0 {
// switch spec.Platform.OS {
// case "windows":
// setupScriptWin(spec, dst, src)
// default:
// setupScript(spec, dst, src)
// }
// }
// set the pipeline step run policy. steps run on
// success by default, but may be optionally configured
// to run on failure.

View File

@@ -22,7 +22,12 @@ func createWorkspace(from *resource.Pipeline) (base, path, full string) {
base = from.Workspace.Base
path = from.Workspace.Path
if base == "" {
base = workspacePath
if strings.HasPrefix(path, "/") {
base = path
path = ""
} else {
base = workspacePath
}
}
full = stdpath.Join(base, path)

View File

@@ -36,7 +36,7 @@ func toConfig(spec *Spec, step *Step) *container.Config {
}
if len(step.Entrypoint) != 0 {
config.Cmd = step.Entrypoint
config.Entrypoint = step.Entrypoint
}
if len(step.Command) != 0 {
config.Cmd = step.Command
@@ -117,7 +117,7 @@ func toNetConfig(spec *Spec, proc *Step) *network.NetworkingConfig {
func toDeviceSlice(spec *Spec, step *Step) []container.DeviceMapping {
var to []container.DeviceMapping
for _, mount := range step.Devices {
device, ok := LookupVolume(spec, mount.Name)
device, ok := lookupVolume(spec, mount.Name)
if !ok {
continue
}
@@ -141,7 +141,7 @@ func toDeviceSlice(spec *Spec, step *Step) []container.DeviceMapping {
func toVolumeSet(spec *Spec, step *Step) map[string]struct{} {
set := map[string]struct{}{}
for _, mount := range step.Volumes {
volume, ok := LookupVolume(spec, mount.Name)
volume, ok := lookupVolume(spec, mount.Name)
if !ok {
continue
}
@@ -166,7 +166,7 @@ func toVolumeSlice(spec *Spec, step *Step) []string {
// to get it working with data volumes.
var to []string
for _, mount := range step.Volumes {
volume, ok := LookupVolume(spec, mount.Name)
volume, ok := lookupVolume(spec, mount.Name)
if !ok {
continue
}
@@ -174,7 +174,7 @@ func toVolumeSlice(spec *Spec, step *Step) []string {
continue
}
if isDataVolume(volume) {
path := volume.Metadata.UID + ":" + mount.Path
path := volume.EmptyDir.ID + ":" + mount.Path
to = append(to, path)
}
if isBindMount(volume) {
@@ -190,7 +190,7 @@ func toVolumeSlice(spec *Spec, step *Step) []string {
func toVolumeMounts(spec *Spec, step *Step) []mount.Mount {
var mounts []mount.Mount
for _, target := range step.Volumes {
source, ok := LookupVolume(spec, target.Name)
source, ok := lookupVolume(spec, target.Name)
if !ok {
continue
}
@@ -284,3 +284,16 @@ func isNamedPipe(volume *Volume) bool {
return volume.HostPath != nil &&
strings.HasPrefix(volume.HostPath.Path, `\\.\pipe\`)
}
// helper function returns the named volume.
func lookupVolume(spec *Spec, name string) (*Volume, bool) {
for _, v := range spec.Volumes {
if v.HostPath != nil && v.HostPath.Name == name {
return v, true
}
if v.EmptyDir != nil && v.EmptyDir.Name == name {
return v, true
}
}
return nil, false
}

View File

@@ -139,6 +139,8 @@ func checkVolumes(pipeline *resource.Pipeline, trusted bool) error {
}
}
switch volume.Name {
case "":
return fmt.Errorf("linter: missing volume name")
case "workspace", "_workspace", "_docker_socket":
return fmt.Errorf("linter: invalid volume name: %s", volume.Name)
}

View File

@@ -30,6 +30,12 @@ func TestLint(t *testing.T) {
message: "linter: invalid or missing image",
},
// user should not use reserved volume names.
{
path: "testdata/volume_missing_name.yml",
trusted: false,
invalid: true,
message: "linter: missing volume name",
},
{
path: "testdata/volume_invalid_name.yml",
trusted: false,

View File

@@ -0,0 +1,18 @@
---
kind: pipeline
type: docker
name: linux
steps:
- name: test
image: golang
commands:
- go build
- go test
services:
- name: database
image: redis
volumes:
- temp: {}

View File

@@ -32,7 +32,8 @@ func parse(r *manifest.RawResource) (manifest.Resource, bool, error) {
// match returns true if the resource matches the kind and type.
func match(r *manifest.RawResource) bool {
return r.Kind == Kind && r.Type == Type
return (r.Kind == Kind && r.Type == Type) ||
(r.Kind == Kind && r.Type == "")
}
func lint(pipeline *Pipeline) error {

View File

@@ -27,6 +27,7 @@ type (
CPUSet []string `json:"cpu_set,omitempty"`
Detach bool `json:"detach,omitempty"`
DependsOn []string `json:"depends_on,omitempty"`
Devices []*VolumeDevice `json:"devices,omitempty"`
DNS []string `json:"dns,omitempty"`
DNSSearch []string `json:"dns_search,omitempty"`
Entrypoint []string `json:"entrypoint,omitempty"`
@@ -119,39 +120,11 @@ type (
Labels map[string]string `json:"labels,omitempty"`
}
// XVolume that is mounted into the container
XVolume struct {
ID string `json:"id,omitempty"`
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
Labels map[string]string `json:"labels,omitempty"`
}
volumeDevice struct {
Path string
}
volumeData struct {
ID string `json:"id,omitempty"`
Name string `json:"name,omitempty"`
Path string `json:"target,omitempty"`
Mode uint32 `json:"mode,omitempty"`
}
volumeBind struct {
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
Readonly bool `json:"readonly,omitempty"`
}
volumePipe struct {
Source string `json:"source,omitempty"`
Target string `json:"target,omitempty"`
}
volumeTemp struct {
Size int64 `json:"size,omitempty"`
Path string `json:"path,omitempty"`
// VolumeDevice describes a mapping of a raw block
// device within a container.
VolumeDevice struct {
Name string `json:"name,omitempty"`
DevicePath string `json:"path,omitempty"`
}
// Network that is created and attached to containers

0
engine/testdata/network_bridge.yml vendored Normal file
View File

21
engine/testdata/network_default.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: test
pull: if-not-exists
image: redis
commands:
- sleep 5
- redis-cli -h redis ping
- redis-cli -h redis set FOO bar
- redis-cli -h redis get FOO
services:
- name: redis
pull: if-not-exists
image: redis

0
engine/testdata/network_host.yml vendored Normal file
View File

15
engine/testdata/status_failure.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: test
pull: if-not-exists
image: alpine
commands:
- echo hello
- echo world
- exit 1

15
engine/testdata/status_success.yml vendored Normal file
View File

@@ -0,0 +1,15 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: test
pull: if-not-exists
image: alpine
commands:
- echo hello
- echo world
- exit 0

32
engine/testdata/volume_host.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: write
pull: if-not-exists
image: alpine
volumes:
- name: test
path: /tmp
commands:
- pwd
- echo "hello" > /tmp/greetings.txt
- name: read
pull: if-not-exists
image: alpine
volumes:
- name: test
path: /tmp
commands:
- pwd
- cat /tmp/greetings.txt
volumes:
- name: test
host:
path: /tmp/drone/test

24
engine/testdata/volume_mem.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: write
pull: if-not-exists
image: alpine
volumes:
- name: test
path: /tmp/memory
commands:
- ls -la /tmp
- ls -la /tmp/memory
- touch /tmp/memory/hello.txt
- df -T /tmp/memory
volumes:
- name: test
temp:
medium: memory

31
engine/testdata/volume_temp.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: write
pull: if-not-exists
image: alpine
volumes:
- name: test
path: /tmp
commands:
- pwd
- echo "hello" > /tmp/greetings.txt
- name: read
pull: if-not-exists
image: alpine
volumes:
- name: test
path: /tmp
commands:
- pwd
- cat /tmp/greetings.txt
volumes:
- name: test
temp: {}

24
engine/testdata/workspace_custom.yml vendored Normal file
View File

@@ -0,0 +1,24 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
workspace:
path: /drone/custom/path
steps:
- name: write
pull: if-not-exists
image: alpine
commands:
- pwd
- echo "hello" > greetings.txt
- name: read
pull: if-not-exists
image: alpine
commands:
- pwd
- cat greetings.txt

21
engine/testdata/workspace_default.yml vendored Normal file
View File

@@ -0,0 +1,21 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
steps:
- name: write
pull: if-not-exists
image: alpine
commands:
- echo "hello" > greetings.txt
- df -T /drone/src
- name: read
pull: if-not-exists
image: alpine
commands:
- pwd
- cat greetings.txt

25
engine/testdata/workspace_legacy.yml vendored Normal file
View File

@@ -0,0 +1,25 @@
kind: pipeline
type: docker
name: default
clone:
disable: true
workspace:
base: /tmp
path: /drone
steps:
- name: write
pull: if-not-exists
image: alpine
commands:
- pwd
- echo "hello" > /tmp/greetings.txt
- name: read
pull: if-not-exists
image: alpine
commands:
- pwd
- cat /tmp/greetings.txt