Skip to content
Permalink
Browse files

Merge pull request #114 from bookingcom/jgreff/selfcontained-it

Make InstallationTarget objects self contained
  • Loading branch information...
parhamdoustdar committed Aug 28, 2019
2 parents 88a97e3 + d8f3428 commit e6c4dd26c5c7538803fee9954dee2e8e74273423
@@ -32,8 +32,26 @@ spec:
type: object
required:
- clusters
- canOverride
properties:
clusters:
type: array
items:
type: string
canOverride:
type: boolean
chart:
type: object
required:
- name
- version
- repoUrl
properties:
name:
type: string
version:
type: string
repoUrl:
type: string
values:
type: object
1 go.mod
@@ -15,6 +15,7 @@ require (
github.com/gogo/protobuf v1.2.1 // indirect
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef // indirect
github.com/google/go-cmp v0.3.0
github.com/google/gofuzz v1.0.0 // indirect
github.com/googleapis/gnostic v0.2.0 // indirect
github.com/gophercloud/gophercloud v0.1.0 // indirect
7 go.sum
@@ -5,6 +5,7 @@ cloud.google.com/go v0.39.0/go.mod h1:rVLT6fkc8chs9sfPtFc1SBH6em7n+ZoXaG+87tDISt
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/Azure/go-autorest v11.1.2+incompatible h1:viZ3tV5l4gE2Sw0xrasFHytCGtzYCrT+um/rrSQ1BfA=
github.com/Azure/go-autorest v11.1.2+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY=
github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
@@ -25,6 +26,7 @@ github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuy
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/aokoli/goutils v1.0.1 h1:7fpzNGoJ3VA8qcrm++XEE1QUe0mIwNeLa02Nwq7RDkg=
github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco=
github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q=
github.com/beorn7/perks v1.0.0 h1:HWo1m869IqiPhD389kmkxeTalrjNbbJTC8LXupb+sl0=
@@ -51,6 +53,7 @@ github.com/docker/go-units v0.3.3/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD
github.com/docker/spdystream v0.0.0-20160310174837-449fdfce4d96/go.mod h1:Qh8CwZgvJUkLughtfhJv5dyTYa91l1fOUCrgjqmcifM=
github.com/elazarl/goproxy v0.0.0-20170405201442-c4fc26588b6e/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550 h1:mV9jbLoSW/8m4VK16ZkHTozJa8sesK5u5kTMFysTYac=
github.com/evanphx/json-patch v0.0.0-20190203023257-5858425f7550/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/evanphx/json-patch v4.2.0+incompatible h1:fUDGZCv/7iAN7u0puUVhvKCcsR6vRfwrJatElLBEf0I=
github.com/evanphx/json-patch v4.2.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
@@ -83,6 +86,7 @@ github.com/go-openapi/runtime v0.17.2/go.mod h1:QO936ZXeisByFmZEO1IS1Dqhtf4QV1sY
github.com/go-openapi/spec v0.0.0-20160808142527-6aced65f8501/go.mod h1:J8+jY1nAiCcj+friV/PDoE1/3eeccG9LYBs0tYvLOWc=
github.com/go-openapi/spec v0.17.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/spec v0.17.2/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
github.com/go-openapi/strfmt v0.17.0 h1:1isAxYf//QDTnVzbLAMrUK++0k1EjeLJU/gTOR0o3Mc=
github.com/go-openapi/strfmt v0.17.0/go.mod h1:P82hnJI0CXkErkXi8IKjPbNBM6lV6+5pLP5l494TcyU=
github.com/go-openapi/swag v0.0.0-20160704191624-1d0bd113de87/go.mod h1:DXUve3Dpr1UfpPtxFw+EFuQ41HhCWZfha5jSVRG7C7I=
github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
@@ -132,6 +136,7 @@ github.com/gregjones/httpcache v0.0.0-20170728041850-787624de3eb7/go.mod h1:Fecb
github.com/grpc-ecosystem/go-grpc-middleware v0.0.0-20190222133341-cfaf5686ec79/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
github.com/grpc-ecosystem/go-grpc-prometheus v0.0.0-20170330212424-2500245aa611/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
github.com/grpc-ecosystem/grpc-gateway v1.3.0/go.mod h1:RSKVYQBd5MCa4OVpNdGskqpgL2+G+NZTnrVHpWWfpdw=
github.com/hashicorp/golang-lru v0.5.0 h1:CL2msUPvZTLb5O648aiLNJw3hnBxN2+1Jq8rCOH9wdo=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
@@ -185,6 +190,7 @@ github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGV
github.com/onsi/gomega v0.0.0-20190113212917-5533ce8a0da3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo=
github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/pborman/uuid v1.2.0 h1:J7Q5mO4ysT1dv8hyrUGHb9+ooztCXu1D8MY8DZYsu3g=
github.com/pborman/uuid v1.2.0/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -344,6 +350,7 @@ gopkg.in/square/go-jose.v2 v2.0.0-20180411045311-89060dee6a84/go.mod h1:M9dMgbHi
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v1 v1.0.0-20140924161607-9f9df34309c0/go.mod h1:WDnlLJ4WF5VGsH/HVa3CI79GS0ol3YnhVnKP89i0kNg=
gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
@@ -13,10 +13,11 @@ const (

PhaseLabel = "phase"

ReleaseLabel = "shipper-release"
AppLabel = "shipper-app"
ReleaseEnvironmentHashLabel = "shipper-release-hash"
PodTrafficStatusLabel = "shipper-traffic-status"
ReleaseLabel = "shipper-release"
AppLabel = "shipper-app"
ReleaseEnvironmentHashLabel = "shipper-release-hash"
PodTrafficStatusLabel = "shipper-traffic-status"
InstallationTargetOwnerLabel = "shipper-owned-by"

ReleaseRecordWaitingForObject = "WaitingForObject"
ReleaseRecordObjectCreated = "ReleaseCreated"
@@ -313,7 +314,11 @@ type ClusterInstallationCondition struct {
}

type InstallationTargetSpec struct {
Clusters []string `json:"clusters"`
Clusters []string `json:"clusters"`
CanOverride bool `json:"canOverride"`
// XXX these are nullable because of migration
Chart *Chart `json:"chart"`
Values *ChartValues `json:"values,omitempty"`
}

// +genclient
@@ -796,6 +796,16 @@ func (in *InstallationTargetSpec) DeepCopyInto(out *InstallationTargetSpec) {
*out = make([]string, len(*in))
copy(*out, *in)
}
if in.Chart != nil {
in, out := &in.Chart, &out.Chart
*out = new(Chart)
**out = **in
}
if in.Values != nil {
in, out := &in.Values, &out.Values
x := (*in).DeepCopy()
*out = &x
}
return
}

@@ -5,9 +5,9 @@ import (
"testing"
"time"

"github.com/google/go-cmp/cmp"
corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/diff"

shipper "github.com/bookingcom/shipper/pkg/apis/shipper/v1alpha1"
)
@@ -240,7 +240,7 @@ func TestContenderStateWaitingForCapacity(t *testing.T) {
if !reflect.DeepEqual(releaseStrategyState, expected) {
t.Fatalf(
"Strategy states are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(releaseStrategyState, expected))
cmp.Diff(releaseStrategyState, expected))
}
}

@@ -287,7 +287,7 @@ func TestContenderStateWaitingForTraffic(t *testing.T) {
if !reflect.DeepEqual(releaseStrategyState, expected) {
t.Fatalf(
"Strategy states are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(releaseStrategyState, expected))
cmp.Diff(releaseStrategyState, expected))
}
}

@@ -333,7 +333,7 @@ func TestIncumbentStateWaitingForTraffic(t *testing.T) {
if !reflect.DeepEqual(releaseStrategyState, expected) {
t.Fatalf(
"Strategy states are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(releaseStrategyState, expected))
cmp.Diff(releaseStrategyState, expected))
}
}

@@ -379,7 +379,7 @@ func TestIncumbentStateWaitingForCapacity(t *testing.T) {
if !reflect.DeepEqual(releaseStrategyState, expected) {
t.Fatalf(
"Strategy states are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(releaseStrategyState, expected))
cmp.Diff(releaseStrategyState, expected))
}
}

@@ -424,7 +424,7 @@ func TestStateWaitingForCommand(t *testing.T) {
if !reflect.DeepEqual(releaseStrategyState, expected) {
t.Fatalf(
"Strategy states are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(releaseStrategyState, expected))
cmp.Diff(releaseStrategyState, expected))
}
}

@@ -450,7 +450,7 @@ func TestContenderAchievedInstallationCondition(t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Fatalf(
"ReleaseStrategyConditions are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(expected, got))
cmp.Diff(expected, got))
}
}

