Skip to content

Commit e334645

Browse files
Cristhian CastanedaJossuecito
andauthored
chore(release): v1.2.1 (#198)
* fix(timeout): avoid revalidation when patching Spinnaker Status. (#192) * fix(timeout): avoid revalidation when patching Spinnaker Status. * fix(timeout): add unit test. * fix(timeout): add unit test. (cherry picked from commit 2e09945) * chore(cve): fix for CVE-2020-13757 (#193) (cherry picked from commit e8de226) * feat(validator/aws): add aws account validator. (#195) * feat(validator/aws): add aws account validator. * feat(validator/aws): solve PR comments. (cherry picked from commit 123572c) * chore(halyard): Updated halyard version (#197) (cherry picked from commit 7eb2a58) Co-authored-by: Jossue <jossue@gmail.com>
1 parent ef06aeb commit e334645

16 files changed

Lines changed: 633 additions & 68 deletions

File tree

build-tools/Dockerfile

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,46 @@
11
ARG BUILDER
22
FROM ${BUILDER} as builder
33

4-
FROM python:2.7.18-alpine3.11
4+
FROM python:3.7-alpine3.12
55

66
ENV OPERATOR=/usr/local/bin/spinnaker-operator \
77
USER_UID=1001 \
88
USER_NAME=spinnaker-operator \
9-
AWS_BINARY_RELEASE_DATE=2019-08-22 \
10-
KUBECTL_RELEASE=1.14.6 \
11-
AWS_CLI_RELEASE=1.18.58 \
12-
OPERATOR_HOME=/opt/spinnaker-operator
9+
AWS_AIM_AUTHENTICATOR_VERSION=0.4.0 \
10+
KUBECTL_RELEASE=1.17.7 \
11+
AWS_CLI_VERSION=1.18.109 \
12+
OPERATOR_HOME=/opt/spinnaker-operator \
13+
GOOGLE_CLOUD_SDK_VERSION=313.0.1 \
14+
PATH="$PATH:/usr/local/bin/:/opt/google-cloud-sdk/bin/:/usr/local/bin/aws-iam-authenticator"
1315

1416
EXPOSE 8383
1517
RUN apk update \
1618
&& apk add ca-certificates bash curl wget unzip \
1719
&& adduser -D -u ${USER_UID} ${USER_NAME} \
1820
&& apk upgrade
1921

20-
# Install aws iam authenticator
21-
RUN curl -o aws-iam-authenticator https://amazon-eks.s3-us-west-2.amazonaws.com/${KUBECTL_RELEASE}/${AWS_BINARY_RELEASE_DATE}/bin/linux/amd64/aws-iam-authenticator && \
22-
chmod +x ./aws-iam-authenticator && \
23-
mv ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
24-
ENV PATH "$PATH:/usr/local/bin/aws-iam-authenticator"
22+
# Google cloud SDK with anthos removed for CVE and because we don't need it
23+
RUN wget -nv https://dl.google.com/dl/cloudsdk/channels/rapid/downloads/google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
24+
&& mkdir -p /opt && cd /opt \
25+
&& tar -xzf /google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
26+
&& rm /google-cloud-sdk-${GOOGLE_CLOUD_SDK_VERSION}-linux-x86_64.tar.gz \
27+
&& CLOUDSDK_PYTHON="python3" /opt/google-cloud-sdk/install.sh --usage-reporting=false --bash-completion=false --additional-components app-engine-java app-engine-go \
28+
&& rm -rf ~/.config/gcloud \
29+
&& gcloud components remove --quiet anthoscli \
30+
&& rm -rf /opt/google-cloud-sdk/.install/.backup
31+
32+
# kubectl + AWS IAM authenticator
33+
RUN wget https://storage.googleapis.com/kubernetes-release/release/v${KUBECTL_RELEASE}/bin/linux/amd64/kubectl \
34+
&& chmod +x kubectl \
35+
&& mv ./kubectl /usr/local/bin/kubectl \
36+
&& wget -O aws-iam-authenticator https://github.com/kubernetes-sigs/aws-iam-authenticator/releases/download/v${AWS_AIM_AUTHENTICATOR_VERSION}/aws-iam-authenticator_${AWS_AIM_AUTHENTICATOR_VERSION}_linux_amd64 \
37+
&& chmod +x ./aws-iam-authenticator \
38+
&& mv ./aws-iam-authenticator /usr/local/bin/aws-iam-authenticator
2539

2640
# Install aws-cli
27-
RUN pip install --upgrade awscli==${AWS_CLI_RELEASE} \
41+
RUN pip install --upgrade awscli==${AWS_CLI_VERSION} \
2842
&& pip uninstall -y pip
2943

30-
# Install gcloud
31-
RUN wget -nv https://dl.google.com/dl/cloudsdk/release/google-cloud-sdk.zip && \
32-
unzip -qq google-cloud-sdk.zip -d /opt && \
33-
rm google-cloud-sdk.zip && \
34-
CLOUDSDK_PYTHON="python2.7" /opt/google-cloud-sdk/install.sh --usage-reporting=false --bash-completion=false && \
35-
rm -rf ~/.config/gcloud
36-
ENV PATH=$PATH:/opt/google-cloud-sdk/bin/
37-
3844
USER ${USER_NAME}
3945

4046
# Everything after this line is never cached

halyard-version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
operator-c1d641c
1+
operator-8e0406f

pkg/apis/spinnaker/interfaces/validation.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,3 +73,10 @@ func (s *SpinnakerValidation) GetValidationSettings() *ValidationSetting {
7373
FrequencySeconds: f,
7474
}
7575
}
76+
77+
func (s *SpinnakerValidation) IsProviderValidationEnabled(key string) bool {
78+
if provider, ok := s.Providers[key]; ok {
79+
return provider.Enabled
80+
}
81+
return true
82+
}

pkg/controller/spinnakerservice/status.go

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ package spinnakerservice
22

33
import (
44
"context"
5-
"errors"
65
"github.com/armory/spinnaker-operator/pkg/apis/spinnaker/interfaces"
76
"github.com/armory/spinnaker-operator/pkg/util"
87
"github.com/go-logr/logr"
@@ -80,10 +79,6 @@ func (s *statusChecker) checks(instance interfaces.SpinnakerService) error {
8079
return err
8180
}
8281

83-
if Updating == status.Status {
84-
return errors.New("spinnaker still updating")
85-
}
86-
8782
return nil
8883
}
8984

@@ -95,6 +90,7 @@ func (s *statusChecker) getStatus(instance interfaces.SpinnakerService, pods []v
9590
return Na, nil
9691
}
9792

93+
var podsRunningOk []v1.Pod
9894
for _, p := range pods {
9995
switch p.Status.Phase {
10096
case v1.PodRunning:
@@ -106,18 +102,12 @@ func (s *statusChecker) getStatus(instance interfaces.SpinnakerService, pods []v
106102
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployFailed", "Pod %s exceeds the time limit", p.Name)
107103
return Failure, nil
108104
}
105+
109106
for _, cs := range p.Status.ContainerStatuses {
110-
if cs.State.Terminated != nil {
111-
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployInProgress", "Pod %s is in Phase: %s. Message: %s", p.Name, p.Status.Phase, cs.State.Terminated.Reason)
112-
return Updating, nil
113-
}
114-
if cs.State.Waiting != nil {
115-
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployInProgress", "Pod %s is in Phase: %s. Message: %s", p.Name, p.Status.Phase, cs.State.Waiting.Reason)
116-
return Updating, nil
117-
}
118-
if !cs.Ready {
119-
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployInProgress", "Pod %s is in Phase: %s. Message: %s", p.Name, p.Status.Phase, p.Status.Reason)
120-
return Updating, nil
107+
if cs.State.Running != nil {
108+
if p.DeletionTimestamp == nil {
109+
podsRunningOk = append(podsRunningOk, p)
110+
}
121111
}
122112
}
123113
break
@@ -138,10 +128,6 @@ func (s *statusChecker) getStatus(instance interfaces.SpinnakerService, pods []v
138128
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployFailed", "Pod %s has not been able to reach a healthy state is in Phase: %s. Message: %s", p.Name, p.Status.Phase, cs.State.Waiting.Reason)
139129
return Failure, nil
140130
}
141-
if !cs.Ready {
142-
s.evtRecorder.Eventf(instance, v1.EventTypeWarning, "DeployInProgress", "Pod %s is in Phase: %s. Message: %s", p.Name, p.Status.Phase, p.Status.Reason)
143-
return Updating, nil
144-
}
145131
}
146132
break
147133
case v1.PodFailed, v1.PodUnknown:
@@ -151,5 +137,10 @@ func (s *statusChecker) getStatus(instance interfaces.SpinnakerService, pods []v
151137
break
152138
}
153139
}
140+
141+
if instance.GetStatus().ServiceCount != len(podsRunningOk) {
142+
status = Updating
143+
}
144+
154145
return status, nil
155146
}

pkg/controller/spinnakerservice/status_test.go

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,13 @@ import (
1010
"github.com/stretchr/testify/assert"
1111
appsv1 "k8s.io/api/apps/v1"
1212
v1 "k8s.io/api/core/v1"
13+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1314
"k8s.io/client-go/kubernetes/scheme"
1415
"k8s.io/client-go/tools/record"
1516
"sigs.k8s.io/controller-runtime/pkg/client"
1617
"sigs.k8s.io/controller-runtime/pkg/client/fake"
1718
"testing"
19+
"time"
1820
)
1921

2022
func Test_statusChecker_checks(t *testing.T) {
@@ -47,6 +49,15 @@ func Test_statusChecker_checks(t *testing.T) {
4749
mockedPods: []v1.Pod{{
4850
Status: v1.PodStatus{
4951
Phase: v1.PodRunning,
52+
ContainerStatuses: []v1.ContainerStatus{
53+
{
54+
State: v1.ContainerState{
55+
Running: &v1.ContainerStateRunning{
56+
StartedAt: metav1.Time{Time: time.Now()},
57+
},
58+
},
59+
},
60+
},
5061
},
5162
}},
5263
mockedDeployments: []appsv1.Deployment{{}},
@@ -93,7 +104,7 @@ func Test_statusChecker_checks(t *testing.T) {
93104
mockedDeployments: []appsv1.Deployment{{}},
94105
mockedExceededTime: false,
95106
},
96-
wantErr: true,
107+
wantErr: false,
97108
status: Updating,
98109
},
99110
{
@@ -140,6 +151,35 @@ func Test_statusChecker_checks(t *testing.T) {
140151
wantErr: false,
141152
status: Na,
142153
},
154+
{
155+
name: "Spinsvc should have Updating status because pods are terminating",
156+
fields: fields{},
157+
args: args{
158+
instance: spinSvc,
159+
mockedPods: []v1.Pod{{
160+
ObjectMeta: metav1.ObjectMeta{
161+
DeletionTimestamp: &metav1.Time{Time: time.Now()},
162+
},
163+
Status: v1.PodStatus{
164+
Phase: v1.PodRunning,
165+
ContainerStatuses: []v1.ContainerStatus{
166+
{
167+
State: v1.ContainerState{
168+
Running: &v1.ContainerStateRunning{
169+
StartedAt: metav1.Time{Time: time.Now()},
170+
},
171+
},
172+
},
173+
},
174+
},
175+
},
176+
},
177+
mockedDeployments: []appsv1.Deployment{{}},
178+
mockedExceededTime: false,
179+
},
180+
wantErr: false,
181+
status: Updating,
182+
},
143183
}
144184
for _, tt := range tests {
145185
t.Run(tt.name, func(t *testing.T) {

pkg/controller/spinnakerservice/testdata/spinsvc.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,3 +28,4 @@ spec:
2828
status:
2929
apiUrl: http://acme.com
3030
uiUrl: http://acme.com
31+
serviceCount: 1

pkg/controller/spinnakervalidating/spinnakervalidating_controller.go

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,18 @@ package spinnakervalidating
22

33
import (
44
"context"
5+
"crypto/md5"
6+
"encoding/hex"
57
"encoding/json"
68
"fmt"
79
"github.com/armory/spinnaker-operator/pkg/apis/spinnaker/interfaces"
810
"github.com/armory/spinnaker-operator/pkg/controller/webhook"
911
"github.com/armory/spinnaker-operator/pkg/halyard"
1012
"github.com/armory/spinnaker-operator/pkg/secrets"
1113
"github.com/armory/spinnaker-operator/pkg/validate"
14+
"gomodules.xyz/jsonpatch/v2"
1215
"k8s.io/api/admission/v1beta1"
16+
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
1317
"k8s.io/apimachinery/pkg/runtime"
1418
"k8s.io/apimachinery/pkg/types"
1519
"k8s.io/client-go/rest"
@@ -20,6 +24,12 @@ import (
2024
"sigs.k8s.io/controller-runtime/pkg/runtime/inject"
2125
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
2226
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
27+
"time"
28+
)
29+
30+
const (
31+
ValidationConfigHashKey = "validation"
32+
DefaultValidationFreqSeconds = 10
2333
)
2434

2535
// +kubebuilder:webhook:path=/validate-v1-spinnakerservice,mutating=false,failurePolicy=fail,groups="",resources=pods,verbs=create;update,versions=v1,name=vpod.kb.io
@@ -65,6 +75,13 @@ func (v *spinnakerValidatingController) Handle(ctx context.Context, req admissio
6575
return admission.ValidationResponse(true, "")
6676
}
6777

78+
hc := svc.GetStatus().GetHash(ValidationConfigHashKey)
79+
if hc != nil {
80+
if !v.NeedsValidation(hc.LastUpdatedAt) {
81+
return admission.Allowed("")
82+
}
83+
}
84+
6885
opts := validate.Options{
6986
Ctx: secrets.NewContext(ctx, v.restConfig, req.Namespace),
7087
Client: v.client,
@@ -86,6 +103,7 @@ func (v *spinnakerValidatingController) Handle(ctx context.Context, req admissio
86103
// Update the status with any admission status change, only if there's already an existing SpinnakerService
87104
if req.AdmissionRequest.Operation == v1beta1.Update {
88105
if len(validationResult.StatusPatches) > 0 {
106+
validationResult.StatusPatches = append(validationResult.StatusPatches, v.addLastValidation(svc))
89107
log.Info(fmt.Sprintf("patching SpinnakerService status with %v", validationResult.StatusPatches), "metadata.name", svc.GetName())
90108
if err := v.client.Status().Patch(ctx, svc, &precomputedPatch{validationResult}); err != nil {
91109
return admission.Errored(http.StatusInternalServerError, err)
@@ -96,6 +114,31 @@ func (v *spinnakerValidatingController) Handle(ctx context.Context, req admissio
96114
return admission.ValidationResponse(true, "")
97115
}
98116

117+
func (v *spinnakerValidatingController) NeedsValidation(lastValid metav1.Time) bool {
118+
if lastValid.IsZero() {
119+
return true
120+
}
121+
n := lastValid.Time.Add(time.Duration(DefaultValidationFreqSeconds) * time.Second)
122+
return time.Now().After(n)
123+
}
124+
125+
func (v *spinnakerValidatingController) getHash(config interface{}) (string, error) {
126+
data, err := json.Marshal(config)
127+
if err != nil {
128+
return "", err
129+
}
130+
m := md5.Sum(data)
131+
return hex.EncodeToString(m[:]), nil
132+
}
133+
134+
func (v *spinnakerValidatingController) addLastValidation(svc interfaces.SpinnakerService) jsonpatch.JsonPatchOperation {
135+
hash, _ := v.getHash(svc.GetStatus())
136+
return jsonpatch.NewPatch("replace", fmt.Sprintf("/status/lastDeployed/%s", ValidationConfigHashKey), interfaces.HashStatus{
137+
Hash: hash,
138+
LastUpdatedAt: metav1.NewTime(time.Now()),
139+
})
140+
}
141+
99142
// InjectClient injects the client.
100143
func (v *spinnakerValidatingController) InjectClient(c client.Client) error {
101144
v.client = c

pkg/halyard/validators.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ var validationsToSkip = []string{
1515
"KubernetesAccountValidator",
1616
"DeploymentConfigurationValidator",
1717
"DockerRegistryAccountValidator",
18+
"AwsAccountValidator",
1819
}
1920

2021
type validationEnableRule struct {

0 commit comments

Comments
 (0)