Skip to content

Commit

Permalink
Merge pull request #5 from namely/volume-sources
Browse files Browse the repository at this point in the history
Add volume source JSON targeting
  • Loading branch information
shraykay authored Feb 1, 2018
2 parents 32855a0 + 8ed825b commit 92b11eb
Show file tree
Hide file tree
Showing 7 changed files with 167 additions and 8 deletions.
2 changes: 1 addition & 1 deletion cmd/k8s-pipeliner/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

const (
// Version defines the current version of k8s-pipeliner
Version = "0.0.3"
Version = "0.0.4"
)

func main() {
Expand Down
4 changes: 2 additions & 2 deletions pipeline/builder/builder.go
Original file line number Diff line number Diff line change
Expand Up @@ -155,10 +155,10 @@ func (b *Builder) buildDeployStage(index int, s config.Stage) (*types.DeployStag
Stack: s.Deploy.Stack,
Strategy: s.Deploy.Strategy,
TargetSize: s.Deploy.TargetSize,
VolumeSources: mg.VolumeSources,

// TODO(bobbytables): allow these to be configurable
VolumeSources: []interface{}{},
Events: []interface{}{},
Events: []interface{}{},
InterestingHealthProviderNames: []string{"KubernetesContainer", "KubernetesPod"},
Provider: "kubernetes",
CloudProvider: "kubernetes",
Expand Down
59 changes: 56 additions & 3 deletions pipeline/builder/kubernetes.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/namely/k8s-pipeliner/pipeline/builder/types"

appsv1 "k8s.io/api/apps/v1"
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime"
"k8s.io/client-go/kubernetes/scheme"
)
Expand Down Expand Up @@ -54,9 +55,10 @@ const (
// ManifestGroup keeps a collection of containers from a deployment
// and metadata associated with them
type ManifestGroup struct {
Namespace string
Annotations map[string]string
Containers []*types.Container
Namespace string
Annotations map[string]string
Containers []*types.Container
VolumeSources []*types.VolumeSource
}

// ContainersFromManifest loads a kubernetes manifest file and generates
Expand Down Expand Up @@ -96,15 +98,57 @@ func ContainersFromManifest(file string) (*ManifestGroup, error) {
mg.Containers = deploymentContainers(t)
mg.Annotations = t.Annotations
mg.Namespace = t.Namespace
mg.VolumeSources = volumeSources(t.Spec.Template.Spec.Volumes)
default:
return nil, ErrUnsupportedManifest
}

return &mg, nil
}

// converts kubernetes volume sources into builder types
func volumeSources(vols []corev1.Volume) []*types.VolumeSource {
var vs []*types.VolumeSource

for _, vol := range vols {
spinVol := &types.VolumeSource{
Name: vol.Name,
}

if cm := vol.ConfigMap; cm != nil {
spinVol.ConfigMap = &types.ConfigMapVolumeSource{
ConfigMapName: cm.Name,
Items: cm.Items,
DefaultMode: cm.DefaultMode,
}
spinVol.Type = "CONFIGMAP"
}

if sec := vol.Secret; sec != nil {
spinVol.Secret = &types.SecretVolumeSource{
SecretName: sec.SecretName,
Items: sec.Items,
}
spinVol.Type = "SECRET"
}

if ed := vol.EmptyDir; ed != nil {
spinVol.EmptyDir = &types.EmptyDirVolumeSource{
// Spinnaker requires this to be uppercased for some reason
Medium: strings.ToUpper(string(ed.Medium)),
}
spinVol.Type = "EMPTYDIR"
}

vs = append(vs, spinVol)
}

return vs
}

func deploymentContainers(dep *appsv1.Deployment) []*types.Container {
var c []*types.Container

for _, container := range dep.Spec.Template.Spec.Containers {
spinContainer := &types.Container{}

Expand Down Expand Up @@ -170,6 +214,15 @@ func deploymentContainers(dep *appsv1.Deployment) []*types.Container {
spinContainer.EnvVars = append(spinContainer.EnvVars, e)
}

// add all of the volume mounts
for _, vm := range container.VolumeMounts {
spinContainer.VolumeMounts = append(spinContainer.VolumeMounts, types.VolumeMount{
Name: vm.Name,
ReadOnly: vm.ReadOnly,
MountPath: vm.MountPath,
})
}

c = append(c, spinContainer)
}

Expand Down
34 changes: 34 additions & 0 deletions pipeline/builder/kubernetes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ func TestContainersFromManifests(t *testing.T) {
assert.Len(t, group.Containers, 1)
assert.Len(t, group.Annotations, 2)
assert.Equal(t, "fake-namespace", group.Namespace)

t.Run("Container VolumeMounts are copied in", func(t *testing.T) {
c := group.Containers[0]

require.Len(t, c.VolumeMounts, 1)
assert.Equal(t, "configmap-volume", c.VolumeMounts[0].Name)
assert.Equal(t, "/thisisthemount", c.VolumeMounts[0].MountPath)
assert.Equal(t, true, c.VolumeMounts[0].ReadOnly)
})
})

t.Run("Deployments schemes are converted to latest", func(t *testing.T) {
Expand All @@ -34,4 +43,29 @@ func TestContainersFromManifests(t *testing.T) {
assert.Len(t, group.Annotations, 2)
assert.Equal(t, "fake-namespace", group.Namespace)
})

t.Run("Volume sources are copied", func(t *testing.T) {
file := filepath.Join(wd, "testdata", "deployment.full.yml")
group, err := builder.ContainersFromManifest(file)
require.NoError(t, err)
require.Len(t, group.VolumeSources, 3)

t.Run("ConfigMaps are copied", func(t *testing.T) {
cms := group.VolumeSources[0]
require.NotNil(t, cms.ConfigMap)
assert.Equal(t, cms.Type, "CONFIGMAP")
})

t.Run("Secrets are copied", func(t *testing.T) {
sec := group.VolumeSources[1]
require.NotNil(t, sec.Secret)
assert.Equal(t, sec.Type, "SECRET")
})

t.Run("EmptyDirs are copied", func(t *testing.T) {
ed := group.VolumeSources[2]
require.NotNil(t, ed.EmptyDir)
assert.Equal(t, ed.Type, "EMPTYDIR")
})
})
}
20 changes: 20 additions & 0 deletions pipeline/builder/testdata/deployment.full.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,3 +20,23 @@ spec:
- name: WHATS_THE_WORD
value: "bird is the word"
image: bird.word/latest
volumeMounts:
- name: configmap-volume
mountPath: "/thisisthemount"
readOnly: true
volumes:
- name: configmap-volume
configMap:
name: "my-configmap-name"
items:
- key: "hello"
path: "/my/file/path"
- name: secret-volume
secret:
secretName: "my-secret"
items:
- key: "hello"
path: "/my/file/path"
- name: empty-volume
emptyDir:
medium: "Memory"
45 changes: 43 additions & 2 deletions pipeline/builder/types/types.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package types

import (
corev1 "k8s.io/api/core/v1"
)

// SpinnakerPipeline defines the fields for the top leve object of a spinnaker
// pipeline. Mostly used for constructing JSON
type SpinnakerPipeline struct {
Expand Down Expand Up @@ -115,7 +119,7 @@ type Cluster struct {
Strategy string `json:"strategy"`
TargetSize int `json:"targetSize"`
TerminationGracePeriodSeconds int `json:"terminationGracePeriodSeconds"`
VolumeSources []interface{} `json:"volumeSources"`
VolumeSources []*VolumeSource `json:"volumeSources"`
DelayBeforeDisableSec int `json:"delayBeforeDisableSec,omitempty"`
}

Expand All @@ -133,7 +137,15 @@ type Container struct {
Name string `json:"name"`
Ports []Port `json:"ports"`

VolumeMounts []interface{} `json:"volumeMounts"`
VolumeMounts []VolumeMount `json:"volumeMounts"`
}

// VolumeMount describes a mount that should be mounted in to the container
// by referencing a volume source in the pod spec
type VolumeMount struct {
MountPath string `json:"mountPath"`
Name string `json:"name"`
ReadOnly bool `json:"readOnly"`
}

// Resources for the container either as a limit or request
Expand Down Expand Up @@ -201,3 +213,32 @@ type Notification struct {
type NotificationMessage struct {
Text string `json:"text"`
}

// VolumeSource defines a pod volume source that can be referenced by containers
type VolumeSource struct {
Name string `json:"name"`
Type string `json:"type"`

EmptyDir *EmptyDirVolumeSource `json:"emptyDir,omitempty"`
ConfigMap *ConfigMapVolumeSource `json:"configMap,omitempty"`
Secret *SecretVolumeSource `json:"secret,omitempty"`
}

// EmptyDirVolumeSource defines a empty directory volume source for a pod:
// https://kubernetes.io/docs/api-reference/v1.9/#emptydirvolumesource-v1-core
type EmptyDirVolumeSource struct {
Medium string `json:"medium"`
}

// ConfigMapVolumeSource type for referencing configmaps in volumes
type ConfigMapVolumeSource struct {
ConfigMapName string `json:"configMapName"`
DefaultMode *int32 `json:"defaultMode,omitempty"`
Items []corev1.KeyToPath `json:"items"`
}

// SecretVolumeSource for referencing secret types in volumes
type SecretVolumeSource struct {
SecretName string `json:"secretName"`
Items []corev1.KeyToPath `json:"items"`
}
11 changes: 11 additions & 0 deletions test-deployment.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,13 @@ spec:
labels:
app: example
spec:
volumes:
- name: configmap-volume
configMap:
name: "my-configmap-name"
items:
- key: "hello"
path: "/my/file/path"
containers:
- command:
- bundle
Expand All @@ -25,6 +32,10 @@ spec:
- "80"
- -c
- ./config/unicorn.rb
volumeMounts:
- name: configmap-volume
mountPath: "/thisisthemount"
readOnly: true
env:
- name: ADMIN_PASSWORD
valueFrom:
Expand Down

0 comments on commit 92b11eb

Please sign in to comment.