@@ -498,7 +498,7 @@ func TestContenderAchievedTrafficCondition(t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Fatalf(
"ReleaseStrategyConditions are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(expected, got))
cmp.Diff(expected, got))
}
}

@@ -536,7 +536,7 @@ func TestContenderAchievedCapacityCondition(t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Fatalf(
"ReleaseStrategyConditions are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(expected, got))
cmp.Diff(expected, got))
}
}

@@ -594,7 +594,7 @@ func TestIncumbentAchievedTrafficCondition(t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Fatalf(
"ReleaseStrategyConditions are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(expected, got))
cmp.Diff(expected, got))
}
}

@@ -662,7 +662,7 @@ func TestIncumbentAchievedCapacityCondition(t *testing.T) {
if !reflect.DeepEqual(expected, got) {
t.Fatalf(
"ReleaseStrategyConditions are different\nDiff:\n %s",
diff.ObjectGoPrintDiff(expected, got))
cmp.Diff(expected, got))
}
}

@@ -213,32 +213,36 @@ func (c *Controller) enqueueInstallationTarget(obj interface{}) {
c.workqueue.Add(key)
}

// processInstallation attempts to install the related release on all target clusters.
// processInstallation attempts to install the related InstallationTarget on
// all target clusters.
func (c *Controller) processInstallation(it *shipper.InstallationTarget) error {
relNamespaceLister := c.releaseLister.Releases(it.Namespace)

release, err := relNamespaceLister.ReleaseForInstallationTarget(it)
if err != nil {
return err
if !it.Spec.CanOverride {
glog.V(3).Infof("InstallationTarget %q is not allowed to override, skipping", it.Name)
return nil
}

appName, ok := release.GetLabels()[shipper.AppLabel]
if !ok {
return shippererrors.NewIncompleteReleaseError(`couldn't find label %q in release %q`, shipper.AppLabel, release.Name)
}
// If an InstallationTarget was created before we introduced
// self-contained InstallationTargets, it will not contain a chart nor
// values, so it will need to be migrated. We do so by getting those
// values from the release.
// Note that this is temporary. After this code gets released, it can
// safely be dropped in the next version.
if it.Spec.Chart == nil {
relNamespaceLister := c.releaseLister.Releases(it.Namespace)

contenderRel, err := relNamespaceLister.ContenderForApplication(appName)
if err != nil {
return err
}
release, err := relNamespaceLister.ReleaseForInstallationTarget(it)
if err != nil {
return shippererrors.NewUnrecoverableError(fmt.Errorf(
"InstallationTarget is missing Chart, and the owning release cannot be found: %s", err))
}

if contenderRel.Name != release.Name {
glog.V(3).Infof("InstallationTarget %q: Release %q is not the contender for Application %q, skipping",
it.Name, release.Name, appName)
return nil
}
it.Spec.Chart = release.Spec.Environment.Chart.DeepCopy()

installer := NewInstaller(c.chartFetcher, release, it)
if release.Spec.Environment.Values != nil {
values := release.Spec.Environment.Values.DeepCopy()
it.Spec.Values = &values
}
}

// Build .status over based on the current .spec.clusters.
newClusterStatuses := make([]*shipper.ClusterInstallationStatus, 0, len(it.Spec.Clusters))
@@ -253,6 +257,7 @@ func (c *Controller) processInstallation(it *shipper.InstallationTarget) error {
// not be operational if operations on the application cluster fail for any
// reason.

installer := NewInstaller(c.chartFetcher, it)
clusterErrors := shippererrors.NewMultiError()

for _, name := range it.Spec.Clusters {
@@ -269,13 +274,27 @@ func (c *Controller) processInstallation(it *shipper.InstallationTarget) error {
newClusterStatuses = append(newClusterStatuses, status)

var cluster *shipper.Cluster
var err error
if cluster, err = c.clusterLister.Get(name); err != nil {
err = shippererrors.NewKubeclientGetError("", name, err).WithShipperKind("Cluster")
err = shippererrors.NewKubeclientGetError("", name, err).
WithShipperKind("Cluster")
clusterErrors.Append(err)
status.Status = shipper.InstallationStatusFailed
status.Message = err.Error()
status.Conditions = conditions.SetInstallationCondition(status.Conditions, shipper.ClusterConditionTypeOperational, corev1.ConditionFalse, reasonForOperationalCondition(err), err.Error())
status.Conditions = conditions.SetInstallationCondition(status.Conditions, shipper.ClusterConditionTypeReady, corev1.ConditionUnknown, reasonForReadyCondition(err), err.Error())
status.Conditions = conditions.SetInstallationCondition(
status.Conditions,
shipper.ClusterConditionTypeOperational,
corev1.ConditionFalse,
reasonForOperationalCondition(err),
err.Error())

status.Conditions = conditions.SetInstallationCondition(
status.Conditions,
shipper.ClusterConditionTypeReady,
corev1.ConditionUnknown,
reasonForReadyCondition(err),
err.Error())

continue
}

@@ -296,7 +315,7 @@ func (c *Controller) processInstallation(it *shipper.InstallationTarget) error {
// otherwise arrives.
status.Conditions = conditions.SetInstallationCondition(status.Conditions, shipper.ClusterConditionTypeOperational, corev1.ConditionTrue, "", "")

if err = installer.installRelease(cluster, client, restConfig, c.dynamicClientBuilderFunc); err != nil {
if err = installer.install(cluster, client, restConfig, c.dynamicClientBuilderFunc); err != nil {
clusterErrors.Append(err)
status.Status = shipper.InstallationStatusFailed
status.Message = err.Error()
@@ -311,7 +330,11 @@ func (c *Controller) processInstallation(it *shipper.InstallationTarget) error {
sort.Sort(byClusterName(newClusterStatuses))
it.Status.Clusters = newClusterStatuses

_, err = c.shipperclientset.ShipperV1alpha1().InstallationTargets(it.Namespace).Update(it)
if !clusterErrors.Any() {
it.Spec.CanOverride = false
}

_, err := c.shipperclientset.ShipperV1alpha1().InstallationTargets(it.Namespace).Update(it)
if err != nil {
err = shippererrors.NewKubeclientUpdateError(it, err).
WithShipperKind("InstallationTarget")

0 comments on commit e6c4dd2

Please sign in to comment.
You can’t perform that action at this time.