| ... | ... |
@@ -230,6 +230,19 @@ message DeploymentLogOptions {
|
| 230 | 230 |
optional int64 version = 10; |
| 231 | 231 |
} |
| 232 | 232 |
|
| 233 |
+// DeploymentRequest is a request to a deployment config for a new deployment. |
|
| 234 |
+message DeploymentRequest {
|
|
| 235 |
+ // Name of the deployment config for requesting a new deployment. |
|
| 236 |
+ optional string name = 1; |
|
| 237 |
+ |
|
| 238 |
+ // Latest will update the deployment config with the latest state from all triggers. |
|
| 239 |
+ optional bool latest = 2; |
|
| 240 |
+ |
|
| 241 |
+ // Force will try to force a new deployment to run. If the deployment config is paused, |
|
| 242 |
+ // then setting this to true will return an Invalid error. |
|
| 243 |
+ optional bool force = 3; |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 233 | 246 |
// DeploymentStrategy describes how to perform a deployment. |
| 234 | 247 |
message DeploymentStrategy {
|
| 235 | 248 |
// Type is the name of a deployment strategy. |
| ... | ... |
@@ -6258,6 +6258,67 @@ |
| 6258 | 6258 |
] |
| 6259 | 6259 |
}, |
| 6260 | 6260 |
{
|
| 6261 |
+ "path": "/oapi/v1/namespaces/{namespace}/deploymentconfigs/{name}/instantiate",
|
|
| 6262 |
+ "description": "OpenShift REST API, version v1", |
|
| 6263 |
+ "operations": [ |
|
| 6264 |
+ {
|
|
| 6265 |
+ "type": "v1.DeploymentRequest", |
|
| 6266 |
+ "method": "POST", |
|
| 6267 |
+ "summary": "create instantiate of a DeploymentRequest", |
|
| 6268 |
+ "nickname": "createNamespacedDeploymentRequestInstantiate", |
|
| 6269 |
+ "parameters": [ |
|
| 6270 |
+ {
|
|
| 6271 |
+ "type": "string", |
|
| 6272 |
+ "paramType": "query", |
|
| 6273 |
+ "name": "pretty", |
|
| 6274 |
+ "description": "If 'true', then the output is pretty printed.", |
|
| 6275 |
+ "required": false, |
|
| 6276 |
+ "allowMultiple": false |
|
| 6277 |
+ }, |
|
| 6278 |
+ {
|
|
| 6279 |
+ "type": "v1.DeploymentRequest", |
|
| 6280 |
+ "paramType": "body", |
|
| 6281 |
+ "name": "body", |
|
| 6282 |
+ "description": "", |
|
| 6283 |
+ "required": true, |
|
| 6284 |
+ "allowMultiple": false |
|
| 6285 |
+ }, |
|
| 6286 |
+ {
|
|
| 6287 |
+ "type": "string", |
|
| 6288 |
+ "paramType": "path", |
|
| 6289 |
+ "name": "namespace", |
|
| 6290 |
+ "description": "object name and auth scope, such as for teams and projects", |
|
| 6291 |
+ "required": true, |
|
| 6292 |
+ "allowMultiple": false |
|
| 6293 |
+ }, |
|
| 6294 |
+ {
|
|
| 6295 |
+ "type": "string", |
|
| 6296 |
+ "paramType": "path", |
|
| 6297 |
+ "name": "name", |
|
| 6298 |
+ "description": "name of the DeploymentRequest", |
|
| 6299 |
+ "required": true, |
|
| 6300 |
+ "allowMultiple": false |
|
| 6301 |
+ } |
|
| 6302 |
+ ], |
|
| 6303 |
+ "responseMessages": [ |
|
| 6304 |
+ {
|
|
| 6305 |
+ "code": 200, |
|
| 6306 |
+ "message": "OK", |
|
| 6307 |
+ "responseModel": "v1.DeploymentRequest" |
|
| 6308 |
+ } |
|
| 6309 |
+ ], |
|
| 6310 |
+ "produces": [ |
|
| 6311 |
+ "application/json", |
|
| 6312 |
+ "application/yaml", |
|
| 6313 |
+ "application/vnd.kubernetes.protobuf" |
|
| 6314 |
+ ], |
|
| 6315 |
+ "consumes": [ |
|
| 6316 |
+ "*/*" |
|
| 6317 |
+ ] |
|
| 6318 |
+ } |
|
| 6319 |
+ ] |
|
| 6320 |
+ }, |
|
| 6321 |
+ {
|
|
| 6261 | 6322 |
"path": "/oapi/v1/namespaces/{namespace}/deploymentconfigs/{name}/log",
|
| 6262 | 6323 |
"description": "OpenShift REST API, version v1", |
| 6263 | 6324 |
"operations": [ |
| ... | ... |
@@ -24620,6 +24681,37 @@ |
| 24620 | 24620 |
} |
| 24621 | 24621 |
} |
| 24622 | 24622 |
}, |
| 24623 |
+ "v1.DeploymentRequest": {
|
|
| 24624 |
+ "id": "v1.DeploymentRequest", |
|
| 24625 |
+ "description": "DeploymentRequest is a request to a deployment config for a new deployment.", |
|
| 24626 |
+ "required": [ |
|
| 24627 |
+ "name", |
|
| 24628 |
+ "latest", |
|
| 24629 |
+ "force" |
|
| 24630 |
+ ], |
|
| 24631 |
+ "properties": {
|
|
| 24632 |
+ "kind": {
|
|
| 24633 |
+ "type": "string", |
|
| 24634 |
+ "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/release-1.4/docs/devel/api-conventions.md#types-kinds" |
|
| 24635 |
+ }, |
|
| 24636 |
+ "apiVersion": {
|
|
| 24637 |
+ "type": "string", |
|
| 24638 |
+ "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/release-1.4/docs/devel/api-conventions.md#resources" |
|
| 24639 |
+ }, |
|
| 24640 |
+ "name": {
|
|
| 24641 |
+ "type": "string", |
|
| 24642 |
+ "description": "Name of the deployment config for requesting a new deployment." |
|
| 24643 |
+ }, |
|
| 24644 |
+ "latest": {
|
|
| 24645 |
+ "type": "boolean", |
|
| 24646 |
+ "description": "Latest will update the deployment config with the latest state from all triggers." |
|
| 24647 |
+ }, |
|
| 24648 |
+ "force": {
|
|
| 24649 |
+ "type": "boolean", |
|
| 24650 |
+ "description": "Force will try to force a new deployment to run. If the deployment config is paused, then setting this to true will return an Invalid error." |
|
| 24651 |
+ } |
|
| 24652 |
+ } |
|
| 24653 |
+ }, |
|
| 24623 | 24654 |
"v1.DeploymentLog": {
|
| 24624 | 24655 |
"id": "v1.DeploymentLog", |
| 24625 | 24656 |
"description": "DeploymentLog represents the logs for a deployment", |
| ... | ... |
@@ -32199,6 +32199,64 @@ |
| 32199 | 32199 |
} |
| 32200 | 32200 |
] |
| 32201 | 32201 |
}, |
| 32202 |
+ "/oapi/v1/namespaces/{namespace}/deploymentconfigs/{name}/instantiate": {
|
|
| 32203 |
+ "post": {
|
|
| 32204 |
+ "description": "create instantiate of a DeploymentRequest", |
|
| 32205 |
+ "consumes": [ |
|
| 32206 |
+ "*/*" |
|
| 32207 |
+ ], |
|
| 32208 |
+ "produces": [ |
|
| 32209 |
+ "application/json", |
|
| 32210 |
+ "application/yaml", |
|
| 32211 |
+ "application/vnd.kubernetes.protobuf" |
|
| 32212 |
+ ], |
|
| 32213 |
+ "schemes": [ |
|
| 32214 |
+ "https" |
|
| 32215 |
+ ], |
|
| 32216 |
+ "operationId": "createNamespacedDeploymentRequestInstantiate", |
|
| 32217 |
+ "responses": {
|
|
| 32218 |
+ "200": {
|
|
| 32219 |
+ "description": "OK", |
|
| 32220 |
+ "schema": {
|
|
| 32221 |
+ "$ref": "#/definitions/v1.DeploymentRequest" |
|
| 32222 |
+ } |
|
| 32223 |
+ } |
|
| 32224 |
+ } |
|
| 32225 |
+ }, |
|
| 32226 |
+ "parameters": [ |
|
| 32227 |
+ {
|
|
| 32228 |
+ "name": "body", |
|
| 32229 |
+ "in": "body", |
|
| 32230 |
+ "required": true, |
|
| 32231 |
+ "schema": {
|
|
| 32232 |
+ "$ref": "#/definitions/v1.DeploymentRequest" |
|
| 32233 |
+ } |
|
| 32234 |
+ }, |
|
| 32235 |
+ {
|
|
| 32236 |
+ "uniqueItems": true, |
|
| 32237 |
+ "type": "string", |
|
| 32238 |
+ "description": "name of the DeploymentRequest", |
|
| 32239 |
+ "name": "name", |
|
| 32240 |
+ "in": "path", |
|
| 32241 |
+ "required": true |
|
| 32242 |
+ }, |
|
| 32243 |
+ {
|
|
| 32244 |
+ "uniqueItems": true, |
|
| 32245 |
+ "type": "string", |
|
| 32246 |
+ "description": "object name and auth scope, such as for teams and projects", |
|
| 32247 |
+ "name": "namespace", |
|
| 32248 |
+ "in": "path", |
|
| 32249 |
+ "required": true |
|
| 32250 |
+ }, |
|
| 32251 |
+ {
|
|
| 32252 |
+ "uniqueItems": true, |
|
| 32253 |
+ "type": "string", |
|
| 32254 |
+ "description": "If 'true', then the output is pretty printed.", |
|
| 32255 |
+ "name": "pretty", |
|
| 32256 |
+ "in": "query" |
|
| 32257 |
+ } |
|
| 32258 |
+ ] |
|
| 32259 |
+ }, |
|
| 32202 | 32260 |
"/oapi/v1/namespaces/{namespace}/deploymentconfigs/{name}/log": {
|
| 32203 | 32261 |
"get": {
|
| 32204 | 32262 |
"description": "read log of the specified DeploymentLog", |
| ... | ... |
@@ -46200,6 +46258,36 @@ |
| 46200 | 46200 |
} |
| 46201 | 46201 |
} |
| 46202 | 46202 |
}, |
| 46203 |
+ "v1.DeploymentRequest": {
|
|
| 46204 |
+ "description": "DeploymentRequest is a request to a deployment config for a new deployment.", |
|
| 46205 |
+ "required": [ |
|
| 46206 |
+ "name", |
|
| 46207 |
+ "latest", |
|
| 46208 |
+ "force" |
|
| 46209 |
+ ], |
|
| 46210 |
+ "properties": {
|
|
| 46211 |
+ "apiVersion": {
|
|
| 46212 |
+ "description": "APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: http://releases.k8s.io/release-1.4/docs/devel/api-conventions.md#resources", |
|
| 46213 |
+ "type": "string" |
|
| 46214 |
+ }, |
|
| 46215 |
+ "force": {
|
|
| 46216 |
+ "description": "Force will try to force a new deployment to run. If the deployment config is paused, then setting this to true will return an Invalid error.", |
|
| 46217 |
+ "type": "boolean" |
|
| 46218 |
+ }, |
|
| 46219 |
+ "kind": {
|
|
| 46220 |
+ "description": "Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: http://releases.k8s.io/release-1.4/docs/devel/api-conventions.md#types-kinds", |
|
| 46221 |
+ "type": "string" |
|
| 46222 |
+ }, |
|
| 46223 |
+ "latest": {
|
|
| 46224 |
+ "description": "Latest will update the deployment config with the latest state from all triggers.", |
|
| 46225 |
+ "type": "boolean" |
|
| 46226 |
+ }, |
|
| 46227 |
+ "name": {
|
|
| 46228 |
+ "description": "Name of the deployment config for requesting a new deployment.", |
|
| 46229 |
+ "type": "string" |
|
| 46230 |
+ } |
|
| 46231 |
+ } |
|
| 46232 |
+ }, |
|
| 46203 | 46233 |
"v1.DeploymentStrategy": {
|
| 46204 | 46234 |
"description": "DeploymentStrategy describes how to perform a deployment.", |
| 46205 | 46235 |
"properties": {
|
| ... | ... |
@@ -64,6 +64,7 @@ func registerAll() {
|
| 64 | 64 |
Validator.MustRegister(&deployapi.DeploymentConfig{}, deployvalidation.ValidateDeploymentConfig, deployvalidation.ValidateDeploymentConfigUpdate)
|
| 65 | 65 |
Validator.MustRegister(&deployapi.DeploymentConfigRollback{}, deployvalidation.ValidateDeploymentConfigRollback, nil)
|
| 66 | 66 |
Validator.MustRegister(&deployapi.DeploymentLogOptions{}, deployvalidation.ValidateDeploymentLogOptions, nil)
|
| 67 |
+ Validator.MustRegister(&deployapi.DeploymentRequest{}, deployvalidation.ValidateDeploymentRequest, nil)
|
|
| 67 | 68 |
Validator.MustRegister(&extensions.Scale{}, extvalidation.ValidateScale, nil)
|
| 68 | 69 |
|
| 69 | 70 |
Validator.MustRegister(&imageapi.Image{}, imagevalidation.ValidateImage, imagevalidation.ValidateImageUpdate)
|
| ... | ... |
@@ -30,6 +30,7 @@ type DeploymentConfigInterface interface {
|
| 30 | 30 |
GetScale(name string) (*extensions.Scale, error) |
| 31 | 31 |
UpdateScale(scale *extensions.Scale) (*extensions.Scale, error) |
| 32 | 32 |
UpdateStatus(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) |
| 33 |
+ Instantiate(request *deployapi.DeploymentRequest) (*deployapi.DeploymentConfig, error) |
|
| 33 | 34 |
} |
| 34 | 35 |
|
| 35 | 36 |
// deploymentConfigs implements DeploymentConfigsNamespacer interface |
| ... | ... |
@@ -155,6 +156,13 @@ func (c *deploymentConfigs) UpdateStatus(deploymentConfig *deployapi.DeploymentC |
| 155 | 155 |
return |
| 156 | 156 |
} |
| 157 | 157 |
|
| 158 |
+// Instantiate instantiates a new build from build config returning new object or an error |
|
| 159 |
+func (c *deploymentConfigs) Instantiate(request *deployapi.DeploymentRequest) (*deployapi.DeploymentConfig, error) {
|
|
| 160 |
+ result := &deployapi.DeploymentConfig{}
|
|
| 161 |
+ err := c.r.Post().Namespace(c.ns).Resource("deploymentConfigs").Name(request.Name).SubResource("instantiate").Body(request).Do().Into(result)
|
|
| 162 |
+ return result, err |
|
| 163 |
+} |
|
| 164 |
+ |
|
| 158 | 165 |
type updateConfigFunc func(d *deployapi.DeploymentConfig) |
| 159 | 166 |
|
| 160 | 167 |
// UpdateConfigWithRetries will try to update a deployment config and ignore any update conflicts. |
| ... | ... |
@@ -114,3 +114,13 @@ func (c *FakeDeploymentConfigs) UpdateStatus(inObj *deployapi.DeploymentConfig) |
| 114 | 114 |
|
| 115 | 115 |
return obj.(*deployapi.DeploymentConfig), err |
| 116 | 116 |
} |
| 117 |
+ |
|
| 118 |
+func (c *FakeDeploymentConfigs) Instantiate(inObj *deployapi.DeploymentRequest) (*deployapi.DeploymentConfig, error) {
|
|
| 119 |
+ deployment := &deployapi.DeploymentConfig{ObjectMeta: kapi.ObjectMeta{Name: inObj.Name}}
|
|
| 120 |
+ obj, err := c.Fake.Invokes(ktestclient.NewUpdateAction("deploymentconfigs/instantiate", c.Namespace, deployment), deployment)
|
|
| 121 |
+ if obj == nil {
|
|
| 122 |
+ return nil, err |
|
| 123 |
+ } |
|
| 124 |
+ |
|
| 125 |
+ return obj.(*deployapi.DeploymentConfig), err |
|
| 126 |
+} |
| ... | ... |
@@ -245,8 +245,19 @@ func (o DeployOptions) deploy(config *deployapi.DeploymentConfig) error {
|
| 245 | 245 |
return err |
| 246 | 246 |
} |
| 247 | 247 |
|
| 248 |
- config.Status.LatestVersion++ |
|
| 249 |
- dc, err := o.osClient.DeploymentConfigs(config.Namespace).Update(config) |
|
| 248 |
+ request := &deployapi.DeploymentRequest{
|
|
| 249 |
+ Name: config.Name, |
|
| 250 |
+ Latest: false, |
|
| 251 |
+ Force: true, |
|
| 252 |
+ } |
|
| 253 |
+ |
|
| 254 |
+ dc, err := o.osClient.DeploymentConfigs(config.Namespace).Instantiate(request) |
|
| 255 |
+ // Pre 1.4 servers don't support the instantiate endpoint. Fallback to incrementing |
|
| 256 |
+ // latestVersion on them. |
|
| 257 |
+ if kerrors.IsNotFound(err) || kerrors.IsForbidden(err) {
|
|
| 258 |
+ config.Status.LatestVersion++ |
|
| 259 |
+ dc, err = o.osClient.DeploymentConfigs(config.Namespace).Update(config) |
|
| 260 |
+ } |
|
| 250 | 261 |
if err != nil {
|
| 251 | 262 |
return err |
| 252 | 263 |
} |
| ... | ... |
@@ -40,14 +40,14 @@ func TestCmdDeploy_latestOk(t *testing.T) {
|
| 40 | 40 |
} |
| 41 | 41 |
for _, status := range validStatusList {
|
| 42 | 42 |
config := deploytest.OkDeploymentConfig(1) |
| 43 |
- var updatedConfig *deployapi.DeploymentConfig |
|
| 43 |
+ updatedConfig := config |
|
| 44 | 44 |
|
| 45 | 45 |
osClient := &tc.Fake{}
|
| 46 | 46 |
osClient.AddReactor("get", "deploymentconfigs", func(action ktc.Action) (handled bool, ret runtime.Object, err error) {
|
| 47 | 47 |
return true, config, nil |
| 48 | 48 |
}) |
| 49 |
- osClient.AddReactor("update", "deploymentconfigs", func(action ktc.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 50 |
- updatedConfig = action.(ktc.UpdateAction).GetObject().(*deployapi.DeploymentConfig) |
|
| 49 |
+ osClient.AddReactor("update", "deploymentconfigs/instantiate", func(action ktc.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 50 |
+ updatedConfig.Status.LatestVersion++ |
|
| 51 | 51 |
return true, updatedConfig, nil |
| 52 | 52 |
}) |
| 53 | 53 |
|
| ... | ... |
@@ -62,10 +62,7 @@ func TestCmdDeploy_latestOk(t *testing.T) {
|
| 62 | 62 |
t.Fatalf("unexpected error: %v", err)
|
| 63 | 63 |
} |
| 64 | 64 |
|
| 65 |
- if updatedConfig == nil {
|
|
| 66 |
- t.Fatalf("expected updated config")
|
|
| 67 |
- } |
|
| 68 |
- if exp, got := updatedConfig.Status.LatestVersion, int64(2); exp != got {
|
|
| 65 |
+ if exp, got := int64(2), updatedConfig.Status.LatestVersion; exp != got {
|
|
| 69 | 66 |
t.Fatalf("expected deployment config version: %d, got: %d", exp, got)
|
| 70 | 67 |
} |
| 71 | 68 |
} |
| ... | ... |
@@ -51,6 +51,7 @@ var DescriberCoverageExceptions = []reflect.Type{
|
| 51 | 51 |
reflect.TypeOf(&deployapi.DeploymentConfigRollback{}), // normal users don't ever look at these
|
| 52 | 52 |
reflect.TypeOf(&deployapi.DeploymentLog{}), // normal users don't ever look at these
|
| 53 | 53 |
reflect.TypeOf(&deployapi.DeploymentLogOptions{}), // normal users don't ever look at these
|
| 54 |
+ reflect.TypeOf(&deployapi.DeploymentRequest{}), // normal users don't ever look at these
|
|
| 54 | 55 |
reflect.TypeOf(&imageapi.DockerImage{}), // not a top level resource
|
| 55 | 56 |
reflect.TypeOf(&imageapi.ImageStreamImport{}), // normal users don't ever look at these
|
| 56 | 57 |
reflect.TypeOf(&oauthapi.OAuthAccessToken{}), // normal users don't ever look at these
|
| ... | ... |
@@ -30,6 +30,7 @@ var PrinterCoverageExceptions = []reflect.Type{
|
| 30 | 30 |
reflect.TypeOf(&imageapi.ImageStreamImport{}), // normal users don't ever look at these
|
| 31 | 31 |
reflect.TypeOf(&buildapi.BuildLog{}), // just a marker type
|
| 32 | 32 |
reflect.TypeOf(&buildapi.BuildLogOptions{}), // just a marker type
|
| 33 |
+ reflect.TypeOf(&deployapi.DeploymentRequest{}), // normal users don't ever look at these
|
|
| 33 | 34 |
reflect.TypeOf(&deployapi.DeploymentLog{}), // just a marker type
|
| 34 | 35 |
reflect.TypeOf(&deployapi.DeploymentLogOptions{}), // just a marker type
|
| 35 | 36 |
|
| ... | ... |
@@ -251,7 +251,8 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
|
| 251 | 251 |
// access to jenkins. multiple values to ensure that covers relationships |
| 252 | 252 |
authorizationapi.NewRule("admin", "edit", "view").Groups(buildapi.FutureGroupName).Resources("jenkins").RuleOrDie(),
|
| 253 | 253 |
|
| 254 |
- authorizationapi.NewRule(readWrite...).Groups(deployGroup).Resources("deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks", "deploymentconfigs/rollback", "deploymentconfigs/scale").RuleOrDie(),
|
|
| 254 |
+ authorizationapi.NewRule(readWrite...).Groups(deployGroup).Resources("deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigs/scale").RuleOrDie(),
|
|
| 255 |
+ authorizationapi.NewRule("create").Groups(deployGroup).Resources("deploymentconfigrollbacks", "deploymentconfigs/rollback", "deploymentconfigs/instantiate").RuleOrDie(),
|
|
| 255 | 256 |
authorizationapi.NewRule(read...).Groups(deployGroup).Resources("deploymentconfigs/log", "deploymentconfigs/status").RuleOrDie(),
|
| 256 | 257 |
|
| 257 | 258 |
authorizationapi.NewRule(readWrite...).Groups(imageGroup).Resources("imagestreams", "imagestreammappings", "imagestreamtags", "imagestreamimages", "imagestreams/secrets").RuleOrDie(),
|
| ... | ... |
@@ -305,7 +306,8 @@ func GetBootstrapClusterRoles() []authorizationapi.ClusterRole {
|
| 305 | 305 |
// access to jenkins. multiple values to ensure that covers relationships |
| 306 | 306 |
authorizationapi.NewRule("edit", "view").Groups(buildapi.FutureGroupName).Resources("jenkins").RuleOrDie(),
|
| 307 | 307 |
|
| 308 |
- authorizationapi.NewRule(readWrite...).Groups(deployGroup).Resources("deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigrollbacks", "deploymentconfigs/rollback", "deploymentconfigs/scale").RuleOrDie(),
|
|
| 308 |
+ authorizationapi.NewRule(readWrite...).Groups(deployGroup).Resources("deploymentconfigs", "generatedeploymentconfigs", "deploymentconfigs/scale").RuleOrDie(),
|
|
| 309 |
+ authorizationapi.NewRule("create").Groups(deployGroup).Resources("deploymentconfigrollbacks", "deploymentconfigs/rollback", "deploymentconfigs/instantiate").RuleOrDie(),
|
|
| 309 | 310 |
authorizationapi.NewRule(read...).Groups(deployGroup).Resources("deploymentconfigs/log", "deploymentconfigs/status").RuleOrDie(),
|
| 310 | 311 |
|
| 311 | 312 |
authorizationapi.NewRule(readWrite...).Groups(imageGroup).Resources("imagestreams", "imagestreammappings", "imagestreamtags", "imagestreamimages", "imagestreams/secrets").RuleOrDie(),
|
| ... | ... |
@@ -53,6 +53,7 @@ import ( |
| 53 | 53 |
deployconfigetcd "github.com/openshift/origin/pkg/deploy/registry/deployconfig/etcd" |
| 54 | 54 |
deploylogregistry "github.com/openshift/origin/pkg/deploy/registry/deploylog" |
| 55 | 55 |
deployconfiggenerator "github.com/openshift/origin/pkg/deploy/registry/generator" |
| 56 |
+ deployconfiginstantiate "github.com/openshift/origin/pkg/deploy/registry/instantiate" |
|
| 56 | 57 |
deployrollback "github.com/openshift/origin/pkg/deploy/registry/rollback" |
| 57 | 58 |
"github.com/openshift/origin/pkg/dockerregistry" |
| 58 | 59 |
"github.com/openshift/origin/pkg/image/importer" |
| ... | ... |
@@ -498,7 +499,17 @@ func (c *MasterConfig) GetRestStorage() map[string]rest.Storage {
|
| 498 | 498 |
checkStorageErr(err) |
| 499 | 499 |
buildConfigRegistry := buildconfigregistry.NewRegistry(buildConfigStorage) |
| 500 | 500 |
|
| 501 |
- deployConfigStorage, deployConfigStatusStorage, deployConfigScaleStorage, err := deployconfigetcd.NewREST(c.RESTOptionsGetter, c.DeploymentConfigScaleClient()) |
|
| 501 |
+ deployConfigStorage, deployConfigStatusStorage, deployConfigScaleStorage, err := deployconfigetcd.NewREST(c.RESTOptionsGetter) |
|
| 502 |
+ |
|
| 503 |
+ dcInstantiateOriginClient, dcInstantiateKubeClient := c.DeploymentConfigInstantiateClients() |
|
| 504 |
+ dcInstantiateStorage := deployconfiginstantiate.NewREST( |
|
| 505 |
+ *deployConfigStorage.Store, |
|
| 506 |
+ dcInstantiateOriginClient, |
|
| 507 |
+ dcInstantiateKubeClient, |
|
| 508 |
+ c.ExternalVersionCodec, |
|
| 509 |
+ c.AdmissionControl, |
|
| 510 |
+ ) |
|
| 511 |
+ |
|
| 502 | 512 |
checkStorageErr(err) |
| 503 | 513 |
deployConfigRegistry := deployconfigregistry.NewRegistry(deployConfigStorage) |
| 504 | 514 |
|
| ... | ... |
@@ -661,11 +672,12 @@ func (c *MasterConfig) GetRestStorage() map[string]rest.Storage {
|
| 661 | 661 |
"imageStreamMappings": imageStreamMappingStorage, |
| 662 | 662 |
"imageStreamTags": imageStreamTagStorage, |
| 663 | 663 |
|
| 664 |
- "deploymentConfigs": deployConfigStorage, |
|
| 665 |
- "deploymentConfigs/scale": deployConfigScaleStorage, |
|
| 666 |
- "deploymentConfigs/status": deployConfigStatusStorage, |
|
| 667 |
- "deploymentConfigs/rollback": deployConfigRollbackStorage, |
|
| 668 |
- "deploymentConfigs/log": deploylogregistry.NewREST(configClient, kclient, c.DeploymentLogClient(), kubeletClient), |
|
| 664 |
+ "deploymentConfigs": deployConfigStorage, |
|
| 665 |
+ "deploymentConfigs/scale": deployConfigScaleStorage, |
|
| 666 |
+ "deploymentConfigs/status": deployConfigStatusStorage, |
|
| 667 |
+ "deploymentConfigs/rollback": deployConfigRollbackStorage, |
|
| 668 |
+ "deploymentConfigs/log": deploylogregistry.NewREST(configClient, kclient, c.DeploymentLogClient(), kubeletClient), |
|
| 669 |
+ "deploymentConfigs/instantiate": dcInstantiateStorage, |
|
| 669 | 670 |
|
| 670 | 671 |
// TODO: Deprecate these |
| 671 | 672 |
"generateDeploymentConfigs": deployconfiggenerator.NewREST(deployConfigGenerator, c.ExternalVersionCodec), |
| ... | ... |
@@ -787,8 +799,7 @@ func initReadinessCheckRoute(root *restful.WebService, path string, readyFunc fu |
| 787 | 787 |
Produces(restful.MIME_JSON)) |
| 788 | 788 |
} |
| 789 | 789 |
|
| 790 |
-// initHealthCheckRoute initializes an HTTP endpoint for health checking. |
|
| 791 |
-// OpenShift is deemed healthy if the API server can respond with an OK messages |
|
| 790 |
+// initMetricsRoute initializes an HTTP endpoint for metrics. |
|
| 792 | 791 |
func initMetricsRoute(root *restful.WebService, path string) {
|
| 793 | 792 |
h := prometheus.Handler() |
| 794 | 793 |
root.Route(root.GET(path).To(func(req *restful.Request, resp *restful.Response) {
|
| ... | ... |
@@ -898,9 +898,9 @@ func (c *MasterConfig) ImageImportControllerClient() *osclient.Client {
|
| 898 | 898 |
return c.PrivilegedLoopbackOpenShiftClient |
| 899 | 899 |
} |
| 900 | 900 |
|
| 901 |
-// DeploymentConfigScaleClient returns the client used by the Scale subresource registry |
|
| 902 |
-func (c *MasterConfig) DeploymentConfigScaleClient() *kclient.Client {
|
|
| 903 |
- return c.PrivilegedLoopbackKubernetesClient |
|
| 901 |
+// DeploymentConfigInstantiateClients returns the clients used by the instantiate endpoint. |
|
| 902 |
+func (c *MasterConfig) DeploymentConfigInstantiateClients() (*osclient.Client, *kclient.Client) {
|
|
| 903 |
+ return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient |
|
| 904 | 904 |
} |
| 905 | 905 |
|
| 906 | 906 |
// DeploymentControllerClients returns the deployment controller client objects |
| ... | ... |
@@ -922,13 +922,8 @@ func (c *MasterConfig) DeploymentConfigControllerClients() (*osclient.Client, *k |
| 922 | 922 |
return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient |
| 923 | 923 |
} |
| 924 | 924 |
|
| 925 |
-// DeploymentTriggerControllerClients returns the deploymentConfig trigger controller client objects |
|
| 926 |
-func (c *MasterConfig) DeploymentTriggerControllerClients() (*osclient.Client, *kclient.Client) {
|
|
| 927 |
- return c.PrivilegedLoopbackOpenShiftClient, c.PrivilegedLoopbackKubernetesClient |
|
| 928 |
-} |
|
| 929 |
- |
|
| 930 |
-// DeploymentImageChangeTriggerControllerClient returns the deploymentConfig image change controller client object |
|
| 931 |
-func (c *MasterConfig) DeploymentImageChangeTriggerControllerClient() *osclient.Client {
|
|
| 925 |
+// DeploymentTriggerControllerClient returns the deploymentConfig trigger controller client object |
|
| 926 |
+func (c *MasterConfig) DeploymentTriggerControllerClient() *osclient.Client {
|
|
| 932 | 927 |
return c.PrivilegedLoopbackOpenShiftClient |
| 933 | 928 |
} |
| 934 | 929 |
|
| ... | ... |
@@ -15,6 +15,7 @@ import ( |
| 15 | 15 |
"github.com/openshift/origin/pkg/api/validation" |
| 16 | 16 |
otestclient "github.com/openshift/origin/pkg/client/testclient" |
| 17 | 17 |
"github.com/openshift/origin/pkg/controller/shared" |
| 18 |
+ deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 18 | 19 |
quotaapi "github.com/openshift/origin/pkg/quota/api" |
| 19 | 20 |
"github.com/openshift/origin/pkg/quota/controller/clusterquotamapping" |
| 20 | 21 |
"github.com/openshift/origin/pkg/util/restoptions" |
| ... | ... |
@@ -25,6 +26,7 @@ import ( |
| 25 | 25 |
var KnownUpdateValidationExceptions = []reflect.Type{
|
| 26 | 26 |
reflect.TypeOf(&extapi.Scale{}), // scale operation uses the ValidateScale() function for both create and update
|
| 27 | 27 |
reflect.TypeOf("aapi.AppliedClusterResourceQuota{}), // this only retrieved, never created. its a virtual projection of ClusterResourceQuota
|
| 28 |
+ reflect.TypeOf(&deployapi.DeploymentRequest{}), // request for deployments already use ValidateDeploymentRequest()
|
|
| 28 | 29 |
} |
| 29 | 30 |
|
| 30 | 31 |
// TestValidationRegistration makes sure that any RESTStorage that allows create or update has the correct validation register. |
| ... | ... |
@@ -43,7 +43,6 @@ import ( |
| 43 | 43 |
deploycontroller "github.com/openshift/origin/pkg/deploy/controller/deployment" |
| 44 | 44 |
deployconfigcontroller "github.com/openshift/origin/pkg/deploy/controller/deploymentconfig" |
| 45 | 45 |
triggercontroller "github.com/openshift/origin/pkg/deploy/controller/generictrigger" |
| 46 |
- imagechangecontroller "github.com/openshift/origin/pkg/deploy/controller/imagechange" |
|
| 47 | 46 |
"github.com/openshift/origin/pkg/dns" |
| 48 | 47 |
imagecontroller "github.com/openshift/origin/pkg/image/controller" |
| 49 | 48 |
projectcontroller "github.com/openshift/origin/pkg/project/controller" |
| ... | ... |
@@ -356,19 +355,9 @@ func (c *MasterConfig) RunDeploymentConfigController() {
|
| 356 | 356 |
func (c *MasterConfig) RunDeploymentTriggerController() {
|
| 357 | 357 |
dcInfomer := c.Informers.DeploymentConfigs().Informer() |
| 358 | 358 |
streamInformer := c.Informers.ImageStreams().Informer() |
| 359 |
- osclient, kclient := c.DeploymentTriggerControllerClients() |
|
| 359 |
+ osclient := c.DeploymentTriggerControllerClient() |
|
| 360 | 360 |
|
| 361 |
- controller := triggercontroller.NewDeploymentTriggerController(dcInfomer, streamInformer, osclient, kclient, c.ExternalVersionCodec) |
|
| 362 |
- go controller.Run(5, utilwait.NeverStop) |
|
| 363 |
-} |
|
| 364 |
- |
|
| 365 |
-// RunDeploymentImageChangeTriggerController starts the image change trigger controller process. |
|
| 366 |
-func (c *MasterConfig) RunDeploymentImageChangeTriggerController() {
|
|
| 367 |
- dcInfomer := c.Informers.DeploymentConfigs().Informer() |
|
| 368 |
- streamInformer := c.Informers.ImageStreams().Informer() |
|
| 369 |
- osclient, _ := c.DeploymentTriggerControllerClients() |
|
| 370 |
- |
|
| 371 |
- controller := imagechangecontroller.NewImageChangeController(dcInfomer, streamInformer, osclient) |
|
| 361 |
+ controller := triggercontroller.NewDeploymentTriggerController(dcInfomer, streamInformer, osclient, c.ExternalVersionCodec) |
|
| 372 | 362 |
go controller.Run(5, utilwait.NeverStop) |
| 373 | 363 |
} |
| 374 | 364 |
|
| ... | ... |
@@ -713,7 +713,6 @@ func startControllers(oc *origin.MasterConfig, kc *kubernetes.MasterConfig) erro |
| 713 | 713 |
oc.RunDeploymentController() |
| 714 | 714 |
oc.RunDeploymentConfigController() |
| 715 | 715 |
oc.RunDeploymentTriggerController() |
| 716 |
- oc.RunDeploymentImageChangeTriggerController() |
|
| 717 | 716 |
oc.RunImageImportController() |
| 718 | 717 |
oc.RunOriginNamespaceController() |
| 719 | 718 |
oc.RunSDNController() |
| ... | ... |
@@ -49,6 +49,13 @@ func ScaleFromConfig(dc *DeploymentConfig) *extensions.Scale {
|
| 49 | 49 |
} |
| 50 | 50 |
} |
| 51 | 51 |
|
| 52 |
+// RequestForConfig builds a new deployment request for a deployment config. |
|
| 53 |
+func RequestForConfig(dc *DeploymentConfig) *DeploymentRequest {
|
|
| 54 |
+ return &DeploymentRequest{
|
|
| 55 |
+ Name: dc.Name, |
|
| 56 |
+ } |
|
| 57 |
+} |
|
| 58 |
+ |
|
| 52 | 59 |
// TemplateImage is a structure for helping a caller iterate over a PodSpec |
| 53 | 60 |
type TemplateImage struct {
|
| 54 | 61 |
Image string |
| ... | ... |
@@ -32,6 +32,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
| 32 | 32 |
&DeploymentConfig{},
|
| 33 | 33 |
&DeploymentConfigList{},
|
| 34 | 34 |
&DeploymentConfigRollback{},
|
| 35 |
+ &DeploymentRequest{},
|
|
| 35 | 36 |
&DeploymentLog{},
|
| 36 | 37 |
&DeploymentLogOptions{},
|
| 37 | 38 |
) |
| ... | ... |
@@ -41,5 +42,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
| 41 | 41 |
func (obj *DeploymentConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 42 | 42 |
func (obj *DeploymentConfigList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 43 | 43 |
func (obj *DeploymentConfigRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 44 |
+func (obj *DeploymentRequest) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
|
| 44 | 45 |
func (obj *DeploymentLog) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 45 | 46 |
func (obj *DeploymentLogOptions) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| ... | ... |
@@ -1,12 +1,15 @@ |
| 1 | 1 |
package test |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
+ "testing" |
|
| 5 |
+ |
|
| 4 | 6 |
kapi "k8s.io/kubernetes/pkg/api" |
| 5 | 7 |
"k8s.io/kubernetes/pkg/api/resource" |
| 6 | 8 |
"k8s.io/kubernetes/pkg/apis/autoscaling" |
| 7 | 9 |
"k8s.io/kubernetes/pkg/util/sets" |
| 8 | 10 |
|
| 9 | 11 |
deployapi "github.com/openshift/origin/pkg/deploy/api" |
| 12 |
+ deployv1 "github.com/openshift/origin/pkg/deploy/api/v1" |
|
| 10 | 13 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 11 | 14 |
) |
| 12 | 15 |
|
| ... | ... |
@@ -238,6 +241,29 @@ func OkHPAForDeploymentConfig(config *deployapi.DeploymentConfig, min, max int) |
| 238 | 238 |
} |
| 239 | 239 |
} |
| 240 | 240 |
|
| 241 |
+func OkStreamForConfig(config *deployapi.DeploymentConfig) *imageapi.ImageStream {
|
|
| 242 |
+ for _, t := range config.Spec.Triggers {
|
|
| 243 |
+ if t.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 244 |
+ continue |
|
| 245 |
+ } |
|
| 246 |
+ |
|
| 247 |
+ ref := t.ImageChangeParams.From |
|
| 248 |
+ name, tag, _ := imageapi.SplitImageStreamTag(ref.Name) |
|
| 249 |
+ |
|
| 250 |
+ return &imageapi.ImageStream{
|
|
| 251 |
+ ObjectMeta: kapi.ObjectMeta{
|
|
| 252 |
+ Name: name, |
|
| 253 |
+ Namespace: ref.Namespace, |
|
| 254 |
+ }, |
|
| 255 |
+ Status: imageapi.ImageStreamStatus{
|
|
| 256 |
+ Tags: map[string]imageapi.TagEventList{
|
|
| 257 |
+ tag: {
|
|
| 258 |
+ Items: []imageapi.TagEvent{{DockerImageReference: t.ImageChangeParams.LastTriggeredImage}}}}},
|
|
| 259 |
+ } |
|
| 260 |
+ } |
|
| 261 |
+ return nil |
|
| 262 |
+} |
|
| 263 |
+ |
|
| 241 | 264 |
func RemoveTriggerTypes(config *deployapi.DeploymentConfig, triggerTypes ...deployapi.DeploymentTriggerType) {
|
| 242 | 265 |
types := sets.NewString() |
| 243 | 266 |
for _, triggerType := range triggerTypes {
|
| ... | ... |
@@ -254,3 +280,17 @@ func RemoveTriggerTypes(config *deployapi.DeploymentConfig, triggerTypes ...depl |
| 254 | 254 |
|
| 255 | 255 |
config.Spec.Triggers = remaining |
| 256 | 256 |
} |
| 257 |
+ |
|
| 258 |
+func RoundTripConfig(t *testing.T, config *deployapi.DeploymentConfig) *deployapi.DeploymentConfig {
|
|
| 259 |
+ versioned, err := kapi.Scheme.ConvertToVersion(config, deployv1.SchemeGroupVersion) |
|
| 260 |
+ if err != nil {
|
|
| 261 |
+ t.Errorf("unexpected conversion error: %v", err)
|
|
| 262 |
+ return nil |
|
| 263 |
+ } |
|
| 264 |
+ defaulted, err := kapi.Scheme.ConvertToVersion(versioned, deployapi.SchemeGroupVersion) |
|
| 265 |
+ if err != nil {
|
|
| 266 |
+ t.Errorf("unexpected conversion error: %v", err)
|
|
| 267 |
+ return nil |
|
| 268 |
+ } |
|
| 269 |
+ return defaulted.(*deployapi.DeploymentConfig) |
|
| 270 |
+} |
| ... | ... |
@@ -445,6 +445,18 @@ type DeploymentConfigRollbackSpec struct {
|
| 445 | 445 |
IncludeStrategy bool |
| 446 | 446 |
} |
| 447 | 447 |
|
| 448 |
+// DeploymentRequest is a request to a deployment config for a new deployment. |
|
| 449 |
+type DeploymentRequest struct {
|
|
| 450 |
+ unversioned.TypeMeta |
|
| 451 |
+ // Name of the deployment config for requesting a new deployment. |
|
| 452 |
+ Name string |
|
| 453 |
+ // Latest will update the deployment config with the latest state from all triggers. |
|
| 454 |
+ Latest bool |
|
| 455 |
+ // Force will try to force a new deployment to run. If the deployment config is paused, |
|
| 456 |
+ // then setting this to true will return an Invalid error. |
|
| 457 |
+ Force bool |
|
| 458 |
+} |
|
| 459 |
+ |
|
| 448 | 460 |
// DeploymentLog represents the logs for a deployment |
| 449 | 461 |
type DeploymentLog struct {
|
| 450 | 462 |
unversioned.TypeMeta |
| ... | ... |
@@ -21,6 +21,7 @@ |
| 21 | 21 |
DeploymentDetails |
| 22 | 22 |
DeploymentLog |
| 23 | 23 |
DeploymentLogOptions |
| 24 |
+ DeploymentRequest |
|
| 24 | 25 |
DeploymentStrategy |
| 25 | 26 |
DeploymentTriggerImageChangeParams |
| 26 | 27 |
DeploymentTriggerPolicies |
| ... | ... |
@@ -113,51 +114,55 @@ func (m *DeploymentLogOptions) Reset() { *m = DeploymentLogOp
|
| 113 | 113 |
func (*DeploymentLogOptions) ProtoMessage() {}
|
| 114 | 114 |
func (*DeploymentLogOptions) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{11} }
|
| 115 | 115 |
|
| 116 |
+func (m *DeploymentRequest) Reset() { *m = DeploymentRequest{} }
|
|
| 117 |
+func (*DeploymentRequest) ProtoMessage() {}
|
|
| 118 |
+func (*DeploymentRequest) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
|
|
| 119 |
+ |
|
| 116 | 120 |
func (m *DeploymentStrategy) Reset() { *m = DeploymentStrategy{} }
|
| 117 | 121 |
func (*DeploymentStrategy) ProtoMessage() {}
|
| 118 |
-func (*DeploymentStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{12} }
|
|
| 122 |
+func (*DeploymentStrategy) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{13} }
|
|
| 119 | 123 |
|
| 120 | 124 |
func (m *DeploymentTriggerImageChangeParams) Reset() { *m = DeploymentTriggerImageChangeParams{} }
|
| 121 | 125 |
func (*DeploymentTriggerImageChangeParams) ProtoMessage() {}
|
| 122 | 126 |
func (*DeploymentTriggerImageChangeParams) Descriptor() ([]byte, []int) {
|
| 123 |
- return fileDescriptorGenerated, []int{13}
|
|
| 127 |
+ return fileDescriptorGenerated, []int{14}
|
|
| 124 | 128 |
} |
| 125 | 129 |
|
| 126 | 130 |
func (m *DeploymentTriggerPolicies) Reset() { *m = DeploymentTriggerPolicies{} }
|
| 127 | 131 |
func (*DeploymentTriggerPolicies) ProtoMessage() {}
|
| 128 | 132 |
func (*DeploymentTriggerPolicies) Descriptor() ([]byte, []int) {
|
| 129 |
- return fileDescriptorGenerated, []int{14}
|
|
| 133 |
+ return fileDescriptorGenerated, []int{15}
|
|
| 130 | 134 |
} |
| 131 | 135 |
|
| 132 | 136 |
func (m *DeploymentTriggerPolicy) Reset() { *m = DeploymentTriggerPolicy{} }
|
| 133 | 137 |
func (*DeploymentTriggerPolicy) ProtoMessage() {}
|
| 134 | 138 |
func (*DeploymentTriggerPolicy) Descriptor() ([]byte, []int) {
|
| 135 |
- return fileDescriptorGenerated, []int{15}
|
|
| 139 |
+ return fileDescriptorGenerated, []int{16}
|
|
| 136 | 140 |
} |
| 137 | 141 |
|
| 138 | 142 |
func (m *ExecNewPodHook) Reset() { *m = ExecNewPodHook{} }
|
| 139 | 143 |
func (*ExecNewPodHook) ProtoMessage() {}
|
| 140 |
-func (*ExecNewPodHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{16} }
|
|
| 144 |
+func (*ExecNewPodHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{17} }
|
|
| 141 | 145 |
|
| 142 | 146 |
func (m *LifecycleHook) Reset() { *m = LifecycleHook{} }
|
| 143 | 147 |
func (*LifecycleHook) ProtoMessage() {}
|
| 144 |
-func (*LifecycleHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{17} }
|
|
| 148 |
+func (*LifecycleHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{18} }
|
|
| 145 | 149 |
|
| 146 | 150 |
func (m *RecreateDeploymentStrategyParams) Reset() { *m = RecreateDeploymentStrategyParams{} }
|
| 147 | 151 |
func (*RecreateDeploymentStrategyParams) ProtoMessage() {}
|
| 148 | 152 |
func (*RecreateDeploymentStrategyParams) Descriptor() ([]byte, []int) {
|
| 149 |
- return fileDescriptorGenerated, []int{18}
|
|
| 153 |
+ return fileDescriptorGenerated, []int{19}
|
|
| 150 | 154 |
} |
| 151 | 155 |
|
| 152 | 156 |
func (m *RollingDeploymentStrategyParams) Reset() { *m = RollingDeploymentStrategyParams{} }
|
| 153 | 157 |
func (*RollingDeploymentStrategyParams) ProtoMessage() {}
|
| 154 | 158 |
func (*RollingDeploymentStrategyParams) Descriptor() ([]byte, []int) {
|
| 155 |
- return fileDescriptorGenerated, []int{19}
|
|
| 159 |
+ return fileDescriptorGenerated, []int{20}
|
|
| 156 | 160 |
} |
| 157 | 161 |
|
| 158 | 162 |
func (m *TagImageHook) Reset() { *m = TagImageHook{} }
|
| 159 | 163 |
func (*TagImageHook) ProtoMessage() {}
|
| 160 |
-func (*TagImageHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{20} }
|
|
| 164 |
+func (*TagImageHook) Descriptor() ([]byte, []int) { return fileDescriptorGenerated, []int{21} }
|
|
| 161 | 165 |
|
| 162 | 166 |
func init() {
|
| 163 | 167 |
proto.RegisterType((*CustomDeploymentStrategyParams)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.CustomDeploymentStrategyParams") |
| ... | ... |
@@ -172,6 +177,7 @@ func init() {
|
| 172 | 172 |
proto.RegisterType((*DeploymentDetails)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentDetails") |
| 173 | 173 |
proto.RegisterType((*DeploymentLog)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentLog") |
| 174 | 174 |
proto.RegisterType((*DeploymentLogOptions)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentLogOptions") |
| 175 |
+ proto.RegisterType((*DeploymentRequest)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentRequest") |
|
| 175 | 176 |
proto.RegisterType((*DeploymentStrategy)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentStrategy") |
| 176 | 177 |
proto.RegisterType((*DeploymentTriggerImageChangeParams)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentTriggerImageChangeParams") |
| 177 | 178 |
proto.RegisterType((*DeploymentTriggerPolicies)(nil), "github.com.openshift.origin.pkg.deploy.api.v1.DeploymentTriggerPolicies") |
| ... | ... |
@@ -749,6 +755,44 @@ func (m *DeploymentLogOptions) MarshalTo(data []byte) (int, error) {
|
| 749 | 749 |
return i, nil |
| 750 | 750 |
} |
| 751 | 751 |
|
| 752 |
+func (m *DeploymentRequest) Marshal() (data []byte, err error) {
|
|
| 753 |
+ size := m.Size() |
|
| 754 |
+ data = make([]byte, size) |
|
| 755 |
+ n, err := m.MarshalTo(data) |
|
| 756 |
+ if err != nil {
|
|
| 757 |
+ return nil, err |
|
| 758 |
+ } |
|
| 759 |
+ return data[:n], nil |
|
| 760 |
+} |
|
| 761 |
+ |
|
| 762 |
+func (m *DeploymentRequest) MarshalTo(data []byte) (int, error) {
|
|
| 763 |
+ var i int |
|
| 764 |
+ _ = i |
|
| 765 |
+ var l int |
|
| 766 |
+ _ = l |
|
| 767 |
+ data[i] = 0xa |
|
| 768 |
+ i++ |
|
| 769 |
+ i = encodeVarintGenerated(data, i, uint64(len(m.Name))) |
|
| 770 |
+ i += copy(data[i:], m.Name) |
|
| 771 |
+ data[i] = 0x10 |
|
| 772 |
+ i++ |
|
| 773 |
+ if m.Latest {
|
|
| 774 |
+ data[i] = 1 |
|
| 775 |
+ } else {
|
|
| 776 |
+ data[i] = 0 |
|
| 777 |
+ } |
|
| 778 |
+ i++ |
|
| 779 |
+ data[i] = 0x18 |
|
| 780 |
+ i++ |
|
| 781 |
+ if m.Force {
|
|
| 782 |
+ data[i] = 1 |
|
| 783 |
+ } else {
|
|
| 784 |
+ data[i] = 0 |
|
| 785 |
+ } |
|
| 786 |
+ i++ |
|
| 787 |
+ return i, nil |
|
| 788 |
+} |
|
| 789 |
+ |
|
| 752 | 790 |
func (m *DeploymentStrategy) Marshal() (data []byte, err error) {
|
| 753 | 791 |
size := m.Size() |
| 754 | 792 |
data = make([]byte, size) |
| ... | ... |
@@ -1441,6 +1485,16 @@ func (m *DeploymentLogOptions) Size() (n int) {
|
| 1441 | 1441 |
return n |
| 1442 | 1442 |
} |
| 1443 | 1443 |
|
| 1444 |
+func (m *DeploymentRequest) Size() (n int) {
|
|
| 1445 |
+ var l int |
|
| 1446 |
+ _ = l |
|
| 1447 |
+ l = len(m.Name) |
|
| 1448 |
+ n += 1 + l + sovGenerated(uint64(l)) |
|
| 1449 |
+ n += 2 |
|
| 1450 |
+ n += 2 |
|
| 1451 |
+ return n |
|
| 1452 |
+} |
|
| 1453 |
+ |
|
| 1444 | 1454 |
func (m *DeploymentStrategy) Size() (n int) {
|
| 1445 | 1455 |
var l int |
| 1446 | 1456 |
_ = l |
| ... | ... |
@@ -1815,6 +1869,18 @@ func (this *DeploymentLogOptions) String() string {
|
| 1815 | 1815 |
}, "") |
| 1816 | 1816 |
return s |
| 1817 | 1817 |
} |
| 1818 |
+func (this *DeploymentRequest) String() string {
|
|
| 1819 |
+ if this == nil {
|
|
| 1820 |
+ return "nil" |
|
| 1821 |
+ } |
|
| 1822 |
+ s := strings.Join([]string{`&DeploymentRequest{`,
|
|
| 1823 |
+ `Name:` + fmt.Sprintf("%v", this.Name) + `,`,
|
|
| 1824 |
+ `Latest:` + fmt.Sprintf("%v", this.Latest) + `,`,
|
|
| 1825 |
+ `Force:` + fmt.Sprintf("%v", this.Force) + `,`,
|
|
| 1826 |
+ `}`, |
|
| 1827 |
+ }, "") |
|
| 1828 |
+ return s |
|
| 1829 |
+} |
|
| 1818 | 1830 |
func (this *DeploymentStrategy) String() string {
|
| 1819 | 1831 |
if this == nil {
|
| 1820 | 1832 |
return "nil" |
| ... | ... |
@@ -3913,6 +3979,125 @@ func (m *DeploymentLogOptions) Unmarshal(data []byte) error {
|
| 3913 | 3913 |
} |
| 3914 | 3914 |
return nil |
| 3915 | 3915 |
} |
| 3916 |
+func (m *DeploymentRequest) Unmarshal(data []byte) error {
|
|
| 3917 |
+ l := len(data) |
|
| 3918 |
+ iNdEx := 0 |
|
| 3919 |
+ for iNdEx < l {
|
|
| 3920 |
+ preIndex := iNdEx |
|
| 3921 |
+ var wire uint64 |
|
| 3922 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3923 |
+ if shift >= 64 {
|
|
| 3924 |
+ return ErrIntOverflowGenerated |
|
| 3925 |
+ } |
|
| 3926 |
+ if iNdEx >= l {
|
|
| 3927 |
+ return io.ErrUnexpectedEOF |
|
| 3928 |
+ } |
|
| 3929 |
+ b := data[iNdEx] |
|
| 3930 |
+ iNdEx++ |
|
| 3931 |
+ wire |= (uint64(b) & 0x7F) << shift |
|
| 3932 |
+ if b < 0x80 {
|
|
| 3933 |
+ break |
|
| 3934 |
+ } |
|
| 3935 |
+ } |
|
| 3936 |
+ fieldNum := int32(wire >> 3) |
|
| 3937 |
+ wireType := int(wire & 0x7) |
|
| 3938 |
+ if wireType == 4 {
|
|
| 3939 |
+ return fmt.Errorf("proto: DeploymentRequest: wiretype end group for non-group")
|
|
| 3940 |
+ } |
|
| 3941 |
+ if fieldNum <= 0 {
|
|
| 3942 |
+ return fmt.Errorf("proto: DeploymentRequest: illegal tag %d (wire type %d)", fieldNum, wire)
|
|
| 3943 |
+ } |
|
| 3944 |
+ switch fieldNum {
|
|
| 3945 |
+ case 1: |
|
| 3946 |
+ if wireType != 2 {
|
|
| 3947 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Name", wireType)
|
|
| 3948 |
+ } |
|
| 3949 |
+ var stringLen uint64 |
|
| 3950 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3951 |
+ if shift >= 64 {
|
|
| 3952 |
+ return ErrIntOverflowGenerated |
|
| 3953 |
+ } |
|
| 3954 |
+ if iNdEx >= l {
|
|
| 3955 |
+ return io.ErrUnexpectedEOF |
|
| 3956 |
+ } |
|
| 3957 |
+ b := data[iNdEx] |
|
| 3958 |
+ iNdEx++ |
|
| 3959 |
+ stringLen |= (uint64(b) & 0x7F) << shift |
|
| 3960 |
+ if b < 0x80 {
|
|
| 3961 |
+ break |
|
| 3962 |
+ } |
|
| 3963 |
+ } |
|
| 3964 |
+ intStringLen := int(stringLen) |
|
| 3965 |
+ if intStringLen < 0 {
|
|
| 3966 |
+ return ErrInvalidLengthGenerated |
|
| 3967 |
+ } |
|
| 3968 |
+ postIndex := iNdEx + intStringLen |
|
| 3969 |
+ if postIndex > l {
|
|
| 3970 |
+ return io.ErrUnexpectedEOF |
|
| 3971 |
+ } |
|
| 3972 |
+ m.Name = string(data[iNdEx:postIndex]) |
|
| 3973 |
+ iNdEx = postIndex |
|
| 3974 |
+ case 2: |
|
| 3975 |
+ if wireType != 0 {
|
|
| 3976 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Latest", wireType)
|
|
| 3977 |
+ } |
|
| 3978 |
+ var v int |
|
| 3979 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 3980 |
+ if shift >= 64 {
|
|
| 3981 |
+ return ErrIntOverflowGenerated |
|
| 3982 |
+ } |
|
| 3983 |
+ if iNdEx >= l {
|
|
| 3984 |
+ return io.ErrUnexpectedEOF |
|
| 3985 |
+ } |
|
| 3986 |
+ b := data[iNdEx] |
|
| 3987 |
+ iNdEx++ |
|
| 3988 |
+ v |= (int(b) & 0x7F) << shift |
|
| 3989 |
+ if b < 0x80 {
|
|
| 3990 |
+ break |
|
| 3991 |
+ } |
|
| 3992 |
+ } |
|
| 3993 |
+ m.Latest = bool(v != 0) |
|
| 3994 |
+ case 3: |
|
| 3995 |
+ if wireType != 0 {
|
|
| 3996 |
+ return fmt.Errorf("proto: wrong wireType = %d for field Force", wireType)
|
|
| 3997 |
+ } |
|
| 3998 |
+ var v int |
|
| 3999 |
+ for shift := uint(0); ; shift += 7 {
|
|
| 4000 |
+ if shift >= 64 {
|
|
| 4001 |
+ return ErrIntOverflowGenerated |
|
| 4002 |
+ } |
|
| 4003 |
+ if iNdEx >= l {
|
|
| 4004 |
+ return io.ErrUnexpectedEOF |
|
| 4005 |
+ } |
|
| 4006 |
+ b := data[iNdEx] |
|
| 4007 |
+ iNdEx++ |
|
| 4008 |
+ v |= (int(b) & 0x7F) << shift |
|
| 4009 |
+ if b < 0x80 {
|
|
| 4010 |
+ break |
|
| 4011 |
+ } |
|
| 4012 |
+ } |
|
| 4013 |
+ m.Force = bool(v != 0) |
|
| 4014 |
+ default: |
|
| 4015 |
+ iNdEx = preIndex |
|
| 4016 |
+ skippy, err := skipGenerated(data[iNdEx:]) |
|
| 4017 |
+ if err != nil {
|
|
| 4018 |
+ return err |
|
| 4019 |
+ } |
|
| 4020 |
+ if skippy < 0 {
|
|
| 4021 |
+ return ErrInvalidLengthGenerated |
|
| 4022 |
+ } |
|
| 4023 |
+ if (iNdEx + skippy) > l {
|
|
| 4024 |
+ return io.ErrUnexpectedEOF |
|
| 4025 |
+ } |
|
| 4026 |
+ iNdEx += skippy |
|
| 4027 |
+ } |
|
| 4028 |
+ } |
|
| 4029 |
+ |
|
| 4030 |
+ if iNdEx > l {
|
|
| 4031 |
+ return io.ErrUnexpectedEOF |
|
| 4032 |
+ } |
|
| 4033 |
+ return nil |
|
| 4034 |
+} |
|
| 3916 | 4035 |
func (m *DeploymentStrategy) Unmarshal(data []byte) error {
|
| 3917 | 4036 |
l := len(data) |
| 3918 | 4037 |
iNdEx := 0 |
| ... | ... |
@@ -5631,147 +5816,150 @@ var ( |
| 5631 | 5631 |
) |
| 5632 | 5632 |
|
| 5633 | 5633 |
var fileDescriptorGenerated = []byte{
|
| 5634 |
- // 2271 bytes of a gzipped FileDescriptorProto |
|
| 5635 |
- 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x59, 0xcd, 0x6f, 0x24, 0x57, |
|
| 5636 |
- 0x11, 0x77, 0x7b, 0xc6, 0xf6, 0xcc, 0x1b, 0x7f, 0xbe, 0xfd, 0x9a, 0x4c, 0x90, 0x6d, 0x35, 0x49, |
|
| 5637 |
- 0xb4, 0x28, 0xd9, 0x1e, 0xad, 0x01, 0x29, 0xd9, 0xb0, 0x01, 0x8f, 0xe3, 0xcd, 0x3a, 0x8c, 0xd7, |
|
| 5638 |
- 0xce, 0xb3, 0x77, 0x03, 0x41, 0x08, 0xb5, 0x67, 0x9e, 0x67, 0x3b, 0x9e, 0xee, 0x37, 0xf4, 0xc7, |
|
| 5639 |
- 0xec, 0xce, 0x89, 0x95, 0x38, 0x20, 0x84, 0x90, 0x10, 0x48, 0x08, 0x89, 0x4b, 0x4e, 0x5c, 0x90, |
|
| 5640 |
- 0xf8, 0x13, 0x38, 0x70, 0x61, 0x39, 0x11, 0x6e, 0x48, 0xa0, 0x55, 0x58, 0xae, 0xf0, 0x0f, 0x70, |
|
| 5641 |
- 0xa2, 0xde, 0x57, 0x7f, 0x4c, 0xcf, 0x38, 0x3b, 0xb6, 0x73, 0x18, 0xc9, 0xfd, 0xaa, 0xea, 0x57, |
|
| 5642 |
- 0xf5, 0xaa, 0xea, 0xd5, 0xab, 0x7a, 0x46, 0xb7, 0x3b, 0x4e, 0xf8, 0x30, 0x3a, 0xb2, 0x5a, 0xcc, |
|
| 5643 |
- 0xad, 0xb3, 0x1e, 0xf5, 0x82, 0x87, 0xce, 0x71, 0x58, 0x67, 0xbe, 0xd3, 0x71, 0xbc, 0x7a, 0xef, |
|
| 5644 |
- 0xa4, 0x53, 0x6f, 0xd3, 0x5e, 0x97, 0x0d, 0xea, 0x76, 0xcf, 0xa9, 0xf7, 0x6f, 0xd6, 0x3b, 0xd4, |
|
| 5645 |
- 0xa3, 0xbe, 0x1d, 0xd2, 0xb6, 0xd5, 0xf3, 0x59, 0xc8, 0xf0, 0x8d, 0x44, 0xdc, 0x8a, 0xc5, 0x2d, |
|
| 5646 |
- 0x29, 0x6e, 0x81, 0xb8, 0x25, 0xc5, 0x2d, 0x10, 0xb7, 0xfa, 0x37, 0x6b, 0x29, 0xf6, 0x7a, 0x87, |
|
| 5647 |
- 0x75, 0x58, 0x5d, 0xa0, 0x1c, 0x45, 0xc7, 0xe2, 0x4b, 0x7c, 0x88, 0xbf, 0x24, 0x7a, 0xed, 0xeb, |
|
| 5648 |
- 0x27, 0x6f, 0x06, 0x96, 0xc3, 0xea, 0x27, 0xd1, 0x11, 0xf5, 0x3d, 0x1a, 0xd2, 0x40, 0x98, 0xc4, |
|
| 5649 |
- 0x6d, 0x89, 0xbc, 0x3e, 0xf5, 0x03, 0x87, 0x79, 0xb4, 0x3d, 0x6c, 0x54, 0xed, 0x8d, 0xf1, 0x62, |
|
| 5650 |
- 0xf9, 0x2d, 0xd4, 0x6e, 0x8f, 0xe5, 0x0e, 0xea, 0xf4, 0x71, 0x08, 0x7b, 0x02, 0x2d, 0x01, 0x48, |
|
| 5651 |
- 0x1e, 0xd1, 0xd0, 0xce, 0x8b, 0xdf, 0x18, 0x2d, 0xee, 0x47, 0x5e, 0xe8, 0xb8, 0x34, 0xc7, 0x7e, |
|
| 5652 |
- 0x73, 0x34, 0x7b, 0x14, 0x3a, 0xdd, 0xba, 0xe3, 0x85, 0x41, 0xe8, 0x0f, 0x8b, 0x98, 0x7f, 0x31, |
|
| 5653 |
- 0xd0, 0xea, 0x56, 0x14, 0x84, 0xcc, 0x7d, 0x57, 0x38, 0xd3, 0xa5, 0x5e, 0x78, 0x10, 0x72, 0x8e, |
|
| 5654 |
- 0xce, 0x60, 0xdf, 0xf6, 0x6d, 0x37, 0xc0, 0x5f, 0x46, 0x33, 0x8e, 0x6b, 0x77, 0x68, 0xd5, 0x58, |
|
| 5655 |
- 0x37, 0xae, 0x97, 0x1b, 0x0b, 0x4f, 0x9f, 0xad, 0x4d, 0x3d, 0x7f, 0xb6, 0x36, 0xb3, 0xc3, 0x17, |
|
| 5656 |
- 0x89, 0xa4, 0xe1, 0xef, 0xa1, 0x0a, 0xf5, 0xfa, 0x8e, 0xcf, 0x3c, 0x8e, 0x50, 0x9d, 0x5e, 0x2f, |
|
| 5657 |
- 0x5c, 0xaf, 0x6c, 0xbc, 0x62, 0x49, 0x83, 0xac, 0xc4, 0x20, 0x11, 0x37, 0x19, 0x30, 0x6b, 0xdb, |
|
| 5658 |
- 0xeb, 0x3f, 0xb0, 0xfd, 0xc6, 0x25, 0x05, 0x58, 0xd9, 0x4e, 0x00, 0x48, 0x1a, 0x0d, 0xbf, 0x8a, |
|
| 5659 |
- 0xe6, 0x20, 0xa8, 0xae, 0xed, 0xb5, 0xab, 0x05, 0x00, 0x2e, 0x37, 0x2a, 0xc0, 0x3e, 0xb7, 0x25, |
|
| 5660 |
- 0x97, 0x88, 0xa6, 0x99, 0x7f, 0x35, 0xd0, 0x52, 0xb2, 0x8b, 0x2d, 0x3b, 0x0a, 0x28, 0x7e, 0x0b, |
|
| 5661 |
- 0x15, 0xc3, 0x41, 0x4f, 0xdb, 0xfe, 0xaa, 0x52, 0x55, 0x3c, 0x84, 0xb5, 0xff, 0x3d, 0x5b, 0xbb, |
|
| 5662 |
- 0x92, 0xb0, 0x1f, 0x42, 0x5a, 0x75, 0xa8, 0xcf, 0x09, 0x44, 0x88, 0xe0, 0x27, 0x06, 0x9a, 0x17, |
|
| 5663 |
- 0x9b, 0x53, 0x24, 0xd8, 0x94, 0x01, 0x9b, 0x7a, 0xdf, 0x9a, 0x28, 0x2d, 0xad, 0x21, 0x8b, 0x76, |
|
| 5664 |
- 0x52, 0x88, 0x8d, 0x65, 0xb0, 0x65, 0x3e, 0xbd, 0x42, 0x32, 0x1a, 0x4d, 0x0f, 0xbd, 0x7c, 0x8a, |
|
| 5665 |
- 0x38, 0xde, 0x43, 0xc5, 0x63, 0x9f, 0xb9, 0x62, 0x73, 0x95, 0x8d, 0x1b, 0xa7, 0x7b, 0x7b, 0xef, |
|
| 5666 |
- 0xe8, 0x63, 0xda, 0x0a, 0x09, 0x3d, 0xa6, 0x3e, 0xf5, 0x5a, 0xb4, 0x31, 0xaf, 0x7d, 0x71, 0x07, |
|
| 5667 |
- 0x20, 0x88, 0x00, 0x32, 0xff, 0x34, 0x8d, 0x96, 0x53, 0x0a, 0x99, 0x77, 0xec, 0x74, 0xf0, 0x77, |
|
| 5668 |
- 0x50, 0xc9, 0x85, 0xec, 0x6c, 0xdb, 0xa1, 0xad, 0x34, 0x5d, 0x7f, 0x11, 0x4d, 0xbb, 0x20, 0xd3, |
|
| 5669 |
- 0xc0, 0x4a, 0x09, 0x4a, 0xd6, 0x48, 0x8c, 0x86, 0x29, 0x2a, 0x06, 0x3d, 0xda, 0x52, 0x8e, 0xdd, |
|
| 5670 |
- 0x3a, 0xbb, 0x63, 0x85, 0xa1, 0x07, 0x00, 0x95, 0xec, 0x8a, 0x7f, 0x11, 0x01, 0x8f, 0x5d, 0x34, |
|
| 5671 |
- 0x1b, 0x84, 0x76, 0x18, 0x05, 0x90, 0x3d, 0x5c, 0xd1, 0xf6, 0x79, 0x15, 0x09, 0xb0, 0xc6, 0xa2, |
|
| 5672 |
- 0x52, 0x35, 0x2b, 0xbf, 0x89, 0x52, 0x62, 0xfe, 0xc3, 0x40, 0x97, 0x87, 0x45, 0x9a, 0x4e, 0x10, |
|
| 5673 |
- 0xe2, 0xef, 0xe7, 0x1c, 0x59, 0x3f, 0xc5, 0x91, 0xa9, 0x22, 0x64, 0x71, 0x71, 0xe1, 0xcf, 0x65, |
|
| 5674 |
- 0xa5, 0xb3, 0xa4, 0x57, 0x52, 0xde, 0x6c, 0xc3, 0x39, 0x0d, 0xa9, 0x1b, 0xa8, 0xc3, 0xf7, 0xcd, |
|
| 5675 |
- 0x73, 0xee, 0x32, 0x75, 0xd0, 0x39, 0x2a, 0x91, 0xe0, 0xe6, 0x27, 0x05, 0x54, 0x1d, 0x66, 0x25, |
|
| 5676 |
- 0xac, 0xdb, 0x3d, 0xb2, 0x5b, 0x27, 0x78, 0x1d, 0x15, 0x3d, 0xdb, 0xd5, 0xa7, 0x2d, 0x8e, 0xc5, |
|
| 5677 |
- 0x3d, 0x58, 0x23, 0x82, 0x82, 0x7f, 0x6f, 0x20, 0x1c, 0xf5, 0xda, 0xbc, 0x02, 0x6d, 0x7a, 0x1e, |
|
| 5678 |
- 0x03, 0x8f, 0xf1, 0x02, 0xa8, 0x4c, 0xfe, 0xc1, 0x39, 0x4d, 0xd6, 0x76, 0x58, 0xf7, 0x73, 0x1a, |
|
| 5679 |
- 0xb6, 0xbd, 0xd0, 0x1f, 0x34, 0x6a, 0xca, 0x22, 0x9c, 0x67, 0x20, 0x23, 0xcc, 0x82, 0xcc, 0x91, |
|
| 5680 |
- 0x09, 0x2a, 0xf3, 0xe6, 0xdb, 0x17, 0x64, 0xde, 0xb8, 0x44, 0xad, 0x6d, 0xa3, 0x6b, 0x63, 0x2c, |
|
| 5681 |
- 0xc7, 0xcb, 0xa8, 0x70, 0x42, 0x07, 0xd2, 0xb1, 0x84, 0xff, 0x89, 0x2f, 0xa3, 0x99, 0xbe, 0xdd, |
|
| 5682 |
- 0x8d, 0xa8, 0x38, 0x3d, 0x65, 0x22, 0x3f, 0x6e, 0x4d, 0xbf, 0x69, 0x98, 0x7f, 0x2c, 0xa0, 0x2f, |
|
| 5683 |
- 0x9d, 0xa6, 0xfb, 0xc2, 0xeb, 0x06, 0x7e, 0x03, 0x95, 0x7c, 0xda, 0x77, 0x78, 0xb6, 0x0a, 0x73, |
|
| 5684 |
- 0x0a, 0x49, 0xa2, 0x12, 0xb5, 0x4e, 0x62, 0x0e, 0xbc, 0x89, 0x96, 0x1c, 0xaf, 0xd5, 0x8d, 0xda, |
|
| 5685 |
- 0xba, 0x90, 0xc9, 0x83, 0x59, 0x6a, 0x5c, 0x53, 0x42, 0x4b, 0x3b, 0x59, 0x32, 0x19, 0xe6, 0x4f, |
|
| 5686 |
- 0x43, 0x50, 0xb7, 0xd7, 0x05, 0x97, 0x55, 0x8b, 0xa3, 0x21, 0x14, 0x99, 0x0c, 0xf3, 0xe3, 0x07, |
|
| 5687 |
- 0xe8, 0xaa, 0x5a, 0x22, 0xe0, 0x2b, 0xa7, 0x25, 0xbc, 0xcd, 0x8f, 0x54, 0x75, 0x46, 0x20, 0xad, |
|
| 5688 |
- 0x2a, 0xa4, 0xab, 0x3b, 0x23, 0xb9, 0xc8, 0x18, 0xe9, 0x94, 0x69, 0xfa, 0x1e, 0xad, 0xce, 0x8e, |
|
| 5689 |
- 0x34, 0x4d, 0x93, 0xc9, 0x30, 0xbf, 0xf9, 0xdb, 0xd9, 0x7c, 0x05, 0x11, 0x81, 0x63, 0xa8, 0x14, |
|
| 5690 |
- 0x68, 0x50, 0x19, 0xbc, 0xcd, 0x33, 0xe7, 0xa4, 0xd6, 0x96, 0x84, 0x2a, 0x36, 0x28, 0x56, 0x82, |
|
| 5691 |
- 0x7d, 0x54, 0x0a, 0x75, 0x8c, 0x64, 0x95, 0xbe, 0x7b, 0x66, 0x85, 0x2a, 0x78, 0xfb, 0x0c, 0xdc, |
|
| 5692 |
- 0xe5, 0xd0, 0xa0, 0x31, 0xcf, 0x75, 0xc6, 0x21, 0x8e, 0xf5, 0xc8, 0x64, 0x12, 0x3e, 0x95, 0x79, |
|
| 5693 |
- 0x31, 0x93, 0x4e, 0x26, 0xb9, 0x4e, 0x62, 0x0e, 0xdc, 0x44, 0x97, 0x75, 0x62, 0xdd, 0x85, 0x9a, |
|
| 5694 |
- 0xc8, 0xfc, 0x41, 0xd3, 0x71, 0x9d, 0x50, 0xa4, 0xc3, 0x4c, 0xa3, 0x0a, 0x52, 0x97, 0xc9, 0x08, |
|
| 5695 |
- 0x3a, 0x19, 0x29, 0xc5, 0x0b, 0x18, 0xa4, 0x7f, 0xa8, 0x52, 0x20, 0x4e, 0xf5, 0x43, 0x58, 0x23, |
|
| 5696 |
- 0x82, 0x82, 0x5f, 0x43, 0xb3, 0x3d, 0x7e, 0x11, 0xb7, 0x55, 0x54, 0xe3, 0x5b, 0x60, 0x5f, 0xac, |
|
| 5697 |
- 0x12, 0x45, 0xc5, 0x3f, 0x82, 0x50, 0xd1, 0x2e, 0x9c, 0x1c, 0xe6, 0x57, 0xe7, 0x44, 0x75, 0xfb, |
|
| 5698 |
- 0xe0, 0x02, 0xee, 0x37, 0xeb, 0x40, 0x61, 0xca, 0x7a, 0x96, 0x84, 0x4e, 0x2d, 0x93, 0x58, 0x29, |
|
| 5699 |
- 0xfe, 0x10, 0x42, 0xa7, 0xcf, 0x46, 0xe9, 0x45, 0x0e, 0xfa, 0x3e, 0x6b, 0xeb, 0xc3, 0x21, 0x2b, |
|
| 5700 |
- 0x94, 0x88, 0x8f, 0x3e, 0x3f, 0x31, 0x18, 0x4f, 0x70, 0xd7, 0xf1, 0x08, 0xb5, 0xdb, 0x83, 0x03, |
|
| 5701 |
- 0xda, 0x62, 0x5e, 0x3b, 0xa8, 0x96, 0x85, 0xb3, 0xe3, 0x04, 0xdf, 0xcd, 0x92, 0xc9, 0x30, 0x7f, |
|
| 5702 |
- 0xed, 0x6d, 0xb4, 0x90, 0xd9, 0xc8, 0x44, 0xe5, 0xed, 0x57, 0x45, 0x74, 0x75, 0xf4, 0x95, 0x8c, |
|
| 5703 |
- 0x01, 0x97, 0x9b, 0x18, 0x84, 0x0f, 0xe4, 0xd5, 0x29, 0x00, 0x0b, 0x8d, 0x2b, 0xca, 0xb0, 0x85, |
|
| 5704 |
- 0x66, 0x9a, 0x48, 0xb2, 0xbc, 0xf8, 0x7d, 0x84, 0xd9, 0x51, 0x40, 0xfd, 0x3e, 0x6d, 0xbf, 0x27, |
|
| 5705 |
- 0xbb, 0xe4, 0xa4, 0x9c, 0xc5, 0x17, 0xc7, 0x5e, 0x8e, 0x83, 0x8c, 0x90, 0x9a, 0x30, 0x87, 0xc1, |
|
| 5706 |
- 0xa3, 0xea, 0xf2, 0xd1, 0x44, 0x95, 0xbe, 0xb1, 0x47, 0xef, 0x67, 0xc9, 0x64, 0x98, 0x1f, 0xbf, |
|
| 5707 |
- 0x87, 0x56, 0xec, 0xbe, 0xed, 0x74, 0xed, 0xa3, 0x2e, 0x8d, 0x41, 0x66, 0x04, 0xc8, 0x4b, 0x0a, |
|
| 5708 |
- 0x64, 0x65, 0x73, 0x98, 0x81, 0xe4, 0x65, 0xf0, 0x2e, 0xba, 0x14, 0x79, 0x79, 0xa8, 0x59, 0x01, |
|
| 5709 |
- 0xf5, 0xb2, 0x82, 0xba, 0x74, 0x3f, 0xcf, 0x42, 0x46, 0xc9, 0xe1, 0x0e, 0x9a, 0x6b, 0x43, 0x55, |
|
| 5710 |
- 0x74, 0xba, 0x01, 0x9c, 0x02, 0x9e, 0x84, 0xdf, 0x3a, 0xf3, 0x29, 0x78, 0x57, 0xe2, 0xc8, 0xe6, |
|
| 5711 |
- 0x5f, 0x7d, 0x10, 0x8d, 0x6e, 0xfe, 0xce, 0x40, 0x2b, 0x39, 0x5e, 0xfc, 0x15, 0x34, 0xe7, 0xd2, |
|
| 5712 |
- 0x20, 0x48, 0xa6, 0x97, 0x25, 0xb5, 0x83, 0xb9, 0x5d, 0xb9, 0x4c, 0x34, 0x1d, 0x1f, 0xa3, 0xd9, |
|
| 5713 |
- 0x16, 0x3f, 0xba, 0xba, 0x19, 0x79, 0xe7, 0x7c, 0x7d, 0x7e, 0x52, 0x18, 0xc4, 0x27, 0xb4, 0x87, |
|
| 5714 |
- 0x12, 0xdd, 0x5c, 0x42, 0x0b, 0x09, 0x6b, 0x93, 0x75, 0xcc, 0x9f, 0x17, 0xd3, 0xd5, 0x1e, 0x56, |
|
| 5715 |
- 0xf6, 0x7a, 0xb2, 0xfb, 0xa8, 0xa3, 0x32, 0x1c, 0x17, 0xd8, 0x08, 0xa4, 0x95, 0x32, 0x7f, 0x45, |
|
| 5716 |
- 0x81, 0x96, 0xb7, 0x34, 0x81, 0x24, 0x3c, 0xbc, 0x36, 0x1d, 0xc3, 0x3d, 0xcf, 0x1e, 0x89, 0xac, |
|
| 5717 |
- 0x4d, 0xd5, 0xa6, 0x3b, 0x62, 0x95, 0x28, 0x2a, 0xcf, 0xce, 0x1e, 0x2f, 0x7f, 0x2c, 0xd2, 0x37, |
|
| 5718 |
- 0x6f, 0x9c, 0x9d, 0xfb, 0x6a, 0x9d, 0xc4, 0x1c, 0xf8, 0x6b, 0x68, 0x3e, 0x80, 0x1b, 0x8a, 0xea, |
|
| 5719 |
- 0xc3, 0x5e, 0x94, 0x17, 0x3c, 0x1f, 0x5d, 0x0e, 0x52, 0xeb, 0x24, 0xc3, 0x05, 0x53, 0x43, 0x59, |
|
| 5720 |
- 0x7c, 0x1f, 0xc2, 0xa0, 0x2a, 0x12, 0xb1, 0xb2, 0xf1, 0xfa, 0x0b, 0x76, 0xbb, 0x5c, 0xa4, 0xb1, |
|
| 5721 |
- 0xc0, 0x77, 0x79, 0xa0, 0x11, 0x48, 0x02, 0x86, 0x37, 0x10, 0xe2, 0xd3, 0x2f, 0x74, 0xdb, 0x6e, |
|
| 5722 |
- 0x2f, 0x50, 0x55, 0x38, 0x9e, 0x33, 0x0e, 0x63, 0x0a, 0x49, 0x71, 0xe1, 0xd7, 0x51, 0x99, 0x27, |
|
| 5723 |
- 0x44, 0x13, 0xdc, 0x24, 0x13, 0xb1, 0x20, 0x15, 0x1c, 0xea, 0x45, 0x92, 0xd0, 0xb1, 0x85, 0x50, |
|
| 5724 |
- 0x97, 0xdf, 0x06, 0x8d, 0x01, 0x58, 0x28, 0x6a, 0x67, 0xa1, 0xb1, 0xc8, 0xc1, 0x9b, 0xf1, 0x2a, |
|
| 5725 |
- 0x49, 0x71, 0x70, 0xb7, 0x7b, 0xec, 0x91, 0x0d, 0x97, 0x4e, 0x39, 0xeb, 0xf6, 0x7b, 0xec, 0x43, |
|
| 5726 |
- 0x58, 0x25, 0x8a, 0xca, 0xc7, 0x58, 0xb5, 0xc9, 0x2a, 0x12, 0xa0, 0x22, 0x93, 0x75, 0x35, 0xd2, |
|
| 5727 |
- 0x34, 0xf3, 0x6f, 0x73, 0x08, 0xe7, 0xaf, 0x69, 0x7c, 0x2b, 0x33, 0xc9, 0xbe, 0x36, 0x34, 0xc9, |
|
| 5728 |
- 0x5e, 0xcd, 0x4b, 0xa4, 0x46, 0xd9, 0x1f, 0xc3, 0x28, 0xdb, 0x12, 0x53, 0xbe, 0x9c, 0xe9, 0xd5, |
|
| 5729 |
- 0x5d, 0xbe, 0x3b, 0x61, 0x8a, 0x9f, 0xfe, 0x50, 0x20, 0x53, 0x62, 0x2b, 0xa5, 0x86, 0x64, 0x94, |
|
| 5730 |
- 0xe2, 0x9f, 0x19, 0x68, 0xd1, 0xa7, 0x2d, 0x9f, 0x82, 0x90, 0xb2, 0x43, 0x36, 0xd6, 0x7b, 0x13, |
|
| 5731 |
- 0xda, 0x41, 0x14, 0xc8, 0x58, 0x4b, 0x30, 0x58, 0xb2, 0x48, 0x32, 0xaa, 0xc8, 0x90, 0x6a, 0xfc, |
|
| 5732 |
- 0x13, 0x03, 0x2d, 0xf8, 0x70, 0x1e, 0x1c, 0xaf, 0xa3, 0x8c, 0x29, 0x0a, 0x63, 0xee, 0x4d, 0x6a, |
|
| 5733 |
- 0x8c, 0xc4, 0x18, 0x6b, 0xcb, 0x0a, 0xbf, 0x78, 0x48, 0x5a, 0x11, 0xc9, 0xea, 0xc5, 0x2d, 0x54, |
|
| 5734 |
- 0xf6, 0x69, 0xc0, 0x22, 0xbf, 0x45, 0x03, 0x75, 0x54, 0x36, 0x4e, 0xbf, 0xaa, 0x89, 0x62, 0x27, |
|
| 5735 |
- 0xf4, 0x87, 0x91, 0xe3, 0x53, 0xae, 0x35, 0x48, 0x6a, 0x83, 0xa6, 0x42, 0x52, 0xc7, 0xb8, 0x38, |
|
| 5736 |
- 0x42, 0xb3, 0x50, 0x99, 0x69, 0x97, 0x9f, 0x98, 0xc2, 0x19, 0x62, 0x9f, 0xdf, 0x9f, 0xd5, 0x14, |
|
| 5737 |
- 0x78, 0xb2, 0x13, 0x89, 0x73, 0x5e, 0x2e, 0x12, 0xa5, 0x0c, 0xff, 0xd4, 0x40, 0x15, 0x3b, 0x35, |
|
| 5738 |
- 0xe8, 0xc9, 0x56, 0x88, 0x9c, 0x5f, 0x79, 0x6e, 0xb6, 0x8b, 0x9f, 0x91, 0xd2, 0x43, 0x5d, 0x5a, |
|
| 5739 |
- 0x77, 0xed, 0x2d, 0x54, 0x49, 0x99, 0x3c, 0x49, 0xcf, 0x51, 0x7b, 0x07, 0x2d, 0x9f, 0x6b, 0x24, |
|
| 5740 |
- 0xfb, 0xc3, 0x34, 0x32, 0x73, 0x9d, 0xb0, 0x78, 0xcb, 0xd9, 0x7a, 0x68, 0x7b, 0x1d, 0x9d, 0x93, |
|
| 5741 |
- 0x50, 0xf1, 0xed, 0x08, 0x0e, 0x0c, 0xa8, 0x69, 0x09, 0xe0, 0x52, 0x12, 0xd5, 0x4d, 0x4d, 0x20, |
|
| 5742 |
- 0x09, 0x0f, 0x14, 0x85, 0xc5, 0xb8, 0xfc, 0xf3, 0x29, 0x5b, 0x5e, 0x5e, 0x65, 0x79, 0x00, 0xb6, |
|
| 5743 |
- 0x32, 0x14, 0x32, 0xc4, 0x19, 0x4f, 0x81, 0x85, 0x8b, 0x9a, 0x02, 0xa1, 0x81, 0xea, 0xda, 0x81, |
|
| 5744 |
- 0xde, 0x1d, 0x6d, 0x8b, 0xfd, 0x89, 0x53, 0x55, 0x4e, 0x1a, 0xa8, 0x66, 0x8e, 0x83, 0x8c, 0x90, |
|
| 5745 |
- 0x32, 0x7f, 0x69, 0xa0, 0x97, 0xc6, 0x8e, 0x0e, 0xf8, 0x44, 0x3f, 0x75, 0x18, 0x22, 0x9d, 0xee, |
|
| 5746 |
- 0x5c, 0xc8, 0x4c, 0x32, 0x18, 0xfd, 0xe2, 0x71, 0xab, 0xf4, 0x9b, 0x4f, 0xd6, 0xa6, 0x9e, 0xfc, |
|
| 5747 |
- 0x73, 0x7d, 0xca, 0xfc, 0xaf, 0x81, 0xae, 0x8d, 0x91, 0x3d, 0xcf, 0x43, 0xe3, 0xaf, 0xa1, 0x75, |
|
| 5748 |
- 0x71, 0x86, 0x73, 0x41, 0x95, 0xe8, 0x0f, 0xce, 0xbb, 0xb5, 0x5c, 0x92, 0x35, 0xae, 0xf0, 0x5e, |
|
| 5749 |
- 0x30, 0xb7, 0x4c, 0xf2, 0x26, 0x98, 0x9f, 0x41, 0xc1, 0xde, 0x7e, 0x4c, 0x5b, 0xf7, 0xe8, 0x23, |
|
| 5750 |
- 0x18, 0x0e, 0xee, 0x32, 0x76, 0x92, 0x7e, 0x8a, 0x35, 0xc6, 0x3f, 0xc5, 0xe2, 0x2d, 0x54, 0xa0, |
|
| 5751 |
- 0x5e, 0x7f, 0xa2, 0x67, 0xe0, 0x8a, 0x72, 0x59, 0x01, 0xbe, 0x09, 0x97, 0xe6, 0xdd, 0x7c, 0x26, |
|
| 5752 |
- 0x65, 0x45, 0xa6, 0x96, 0x93, 0x6e, 0x3e, 0x93, 0xdf, 0x24, 0xcb, 0x2b, 0x2e, 0x5b, 0xd6, 0x8d, |
|
| 5753 |
- 0xf8, 0x91, 0x28, 0x26, 0x86, 0x3e, 0x90, 0x4b, 0x44, 0xd3, 0xcc, 0x3f, 0x4f, 0xa3, 0x85, 0xa6, |
|
| 5754 |
- 0x73, 0x4c, 0x5b, 0x83, 0x56, 0x97, 0x8a, 0x1d, 0x7e, 0x17, 0x2d, 0x1c, 0x43, 0x2b, 0x10, 0xf9, |
|
| 5755 |
- 0x54, 0x46, 0x56, 0x45, 0xf4, 0xab, 0x5a, 0xeb, 0x9d, 0x34, 0x11, 0x42, 0x5b, 0xcb, 0x88, 0x67, |
|
| 5756 |
- 0xa8, 0x24, 0x8b, 0x84, 0x5d, 0x84, 0x68, 0xec, 0x4e, 0x15, 0xe0, 0xdb, 0x13, 0x06, 0x38, 0x1b, |
|
| 5757 |
- 0x0f, 0xd9, 0x97, 0x24, 0x6b, 0x24, 0xa5, 0x00, 0x77, 0x79, 0xd3, 0xd3, 0x11, 0x91, 0x0e, 0xc4, |
|
| 5758 |
- 0xc3, 0x79, 0x65, 0xe3, 0xed, 0x09, 0xb5, 0x1d, 0x2a, 0x79, 0xa1, 0x2b, 0x2e, 0x45, 0x7a, 0x55, |
|
| 5759 |
- 0x74, 0x4d, 0xea, 0x4f, 0xf3, 0x3f, 0xd3, 0x68, 0xfd, 0xf3, 0x2e, 0x66, 0x5e, 0xaf, 0x78, 0x57, |
|
| 5760 |
- 0xc6, 0xa2, 0x50, 0x77, 0x93, 0x72, 0x42, 0x13, 0xf5, 0xea, 0x30, 0x43, 0x21, 0x43, 0x9c, 0x30, |
|
| 5761 |
- 0xd0, 0x16, 0xa0, 0x27, 0x55, 0x6e, 0xfb, 0xc6, 0x84, 0x1b, 0xc9, 0x04, 0xa9, 0x31, 0xc7, 0xf3, |
|
| 5762 |
- 0x0c, 0x5a, 0x5d, 0xc2, 0x11, 0x39, 0xb0, 0xeb, 0xb4, 0x55, 0x1d, 0xbc, 0x00, 0xe0, 0x5d, 0xa7, |
|
| 5763 |
- 0x4d, 0x38, 0x22, 0xfe, 0x08, 0x15, 0x7b, 0x2c, 0x08, 0x55, 0x63, 0x71, 0x3e, 0xe4, 0x12, 0xaf, |
|
| 5764 |
- 0x26, 0xfb, 0x8c, 0xbf, 0x43, 0x70, 0x4c, 0xf3, 0x79, 0x11, 0xad, 0x7d, 0x4e, 0xeb, 0x81, 0x77, |
|
| 5765 |
- 0x60, 0x96, 0x13, 0x73, 0xe2, 0x3e, 0xf5, 0x1d, 0xd6, 0xce, 0xba, 0xfc, 0x9a, 0x98, 0xe3, 0xf2, |
|
| 5766 |
- 0x64, 0x32, 0x4a, 0x06, 0xdf, 0xe6, 0xaf, 0x5a, 0x21, 0x8c, 0xb9, 0x76, 0x57, 0xc3, 0xc8, 0xc9, |
|
| 5767 |
- 0xf8, 0x92, 0x7c, 0xd1, 0xca, 0x90, 0xc8, 0x30, 0xef, 0x88, 0xb8, 0x17, 0x5e, 0x38, 0xee, 0x1f, |
|
| 5768 |
- 0xa3, 0x45, 0xd7, 0x7e, 0x9c, 0x9a, 0x38, 0x95, 0x3f, 0xad, 0x31, 0x65, 0x85, 0xff, 0xbb, 0xcb, |
|
| 5769 |
- 0x92, 0xff, 0xee, 0xb2, 0xc0, 0xb0, 0x3d, 0x1f, 0xbc, 0x02, 0x5e, 0x92, 0xba, 0x76, 0x33, 0x48, |
|
| 5770 |
- 0x64, 0x08, 0x59, 0xfc, 0xaf, 0xc3, 0x7e, 0x7c, 0x10, 0xf9, 0x1d, 0x3d, 0xb4, 0x4c, 0xaa, 0x45, |
|
| 5771 |
- 0xbc, 0x9a, 0xec, 0x2a, 0x0c, 0x12, 0xa3, 0xe9, 0xec, 0x9d, 0xbb, 0xf0, 0xec, 0xd5, 0x49, 0x56, |
|
| 5772 |
- 0xfa, 0x02, 0x92, 0x0c, 0x6e, 0xa6, 0xf9, 0x74, 0x09, 0xc8, 0x97, 0x64, 0x63, 0x82, 0x92, 0xbc, |
|
| 5773 |
- 0x83, 0xa6, 0x43, 0xa6, 0xce, 0xef, 0x84, 0xed, 0x06, 0x52, 0x0a, 0xa6, 0x0f, 0x19, 0x01, 0x90, |
|
| 5774 |
- 0xc6, 0x2b, 0x4f, 0xff, 0xb5, 0x3a, 0xf5, 0x29, 0xfc, 0xfe, 0x0e, 0xbf, 0x27, 0xcf, 0x57, 0x8d, |
|
| 5775 |
- 0xa7, 0xf0, 0xfb, 0x14, 0x7e, 0x9f, 0xc1, 0xef, 0x17, 0xff, 0x5e, 0x9d, 0xfa, 0x68, 0xba, 0x7f, |
|
| 5776 |
- 0xf3, 0xff, 0x01, 0x00, 0x00, 0xff, 0xff, 0x87, 0xa8, 0x15, 0xd6, 0x80, 0x1e, 0x00, 0x00, |
|
| 5634 |
+ // 2309 bytes of a gzipped FileDescriptorProto |
|
| 5635 |
+ 0x1f, 0x8b, 0x08, 0x00, 0x00, 0x09, 0x6e, 0x88, 0x02, 0xff, 0xb4, 0x59, 0xcd, 0x6f, 0x63, 0x49, |
|
| 5636 |
+ 0x11, 0x8f, 0x63, 0x27, 0xb1, 0xdb, 0xf9, 0xec, 0xf9, 0xf2, 0x7a, 0x51, 0x12, 0x3d, 0x76, 0x57, |
|
| 5637 |
+ 0x83, 0x76, 0xe7, 0x59, 0x13, 0x40, 0xda, 0x9d, 0x65, 0x16, 0xe2, 0x6c, 0xb2, 0x93, 0xc5, 0x99, |
|
| 5638 |
+ 0x64, 0x3b, 0x99, 0x59, 0x58, 0x84, 0xd0, 0x8b, 0xdd, 0xf6, 0xbc, 0x8d, 0xdf, 0x6b, 0xf3, 0x3e, |
|
| 5639 |
+ 0x3c, 0xe3, 0x13, 0x23, 0x38, 0x20, 0x84, 0x90, 0x10, 0x48, 0x08, 0x89, 0xcb, 0x9e, 0xb8, 0x20, |
|
| 5640 |
+ 0xf1, 0x27, 0x70, 0xe0, 0xc2, 0x70, 0x62, 0xb9, 0x21, 0x81, 0x46, 0xc3, 0x70, 0x85, 0x7f, 0x80, |
|
| 5641 |
+ 0x13, 0xd5, 0x5f, 0xef, 0xc3, 0xcf, 0xce, 0x8c, 0x93, 0x70, 0xb0, 0x94, 0xd7, 0x55, 0xf5, 0xab, |
|
| 5642 |
+ 0xea, 0xaa, 0xea, 0xea, 0xaa, 0x0e, 0xba, 0xdd, 0xb1, 0x83, 0x07, 0xe1, 0xb1, 0xd9, 0x64, 0x4e, |
|
| 5643 |
+ 0x8d, 0xf5, 0xa8, 0xeb, 0x3f, 0xb0, 0xdb, 0x41, 0x8d, 0x79, 0x76, 0xc7, 0x76, 0x6b, 0xbd, 0x93, |
|
| 5644 |
+ 0x4e, 0xad, 0x45, 0x7b, 0x5d, 0x36, 0xa8, 0x59, 0x3d, 0xbb, 0xd6, 0xbf, 0x59, 0xeb, 0x50, 0x97, |
|
| 5645 |
+ 0x7a, 0x56, 0x40, 0x5b, 0x66, 0xcf, 0x63, 0x01, 0xc3, 0x37, 0x62, 0x71, 0x33, 0x12, 0x37, 0xa5, |
|
| 5646 |
+ 0xb8, 0x09, 0xe2, 0xa6, 0x14, 0x37, 0x41, 0xdc, 0xec, 0xdf, 0xac, 0x26, 0xd8, 0x6b, 0x1d, 0xd6, |
|
| 5647 |
+ 0x61, 0x35, 0x81, 0x72, 0x1c, 0xb6, 0xc5, 0x97, 0xf8, 0x10, 0x7f, 0x49, 0xf4, 0xea, 0x57, 0x4f, |
|
| 5648 |
+ 0xde, 0xf6, 0x4d, 0x9b, 0xd5, 0x4e, 0xc2, 0x63, 0xea, 0xb9, 0x34, 0xa0, 0xbe, 0x30, 0x89, 0xdb, |
|
| 5649 |
+ 0x12, 0xba, 0x7d, 0xea, 0xf9, 0x36, 0x73, 0x69, 0x6b, 0xd8, 0xa8, 0xea, 0x5b, 0xe3, 0xc5, 0xb2, |
|
| 5650 |
+ 0x5b, 0xa8, 0xde, 0x1e, 0xcb, 0xed, 0xd7, 0xe8, 0xa3, 0x00, 0xf6, 0x04, 0x5a, 0x7c, 0x90, 0x3c, |
|
| 5651 |
+ 0xa6, 0x81, 0x95, 0x15, 0xbf, 0x31, 0x5a, 0xdc, 0x0b, 0xdd, 0xc0, 0x76, 0x68, 0x86, 0xfd, 0xe6, |
|
| 5652 |
+ 0x68, 0xf6, 0x30, 0xb0, 0xbb, 0x35, 0xdb, 0x0d, 0xfc, 0xc0, 0x1b, 0x16, 0x31, 0xfe, 0x9c, 0x43, |
|
| 5653 |
+ 0xab, 0x5b, 0xa1, 0x1f, 0x30, 0xe7, 0x7d, 0xe1, 0x4c, 0x87, 0xba, 0xc1, 0x61, 0xc0, 0x39, 0x3a, |
|
| 5654 |
+ 0x83, 0x03, 0xcb, 0xb3, 0x1c, 0x1f, 0x7f, 0x11, 0xcd, 0xd8, 0x8e, 0xd5, 0xa1, 0x95, 0xdc, 0x7a, |
|
| 5655 |
+ 0xee, 0x7a, 0xa9, 0xbe, 0xf0, 0xe4, 0xe9, 0xda, 0xd4, 0xf3, 0xa7, 0x6b, 0x33, 0xbb, 0x7c, 0x91, |
|
| 5656 |
+ 0x48, 0x1a, 0xfe, 0x0e, 0x2a, 0x53, 0xb7, 0x6f, 0x7b, 0xcc, 0xe5, 0x08, 0x95, 0xe9, 0xf5, 0xfc, |
|
| 5657 |
+ 0xf5, 0xf2, 0xc6, 0x6b, 0xa6, 0x34, 0xc8, 0x8c, 0x0d, 0x12, 0x71, 0x93, 0x01, 0x33, 0xb7, 0xdd, |
|
| 5658 |
+ 0xfe, 0x7d, 0xcb, 0xab, 0x5f, 0x52, 0x80, 0xe5, 0xed, 0x18, 0x80, 0x24, 0xd1, 0xf0, 0xeb, 0x68, |
|
| 5659 |
+ 0x0e, 0x82, 0xea, 0x58, 0x6e, 0xab, 0x92, 0x07, 0xe0, 0x52, 0xbd, 0x0c, 0xec, 0x73, 0x5b, 0x72, |
|
| 5660 |
+ 0x89, 0x68, 0x9a, 0xf1, 0x97, 0x1c, 0x5a, 0x8a, 0x77, 0xb1, 0x65, 0x85, 0x3e, 0xc5, 0xef, 0xa0, |
|
| 5661 |
+ 0x42, 0x30, 0xe8, 0x69, 0xdb, 0x5f, 0x57, 0xaa, 0x0a, 0x47, 0xb0, 0xf6, 0xdf, 0xa7, 0x6b, 0x57, |
|
| 5662 |
+ 0x62, 0xf6, 0x23, 0x48, 0xab, 0x0e, 0xf5, 0x38, 0x81, 0x08, 0x11, 0xfc, 0x38, 0x87, 0xe6, 0xc5, |
|
| 5663 |
+ 0xe6, 0x14, 0x09, 0x36, 0x95, 0x83, 0x4d, 0x7d, 0x68, 0x4e, 0x94, 0x96, 0xe6, 0x90, 0x45, 0xbb, |
|
| 5664 |
+ 0x09, 0xc4, 0xfa, 0x32, 0xd8, 0x32, 0x9f, 0x5c, 0x21, 0x29, 0x8d, 0x86, 0x8b, 0x5e, 0x3d, 0x45, |
|
| 5665 |
+ 0x1c, 0xef, 0xa3, 0x42, 0xdb, 0x63, 0x8e, 0xd8, 0x5c, 0x79, 0xe3, 0xc6, 0xe9, 0xde, 0xde, 0x3f, |
|
| 5666 |
+ 0xfe, 0x94, 0x36, 0x03, 0x42, 0xdb, 0xd4, 0xa3, 0x6e, 0x93, 0xd6, 0xe7, 0xb5, 0x2f, 0x76, 0x00, |
|
| 5667 |
+ 0x82, 0x08, 0x20, 0xe3, 0x8f, 0xd3, 0x68, 0x39, 0xa1, 0x90, 0xb9, 0x6d, 0xbb, 0x83, 0xbf, 0x85, |
|
| 5668 |
+ 0x8a, 0x0e, 0x64, 0x67, 0xcb, 0x0a, 0x2c, 0xa5, 0xe9, 0xfa, 0xcb, 0x68, 0xda, 0x03, 0x99, 0x3a, |
|
| 5669 |
+ 0x56, 0x4a, 0x50, 0xbc, 0x46, 0x22, 0x34, 0x4c, 0x51, 0xc1, 0xef, 0xd1, 0xa6, 0x72, 0xec, 0xd6, |
|
| 5670 |
+ 0xd9, 0x1d, 0x2b, 0x0c, 0x3d, 0x04, 0xa8, 0x78, 0x57, 0xfc, 0x8b, 0x08, 0x78, 0xec, 0xa0, 0x59, |
|
| 5671 |
+ 0x3f, 0xb0, 0x82, 0xd0, 0x87, 0xec, 0xe1, 0x8a, 0xb6, 0xcf, 0xab, 0x48, 0x80, 0xd5, 0x17, 0x95, |
|
| 5672 |
+ 0xaa, 0x59, 0xf9, 0x4d, 0x94, 0x12, 0xe3, 0xef, 0x39, 0x74, 0x79, 0x58, 0xa4, 0x61, 0xfb, 0x01, |
|
| 5673 |
+ 0xfe, 0x6e, 0xc6, 0x91, 0xb5, 0x53, 0x1c, 0x99, 0x28, 0x42, 0x26, 0x17, 0x17, 0xfe, 0x5c, 0x56, |
|
| 5674 |
+ 0x3a, 0x8b, 0x7a, 0x25, 0xe1, 0xcd, 0x16, 0x9c, 0xd3, 0x80, 0x3a, 0xbe, 0x3a, 0x7c, 0x5f, 0x3f, |
|
| 5675 |
+ 0xe7, 0x2e, 0x13, 0x07, 0x9d, 0xa3, 0x12, 0x09, 0x6e, 0x7c, 0x96, 0x47, 0x95, 0x61, 0x56, 0xc2, |
|
| 5676 |
+ 0xba, 0xdd, 0x63, 0xab, 0x79, 0x82, 0xd7, 0x51, 0xc1, 0xb5, 0x1c, 0x7d, 0xda, 0xa2, 0x58, 0xdc, |
|
| 5677 |
+ 0x85, 0x35, 0x22, 0x28, 0xf8, 0x77, 0x39, 0x84, 0xc3, 0x5e, 0x8b, 0x57, 0xa0, 0x4d, 0xd7, 0x65, |
|
| 5678 |
+ 0xe0, 0x31, 0x5e, 0x00, 0x95, 0xc9, 0xdf, 0x3b, 0xa7, 0xc9, 0xda, 0x0e, 0xf3, 0x5e, 0x46, 0xc3, |
|
| 5679 |
+ 0xb6, 0x1b, 0x78, 0x83, 0x7a, 0x55, 0x59, 0x84, 0xb3, 0x0c, 0x64, 0x84, 0x59, 0x90, 0x39, 0x32, |
|
| 5680 |
+ 0x41, 0x65, 0xde, 0x7c, 0xf3, 0x82, 0xcc, 0x1b, 0x97, 0xa8, 0xd5, 0x6d, 0x74, 0x6d, 0x8c, 0xe5, |
|
| 5681 |
+ 0x78, 0x19, 0xe5, 0x4f, 0xe8, 0x40, 0x3a, 0x96, 0xf0, 0x3f, 0xf1, 0x65, 0x34, 0xd3, 0xb7, 0xba, |
|
| 5682 |
+ 0x21, 0x15, 0xa7, 0xa7, 0x44, 0xe4, 0xc7, 0xad, 0xe9, 0xb7, 0x73, 0xc6, 0x1f, 0xf2, 0xe8, 0x0b, |
|
| 5683 |
+ 0xa7, 0xe9, 0xbe, 0xf0, 0xba, 0x81, 0xdf, 0x42, 0x45, 0x8f, 0xf6, 0x6d, 0x9e, 0xad, 0xc2, 0x9c, |
|
| 5684 |
+ 0x7c, 0x9c, 0xa8, 0x44, 0xad, 0x93, 0x88, 0x03, 0x6f, 0xa2, 0x25, 0xdb, 0x6d, 0x76, 0xc3, 0x96, |
|
| 5685 |
+ 0x2e, 0x64, 0xf2, 0x60, 0x16, 0xeb, 0xd7, 0x94, 0xd0, 0xd2, 0x6e, 0x9a, 0x4c, 0x86, 0xf9, 0x93, |
|
| 5686 |
+ 0x10, 0xd4, 0xe9, 0x75, 0xc1, 0x65, 0x95, 0xc2, 0x68, 0x08, 0x45, 0x26, 0xc3, 0xfc, 0xf8, 0x3e, |
|
| 5687 |
+ 0xba, 0xaa, 0x96, 0x08, 0xf8, 0xca, 0x6e, 0x0a, 0x6f, 0xf3, 0x23, 0x55, 0x99, 0x11, 0x48, 0xab, |
|
| 5688 |
+ 0x0a, 0xe9, 0xea, 0xee, 0x48, 0x2e, 0x32, 0x46, 0x3a, 0x61, 0x9a, 0xbe, 0x47, 0x2b, 0xb3, 0x23, |
|
| 5689 |
+ 0x4d, 0xd3, 0x64, 0x32, 0xcc, 0x6f, 0xfc, 0x66, 0x36, 0x5b, 0x41, 0x44, 0xe0, 0x18, 0x2a, 0xfa, |
|
| 5690 |
+ 0x1a, 0x54, 0x06, 0x6f, 0xf3, 0xcc, 0x39, 0xa9, 0xb5, 0xc5, 0xa1, 0x8a, 0x0c, 0x8a, 0x94, 0x60, |
|
| 5691 |
+ 0x0f, 0x15, 0x03, 0x1d, 0x23, 0x59, 0xa5, 0xef, 0x9c, 0x59, 0xa1, 0x0a, 0xde, 0x01, 0x03, 0x77, |
|
| 5692 |
+ 0xd9, 0xd4, 0xaf, 0xcf, 0x73, 0x9d, 0x51, 0x88, 0x23, 0x3d, 0x32, 0x99, 0x84, 0x4f, 0x65, 0x5e, |
|
| 5693 |
+ 0xcc, 0x24, 0x93, 0x49, 0xae, 0x93, 0x88, 0x03, 0x37, 0xd0, 0x65, 0x9d, 0x58, 0x77, 0xa0, 0x26, |
|
| 5694 |
+ 0x32, 0x6f, 0xd0, 0xb0, 0x1d, 0x3b, 0x10, 0xe9, 0x30, 0x53, 0xaf, 0x80, 0xd4, 0x65, 0x32, 0x82, |
|
| 5695 |
+ 0x4e, 0x46, 0x4a, 0xf1, 0x02, 0x06, 0xe9, 0x1f, 0xa8, 0x14, 0x88, 0x52, 0xfd, 0x08, 0xd6, 0x88, |
|
| 5696 |
+ 0xa0, 0xe0, 0x37, 0xd0, 0x6c, 0x8f, 0x5f, 0xc4, 0x2d, 0x15, 0xd5, 0xe8, 0x16, 0x38, 0x10, 0xab, |
|
| 5697 |
+ 0x44, 0x51, 0xf1, 0x0f, 0x20, 0x54, 0xb4, 0x0b, 0x27, 0x87, 0x79, 0x95, 0x39, 0x51, 0xdd, 0x3e, |
|
| 5698 |
+ 0xba, 0x80, 0xfb, 0xcd, 0x3c, 0x54, 0x98, 0xb2, 0x9e, 0xc5, 0xa1, 0x53, 0xcb, 0x24, 0x52, 0x8a, |
|
| 5699 |
+ 0x3f, 0x86, 0xd0, 0xe9, 0xb3, 0x51, 0x7c, 0x99, 0x83, 0x7e, 0xc0, 0x5a, 0xfa, 0x70, 0xc8, 0x0a, |
|
| 5700 |
+ 0x25, 0xe2, 0xa3, 0xcf, 0x4f, 0x04, 0xc6, 0x13, 0xdc, 0xb1, 0x5d, 0x42, 0xad, 0xd6, 0xe0, 0x90, |
|
| 5701 |
+ 0x36, 0x99, 0xdb, 0xf2, 0x2b, 0x25, 0xe1, 0xec, 0x28, 0xc1, 0xf7, 0xd2, 0x64, 0x32, 0xcc, 0x5f, |
|
| 5702 |
+ 0x7d, 0x17, 0x2d, 0xa4, 0x36, 0x32, 0x51, 0x79, 0xfb, 0x65, 0x01, 0x5d, 0x1d, 0x7d, 0x25, 0x63, |
|
| 5703 |
+ 0xc0, 0xe5, 0x26, 0xfa, 0xc1, 0x7d, 0x79, 0x75, 0x0a, 0xc0, 0x7c, 0xfd, 0x8a, 0x32, 0x6c, 0xa1, |
|
| 5704 |
+ 0x91, 0x24, 0x92, 0x34, 0x2f, 0xfe, 0x10, 0x61, 0x76, 0xec, 0x53, 0xaf, 0x4f, 0x5b, 0x1f, 0xc8, |
|
| 5705 |
+ 0x2e, 0x39, 0x2e, 0x67, 0xd1, 0xc5, 0xb1, 0x9f, 0xe1, 0x20, 0x23, 0xa4, 0x26, 0xcc, 0x61, 0xf0, |
|
| 5706 |
+ 0xa8, 0xba, 0x7c, 0x34, 0x51, 0xa5, 0x6f, 0xe4, 0xd1, 0x7b, 0x69, 0x32, 0x19, 0xe6, 0xc7, 0x1f, |
|
| 5707 |
+ 0xa0, 0x15, 0xab, 0x6f, 0xd9, 0x5d, 0xeb, 0xb8, 0x4b, 0x23, 0x90, 0x19, 0x01, 0xf2, 0x8a, 0x02, |
|
| 5708 |
+ 0x59, 0xd9, 0x1c, 0x66, 0x20, 0x59, 0x19, 0xbc, 0x87, 0x2e, 0x85, 0x6e, 0x16, 0x6a, 0x56, 0x40, |
|
| 5709 |
+ 0xbd, 0xaa, 0xa0, 0x2e, 0xdd, 0xcb, 0xb2, 0x90, 0x51, 0x72, 0xb8, 0x83, 0xe6, 0x5a, 0x50, 0x15, |
|
| 5710 |
+ 0xed, 0xae, 0x0f, 0xa7, 0x80, 0x27, 0xe1, 0x37, 0xce, 0x7c, 0x0a, 0xde, 0x97, 0x38, 0xb2, 0xf9, |
|
| 5711 |
+ 0x57, 0x1f, 0x44, 0xa3, 0x1b, 0xbf, 0xcd, 0xa1, 0x95, 0x0c, 0x2f, 0xfe, 0x12, 0x9a, 0x73, 0xa8, |
|
| 5712 |
+ 0xef, 0xc7, 0xd3, 0xcb, 0x92, 0xda, 0xc1, 0xdc, 0x9e, 0x5c, 0x26, 0x9a, 0x8e, 0xdb, 0x68, 0xb6, |
|
| 5713 |
+ 0xc9, 0x8f, 0xae, 0x6e, 0x46, 0xde, 0x3b, 0x5f, 0x9f, 0x1f, 0x17, 0x06, 0xf1, 0x09, 0xed, 0xa1, |
|
| 5714 |
+ 0x44, 0x37, 0x96, 0xd0, 0x42, 0xcc, 0xda, 0x60, 0x1d, 0xe3, 0x67, 0x85, 0x64, 0xb5, 0x87, 0x95, |
|
| 5715 |
+ 0xfd, 0x9e, 0xec, 0x3e, 0x6a, 0xa8, 0x04, 0xc7, 0x05, 0x36, 0x02, 0x69, 0xa5, 0xcc, 0x5f, 0x51, |
|
| 5716 |
+ 0xa0, 0xa5, 0x2d, 0x4d, 0x20, 0x31, 0x0f, 0xaf, 0x4d, 0x6d, 0xb8, 0xe7, 0xd9, 0x43, 0x91, 0xb5, |
|
| 5717 |
+ 0x89, 0xda, 0xb4, 0x23, 0x56, 0x89, 0xa2, 0xf2, 0xec, 0xec, 0xf1, 0xf2, 0xc7, 0x42, 0x7d, 0xf3, |
|
| 5718 |
+ 0x46, 0xd9, 0x79, 0xa0, 0xd6, 0x49, 0xc4, 0x81, 0xbf, 0x82, 0xe6, 0x7d, 0xb8, 0xa1, 0xa8, 0x3e, |
|
| 5719 |
+ 0xec, 0x05, 0x79, 0xc1, 0xf3, 0xd1, 0xe5, 0x30, 0xb1, 0x4e, 0x52, 0x5c, 0x30, 0x35, 0x94, 0xc4, |
|
| 5720 |
+ 0xf7, 0x11, 0x0c, 0xaa, 0x22, 0x11, 0xcb, 0x1b, 0x6f, 0xbe, 0x64, 0xb7, 0xcb, 0x45, 0xea, 0x0b, |
|
| 5721 |
+ 0x7c, 0x97, 0x87, 0x1a, 0x81, 0xc4, 0x60, 0x78, 0x03, 0x21, 0x3e, 0xfd, 0x42, 0xb7, 0xed, 0xf4, |
|
| 5722 |
+ 0x7c, 0x55, 0x85, 0xa3, 0x39, 0xe3, 0x28, 0xa2, 0x90, 0x04, 0x17, 0x7e, 0x13, 0x95, 0x78, 0x42, |
|
| 5723 |
+ 0x34, 0xc0, 0x4d, 0x32, 0x11, 0xf3, 0x52, 0xc1, 0x91, 0x5e, 0x24, 0x31, 0x1d, 0x9b, 0x08, 0x75, |
|
| 5724 |
+ 0xf9, 0x6d, 0x50, 0x1f, 0x80, 0x85, 0xa2, 0x76, 0xe6, 0xeb, 0x8b, 0x1c, 0xbc, 0x11, 0xad, 0x92, |
|
| 5725 |
+ 0x04, 0x07, 0x77, 0xbb, 0xcb, 0x1e, 0x5a, 0x70, 0xe9, 0x94, 0xd2, 0x6e, 0xbf, 0xcb, 0x3e, 0x86, |
|
| 5726 |
+ 0x55, 0xa2, 0xa8, 0x7c, 0x8c, 0x55, 0x9b, 0xac, 0x20, 0x01, 0x2a, 0x32, 0x59, 0x57, 0x23, 0x4d, |
|
| 5727 |
+ 0x33, 0x7e, 0x98, 0xca, 0x64, 0x42, 0xbf, 0x1f, 0xf2, 0x7b, 0xe7, 0xc5, 0xad, 0x35, 0x98, 0x21, |
|
| 5728 |
+ 0x0b, 0xda, 0x70, 0xf4, 0x65, 0xd5, 0x23, 0x8a, 0xca, 0xe7, 0xf9, 0x36, 0xf3, 0x9a, 0x54, 0x85, |
|
| 5729 |
+ 0x3e, 0x6a, 0xf3, 0x77, 0xf8, 0x22, 0x91, 0x34, 0xe3, 0xaf, 0x73, 0x08, 0x67, 0x7b, 0x05, 0x7c, |
|
| 5730 |
+ 0x2b, 0x35, 0x4e, 0xbf, 0x31, 0x34, 0x4e, 0x5f, 0xcd, 0x4a, 0x24, 0xe6, 0xe9, 0x1f, 0xc1, 0x3c, |
|
| 5731 |
+ 0xdd, 0x14, 0x4f, 0x0d, 0xf2, 0x61, 0x41, 0x35, 0x14, 0x7b, 0x13, 0x9e, 0xb3, 0xd3, 0x5f, 0x2b, |
|
| 5732 |
+ 0x64, 0x5e, 0x6e, 0x25, 0xd4, 0x90, 0x94, 0x52, 0xfc, 0xd3, 0x1c, 0x5a, 0xf4, 0x68, 0xd3, 0xa3, |
|
| 5733 |
+ 0x20, 0xa4, 0xec, 0x90, 0xdd, 0xfd, 0xfe, 0x84, 0x76, 0x10, 0x05, 0x32, 0xd6, 0x12, 0x0c, 0x96, |
|
| 5734 |
+ 0x2c, 0x92, 0x94, 0x2a, 0x32, 0xa4, 0x1a, 0xff, 0x38, 0x87, 0x16, 0x3c, 0x38, 0x94, 0xb6, 0xdb, |
|
| 5735 |
+ 0x51, 0xc6, 0x14, 0x84, 0x31, 0x77, 0x27, 0x35, 0x46, 0x62, 0x8c, 0xb5, 0x65, 0x85, 0xdf, 0x7e, |
|
| 5736 |
+ 0x24, 0xa9, 0x88, 0xa4, 0xf5, 0xe2, 0x26, 0x2a, 0x79, 0xd4, 0x67, 0x21, 0x04, 0xdf, 0x57, 0xe7, |
|
| 5737 |
+ 0x75, 0xe3, 0xf4, 0x7e, 0x81, 0x28, 0x76, 0x9e, 0xa1, 0xb6, 0x47, 0xb9, 0x56, 0x3f, 0x2e, 0x50, |
|
| 5738 |
+ 0x9a, 0x0a, 0x27, 0x2b, 0xc2, 0xc5, 0x21, 0x4f, 0xd1, 0x63, 0xda, 0xe5, 0xc7, 0x36, 0x7f, 0x86, |
|
| 5739 |
+ 0xd8, 0x67, 0xf7, 0x67, 0x36, 0x04, 0x9e, 0x6c, 0x87, 0x12, 0x19, 0xcf, 0x17, 0x89, 0x52, 0x86, |
|
| 5740 |
+ 0x7f, 0x92, 0x43, 0x65, 0x2b, 0x31, 0x6d, 0xca, 0x7e, 0x8c, 0x9c, 0x5f, 0x79, 0x66, 0xc0, 0x8c, |
|
| 5741 |
+ 0xde, 0xb2, 0x92, 0x93, 0x65, 0x52, 0x77, 0xf5, 0x1d, 0x54, 0x4e, 0x98, 0x3c, 0x49, 0xe3, 0x53, |
|
| 5742 |
+ 0x7d, 0x0f, 0x2d, 0x9f, 0x6b, 0x2e, 0xfc, 0xfd, 0x34, 0x32, 0x32, 0xed, 0xb8, 0x78, 0x50, 0xda, |
|
| 5743 |
+ 0x7a, 0x60, 0xb9, 0x1d, 0x9d, 0x93, 0x70, 0xed, 0x58, 0x21, 0x1c, 0x18, 0x50, 0xd3, 0x14, 0xc0, |
|
| 5744 |
+ 0xc5, 0x38, 0xaa, 0x9b, 0x9a, 0x40, 0x62, 0x1e, 0x28, 0x0a, 0x8b, 0xd1, 0x1d, 0xc4, 0xeb, 0x91, |
|
| 5745 |
+ 0xbc, 0x41, 0x4b, 0xf2, 0x00, 0x6c, 0xa5, 0x28, 0x64, 0x88, 0x33, 0x1a, 0x45, 0xf3, 0x17, 0x35, |
|
| 5746 |
+ 0x8a, 0x42, 0x17, 0xd7, 0xb5, 0x7c, 0xbd, 0x3b, 0xda, 0x12, 0xfb, 0x13, 0xa7, 0xaa, 0x14, 0x77, |
|
| 5747 |
+ 0x71, 0x8d, 0x0c, 0x07, 0x19, 0x21, 0x65, 0xfc, 0x22, 0x87, 0x5e, 0x19, 0x3b, 0xbf, 0xe0, 0x13, |
|
| 5748 |
+ 0xfd, 0xde, 0x92, 0x13, 0xe9, 0xb4, 0x73, 0x21, 0x83, 0xd1, 0x60, 0xf4, 0xb3, 0xcb, 0xad, 0xe2, |
|
| 5749 |
+ 0xaf, 0x3f, 0x5b, 0x9b, 0x7a, 0xfc, 0x8f, 0xf5, 0x29, 0xe3, 0x3f, 0x39, 0x74, 0x6d, 0x8c, 0xec, |
|
| 5750 |
+ 0x79, 0x5e, 0x3b, 0x7f, 0x05, 0xb7, 0x8e, 0x3d, 0x9c, 0x0b, 0xaa, 0x44, 0x7f, 0x74, 0xde, 0xad, |
|
| 5751 |
+ 0x65, 0x92, 0xac, 0x7e, 0x85, 0x37, 0xa4, 0x99, 0x65, 0x92, 0x35, 0xc1, 0x78, 0x06, 0x05, 0x7b, |
|
| 5752 |
+ 0xfb, 0x11, 0x6d, 0xde, 0xa5, 0x0f, 0x61, 0x42, 0xb9, 0xc3, 0xd8, 0x49, 0xf2, 0x3d, 0x38, 0x37, |
|
| 5753 |
+ 0xfe, 0x3d, 0x18, 0x6f, 0xa1, 0x3c, 0x75, 0xfb, 0x13, 0xbd, 0x45, 0x97, 0x95, 0xcb, 0xf2, 0xf0, |
|
| 5754 |
+ 0x4d, 0xb8, 0x34, 0x1f, 0x29, 0x52, 0x29, 0x2b, 0x32, 0xb5, 0x14, 0x8f, 0x14, 0xa9, 0xfc, 0x26, |
|
| 5755 |
+ 0x69, 0x5e, 0x71, 0xe3, 0xb3, 0x6e, 0xc8, 0x8f, 0x44, 0x21, 0x36, 0xf4, 0xbe, 0x5c, 0x22, 0x9a, |
|
| 5756 |
+ 0x66, 0xfc, 0x69, 0x1a, 0x2d, 0x34, 0xec, 0x36, 0x6d, 0x0e, 0x9a, 0x5d, 0x2a, 0x76, 0xf8, 0x6d, |
|
| 5757 |
+ 0xb4, 0xd0, 0x86, 0x7e, 0x24, 0xf4, 0xa8, 0x8c, 0xac, 0x8a, 0xe8, 0x97, 0xb5, 0xd6, 0x9d, 0x24, |
|
| 5758 |
+ 0x11, 0x42, 0x5b, 0x4d, 0x89, 0xa7, 0xa8, 0x24, 0x8d, 0x84, 0x1d, 0x84, 0x68, 0xe4, 0x4e, 0x15, |
|
| 5759 |
+ 0xe0, 0xdb, 0x13, 0x06, 0x38, 0x1d, 0x0f, 0xd9, 0x1c, 0xc5, 0x6b, 0x24, 0xa1, 0x00, 0x77, 0x79, |
|
| 5760 |
+ 0xe7, 0xd5, 0x11, 0x91, 0xf6, 0xc5, 0xeb, 0x7d, 0x79, 0xe3, 0xdd, 0x09, 0xb5, 0x1d, 0x29, 0x79, |
|
| 5761 |
+ 0xa1, 0x2b, 0x2a, 0x45, 0x7a, 0x55, 0xb4, 0x6e, 0xea, 0x4f, 0xe3, 0xdf, 0xd3, 0x68, 0xfd, 0x45, |
|
| 5762 |
+ 0x17, 0x33, 0xaf, 0x57, 0xbc, 0x35, 0x64, 0x61, 0xa0, 0x5b, 0x5a, 0x39, 0x26, 0x8a, 0x7a, 0x75, |
|
| 5763 |
+ 0x94, 0xa2, 0x90, 0x21, 0x4e, 0x98, 0xaa, 0xf3, 0xd0, 0x18, 0x2b, 0xb7, 0x7d, 0x6d, 0xc2, 0x8d, |
|
| 5764 |
+ 0xa4, 0x82, 0x54, 0x9f, 0xe3, 0x79, 0x06, 0xfd, 0x36, 0xe1, 0x88, 0x1c, 0xd8, 0xb1, 0x5b, 0xaa, |
|
| 5765 |
+ 0x0e, 0x5e, 0x00, 0xf0, 0x9e, 0xdd, 0x22, 0x1c, 0x11, 0x7f, 0x82, 0x0a, 0x3d, 0xe6, 0x07, 0xaa, |
|
| 5766 |
+ 0xb1, 0x38, 0x1f, 0x72, 0x91, 0x57, 0x93, 0x03, 0xc6, 0x1f, 0x43, 0x38, 0xa6, 0xf1, 0xbc, 0x80, |
|
| 5767 |
+ 0xd6, 0x5e, 0xd0, 0x7a, 0xe0, 0x5d, 0x18, 0x28, 0xc5, 0xb0, 0x7a, 0x40, 0x3d, 0x9b, 0xb5, 0xd2, |
|
| 5768 |
+ 0x2e, 0xbf, 0x26, 0x86, 0xc9, 0x2c, 0x99, 0x8c, 0x92, 0xc1, 0xb7, 0xf9, 0xd3, 0x5a, 0x00, 0xb3, |
|
| 5769 |
+ 0xb6, 0xd5, 0xd5, 0x30, 0x72, 0x3c, 0xbf, 0x24, 0x9f, 0xd5, 0x52, 0x24, 0x32, 0xcc, 0x3b, 0x22, |
|
| 5770 |
+ 0xee, 0xf9, 0x97, 0x8e, 0xfb, 0xa7, 0x68, 0xd1, 0xb1, 0x1e, 0x25, 0xc6, 0x5e, 0xe5, 0x4f, 0x73, |
|
| 5771 |
+ 0x4c, 0x59, 0xe1, 0xff, 0x73, 0x33, 0xe5, 0xff, 0xdc, 0x4c, 0x30, 0x6c, 0xdf, 0x03, 0xaf, 0x80, |
|
| 5772 |
+ 0x97, 0xa4, 0xae, 0xbd, 0x14, 0x12, 0x19, 0x42, 0x16, 0xff, 0x70, 0xb1, 0x1e, 0x1d, 0x86, 0x5e, |
|
| 5773 |
+ 0x47, 0x4f, 0x4e, 0x93, 0x6a, 0x11, 0x4f, 0x37, 0x7b, 0x0a, 0x83, 0x44, 0x68, 0x3a, 0x7b, 0xe7, |
|
| 5774 |
+ 0x2e, 0x3c, 0x7b, 0x75, 0x92, 0x15, 0xff, 0x0f, 0x49, 0x06, 0x37, 0xd3, 0x7c, 0xb2, 0x04, 0x64, |
|
| 5775 |
+ 0x4b, 0x72, 0x6e, 0x82, 0x92, 0xbc, 0x8b, 0xa6, 0x03, 0xa6, 0xce, 0xef, 0x84, 0xed, 0x06, 0x52, |
|
| 5776 |
+ 0x0a, 0xa6, 0x8f, 0x18, 0x01, 0x90, 0xfa, 0x6b, 0x4f, 0xfe, 0xb9, 0x3a, 0xf5, 0x39, 0xfc, 0xfe, |
|
| 5777 |
+ 0x06, 0xbf, 0xc7, 0xcf, 0x57, 0x73, 0x4f, 0xe0, 0xf7, 0x39, 0xfc, 0x9e, 0xc1, 0xef, 0xe7, 0xff, |
|
| 5778 |
+ 0x5a, 0x9d, 0xfa, 0x64, 0xba, 0x7f, 0xf3, 0x7f, 0x01, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x26, 0x6d, |
|
| 5779 |
+ 0xfd, 0x05, 0x1f, 0x00, 0x00, |
|
| 5777 | 5780 |
} |
| ... | ... |
@@ -230,6 +230,19 @@ message DeploymentLogOptions {
|
| 230 | 230 |
optional int64 version = 10; |
| 231 | 231 |
} |
| 232 | 232 |
|
| 233 |
+// DeploymentRequest is a request to a deployment config for a new deployment. |
|
| 234 |
+message DeploymentRequest {
|
|
| 235 |
+ // Name of the deployment config for requesting a new deployment. |
|
| 236 |
+ optional string name = 1; |
|
| 237 |
+ |
|
| 238 |
+ // Latest will update the deployment config with the latest state from all triggers. |
|
| 239 |
+ optional bool latest = 2; |
|
| 240 |
+ |
|
| 241 |
+ // Force will try to force a new deployment to run. If the deployment config is paused, |
|
| 242 |
+ // then setting this to true will return an Invalid error. |
|
| 243 |
+ optional bool force = 3; |
|
| 244 |
+} |
|
| 245 |
+ |
|
| 233 | 246 |
// DeploymentStrategy describes how to perform a deployment. |
| 234 | 247 |
message DeploymentStrategy {
|
| 235 | 248 |
// Type is the name of a deployment strategy. |
| ... | ... |
@@ -21,6 +21,7 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
| 21 | 21 |
&DeploymentConfig{},
|
| 22 | 22 |
&DeploymentConfigList{},
|
| 23 | 23 |
&DeploymentConfigRollback{},
|
| 24 |
+ &DeploymentRequest{},
|
|
| 24 | 25 |
&DeploymentLog{},
|
| 25 | 26 |
&DeploymentLogOptions{},
|
| 26 | 27 |
) |
| ... | ... |
@@ -30,5 +31,6 @@ func addKnownTypes(scheme *runtime.Scheme) error {
|
| 30 | 30 |
func (obj *DeploymentConfig) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 31 | 31 |
func (obj *DeploymentConfigList) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 32 | 32 |
func (obj *DeploymentConfigRollback) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 33 |
+func (obj *DeploymentRequest) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
|
| 33 | 34 |
func (obj *DeploymentLog) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| 34 | 35 |
func (obj *DeploymentLogOptions) GetObjectKind() unversioned.ObjectKind { return &obj.TypeMeta }
|
| ... | ... |
@@ -149,6 +149,17 @@ func (DeploymentLogOptions) SwaggerDoc() map[string]string {
|
| 149 | 149 |
return map_DeploymentLogOptions |
| 150 | 150 |
} |
| 151 | 151 |
|
| 152 |
+var map_DeploymentRequest = map[string]string{
|
|
| 153 |
+ "": "DeploymentRequest is a request to a deployment config for a new deployment.", |
|
| 154 |
+ "name": "Name of the deployment config for requesting a new deployment.", |
|
| 155 |
+ "latest": "Latest will update the deployment config with the latest state from all triggers.", |
|
| 156 |
+ "force": "Force will try to force a new deployment to run. If the deployment config is paused, then setting this to true will return an Invalid error.", |
|
| 157 |
+} |
|
| 158 |
+ |
|
| 159 |
+func (DeploymentRequest) SwaggerDoc() map[string]string {
|
|
| 160 |
+ return map_DeploymentRequest |
|
| 161 |
+} |
|
| 162 |
+ |
|
| 152 | 163 |
var map_DeploymentStrategy = map[string]string{
|
| 153 | 164 |
"": "DeploymentStrategy describes how to perform a deployment.", |
| 154 | 165 |
"type": "Type is the name of a deployment strategy.", |
| ... | ... |
@@ -421,6 +421,18 @@ type DeploymentConfigRollbackSpec struct {
|
| 421 | 421 |
IncludeStrategy bool `json:"includeStrategy" protobuf:"varint,6,opt,name=includeStrategy"` |
| 422 | 422 |
} |
| 423 | 423 |
|
| 424 |
+// DeploymentRequest is a request to a deployment config for a new deployment. |
|
| 425 |
+type DeploymentRequest struct {
|
|
| 426 |
+ unversioned.TypeMeta `json:",inline"` |
|
| 427 |
+ // Name of the deployment config for requesting a new deployment. |
|
| 428 |
+ Name string `json:"name" protobuf:"bytes,1,opt,name=name"` |
|
| 429 |
+ // Latest will update the deployment config with the latest state from all triggers. |
|
| 430 |
+ Latest bool `json:"latest" protobuf:"varint,2,opt,name=latest"` |
|
| 431 |
+ // Force will try to force a new deployment to run. If the deployment config is paused, |
|
| 432 |
+ // then setting this to true will return an Invalid error. |
|
| 433 |
+ Force bool `json:"force" protobuf:"varint,3,opt,name=force"` |
|
| 434 |
+} |
|
| 435 |
+ |
|
| 424 | 436 |
// DeploymentLog represents the logs for a deployment |
| 425 | 437 |
type DeploymentLog struct {
|
| 426 | 438 |
unversioned.TypeMeta `json:",inline"` |
| ... | ... |
@@ -44,6 +44,8 @@ func RegisterConversions(scheme *runtime.Scheme) error {
|
| 44 | 44 |
Convert_api_DeploymentLog_To_v1_DeploymentLog, |
| 45 | 45 |
Convert_v1_DeploymentLogOptions_To_api_DeploymentLogOptions, |
| 46 | 46 |
Convert_api_DeploymentLogOptions_To_v1_DeploymentLogOptions, |
| 47 |
+ Convert_v1_DeploymentRequest_To_api_DeploymentRequest, |
|
| 48 |
+ Convert_api_DeploymentRequest_To_v1_DeploymentRequest, |
|
| 47 | 49 |
Convert_v1_DeploymentStrategy_To_api_DeploymentStrategy, |
| 48 | 50 |
Convert_api_DeploymentStrategy_To_v1_DeploymentStrategy, |
| 49 | 51 |
Convert_v1_DeploymentTriggerImageChangeParams_To_api_DeploymentTriggerImageChangeParams, |
| ... | ... |
@@ -543,6 +545,34 @@ func Convert_api_DeploymentLogOptions_To_v1_DeploymentLogOptions(in *api.Deploym |
| 543 | 543 |
return autoConvert_api_DeploymentLogOptions_To_v1_DeploymentLogOptions(in, out, s) |
| 544 | 544 |
} |
| 545 | 545 |
|
| 546 |
+func autoConvert_v1_DeploymentRequest_To_api_DeploymentRequest(in *DeploymentRequest, out *api.DeploymentRequest, s conversion.Scope) error {
|
|
| 547 |
+ if err := pkg_api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
|
| 548 |
+ return err |
|
| 549 |
+ } |
|
| 550 |
+ out.Name = in.Name |
|
| 551 |
+ out.Latest = in.Latest |
|
| 552 |
+ out.Force = in.Force |
|
| 553 |
+ return nil |
|
| 554 |
+} |
|
| 555 |
+ |
|
| 556 |
+func Convert_v1_DeploymentRequest_To_api_DeploymentRequest(in *DeploymentRequest, out *api.DeploymentRequest, s conversion.Scope) error {
|
|
| 557 |
+ return autoConvert_v1_DeploymentRequest_To_api_DeploymentRequest(in, out, s) |
|
| 558 |
+} |
|
| 559 |
+ |
|
| 560 |
+func autoConvert_api_DeploymentRequest_To_v1_DeploymentRequest(in *api.DeploymentRequest, out *DeploymentRequest, s conversion.Scope) error {
|
|
| 561 |
+ if err := pkg_api.Convert_unversioned_TypeMeta_To_unversioned_TypeMeta(&in.TypeMeta, &out.TypeMeta, s); err != nil {
|
|
| 562 |
+ return err |
|
| 563 |
+ } |
|
| 564 |
+ out.Name = in.Name |
|
| 565 |
+ out.Latest = in.Latest |
|
| 566 |
+ out.Force = in.Force |
|
| 567 |
+ return nil |
|
| 568 |
+} |
|
| 569 |
+ |
|
| 570 |
+func Convert_api_DeploymentRequest_To_v1_DeploymentRequest(in *api.DeploymentRequest, out *DeploymentRequest, s conversion.Scope) error {
|
|
| 571 |
+ return autoConvert_api_DeploymentRequest_To_v1_DeploymentRequest(in, out, s) |
|
| 572 |
+} |
|
| 573 |
+ |
|
| 546 | 574 |
func autoConvert_v1_DeploymentStrategy_To_api_DeploymentStrategy(in *DeploymentStrategy, out *api.DeploymentStrategy, s conversion.Scope) error {
|
| 547 | 575 |
SetDefaults_DeploymentStrategy(in) |
| 548 | 576 |
out.Type = api.DeploymentStrategyType(in.Type) |
| ... | ... |
@@ -33,6 +33,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
| 33 | 33 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentDetails, InType: reflect.TypeOf(&DeploymentDetails{})},
|
| 34 | 34 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentLog, InType: reflect.TypeOf(&DeploymentLog{})},
|
| 35 | 35 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentLogOptions, InType: reflect.TypeOf(&DeploymentLogOptions{})},
|
| 36 |
+ conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentRequest, InType: reflect.TypeOf(&DeploymentRequest{})},
|
|
| 36 | 37 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentStrategy, InType: reflect.TypeOf(&DeploymentStrategy{})},
|
| 37 | 38 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentTriggerImageChangeParams, InType: reflect.TypeOf(&DeploymentTriggerImageChangeParams{})},
|
| 38 | 39 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_v1_DeploymentTriggerPolicy, InType: reflect.TypeOf(&DeploymentTriggerPolicy{})},
|
| ... | ... |
@@ -321,6 +322,18 @@ func DeepCopy_v1_DeploymentLogOptions(in interface{}, out interface{}, c *conver
|
| 321 | 321 |
} |
| 322 | 322 |
} |
| 323 | 323 |
|
| 324 |
+func DeepCopy_v1_DeploymentRequest(in interface{}, out interface{}, c *conversion.Cloner) error {
|
|
| 325 |
+ {
|
|
| 326 |
+ in := in.(*DeploymentRequest) |
|
| 327 |
+ out := out.(*DeploymentRequest) |
|
| 328 |
+ out.TypeMeta = in.TypeMeta |
|
| 329 |
+ out.Name = in.Name |
|
| 330 |
+ out.Latest = in.Latest |
|
| 331 |
+ out.Force = in.Force |
|
| 332 |
+ return nil |
|
| 333 |
+ } |
|
| 334 |
+} |
|
| 335 |
+ |
|
| 324 | 336 |
func DeepCopy_v1_DeploymentStrategy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
| 325 | 337 |
{
|
| 326 | 338 |
in := in.(*DeploymentStrategy) |
| ... | ... |
@@ -502,6 +502,31 @@ func IsValidPercent(percent string) bool {
|
| 502 | 502 |
|
| 503 | 503 |
const isNegativeErrorMsg string = `must be non-negative` |
| 504 | 504 |
|
| 505 |
+func ValidateDeploymentRequest(req *deployapi.DeploymentRequest) field.ErrorList {
|
|
| 506 |
+ allErrs := field.ErrorList{}
|
|
| 507 |
+ |
|
| 508 |
+ if len(req.Name) == 0 {
|
|
| 509 |
+ allErrs = append(allErrs, field.Invalid(field.NewPath("name"), req.Name, "name of the deployment config is missing"))
|
|
| 510 |
+ } else if len(kvalidation.IsDNS1123Subdomain(req.Name)) != 0 {
|
|
| 511 |
+ allErrs = append(allErrs, field.Invalid(field.NewPath("name"), req.Name, "name of the deployment config is invalid"))
|
|
| 512 |
+ } |
|
| 513 |
+ |
|
| 514 |
+ return allErrs |
|
| 515 |
+} |
|
| 516 |
+ |
|
| 517 |
+func ValidateRequestForDeploymentConfig(req *deployapi.DeploymentRequest, config *deployapi.DeploymentConfig) field.ErrorList {
|
|
| 518 |
+ allErrs := ValidateDeploymentRequest(req) |
|
| 519 |
+ |
|
| 520 |
+ if config.Spec.Paused {
|
|
| 521 |
+ // TODO: Enable deployment requests for paused deployment configs |
|
| 522 |
+ // See https://github.com/openshift/origin/issues/9903 |
|
| 523 |
+ details := fmt.Sprintf("deployment config %q is paused - unpause to request a new deployment", config.Name)
|
|
| 524 |
+ allErrs = append(allErrs, field.Invalid(field.NewPath("spec").Child("paused"), config.Spec.Paused, details))
|
|
| 525 |
+ } |
|
| 526 |
+ |
|
| 527 |
+ return allErrs |
|
| 528 |
+} |
|
| 529 |
+ |
|
| 505 | 530 |
func ValidateDeploymentLogOptions(opts *deployapi.DeploymentLogOptions) field.ErrorList {
|
| 506 | 531 |
allErrs := field.ErrorList{}
|
| 507 | 532 |
|
| ... | ... |
@@ -33,6 +33,7 @@ func RegisterDeepCopies(scheme *runtime.Scheme) error {
|
| 33 | 33 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentDetails, InType: reflect.TypeOf(&DeploymentDetails{})},
|
| 34 | 34 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentLog, InType: reflect.TypeOf(&DeploymentLog{})},
|
| 35 | 35 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentLogOptions, InType: reflect.TypeOf(&DeploymentLogOptions{})},
|
| 36 |
+ conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentRequest, InType: reflect.TypeOf(&DeploymentRequest{})},
|
|
| 36 | 37 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentStrategy, InType: reflect.TypeOf(&DeploymentStrategy{})},
|
| 37 | 38 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentTriggerImageChangeParams, InType: reflect.TypeOf(&DeploymentTriggerImageChangeParams{})},
|
| 38 | 39 |
conversion.GeneratedDeepCopyFunc{Fn: DeepCopy_api_DeploymentTriggerPolicy, InType: reflect.TypeOf(&DeploymentTriggerPolicy{})},
|
| ... | ... |
@@ -322,6 +323,18 @@ func DeepCopy_api_DeploymentLogOptions(in interface{}, out interface{}, c *conve
|
| 322 | 322 |
} |
| 323 | 323 |
} |
| 324 | 324 |
|
| 325 |
+func DeepCopy_api_DeploymentRequest(in interface{}, out interface{}, c *conversion.Cloner) error {
|
|
| 326 |
+ {
|
|
| 327 |
+ in := in.(*DeploymentRequest) |
|
| 328 |
+ out := out.(*DeploymentRequest) |
|
| 329 |
+ out.TypeMeta = in.TypeMeta |
|
| 330 |
+ out.Name = in.Name |
|
| 331 |
+ out.Latest = in.Latest |
|
| 332 |
+ out.Force = in.Force |
|
| 333 |
+ return nil |
|
| 334 |
+ } |
|
| 335 |
+} |
|
| 336 |
+ |
|
| 325 | 337 |
func DeepCopy_api_DeploymentStrategy(in interface{}, out interface{}, c *conversion.Cloner) error {
|
| 326 | 338 |
{
|
| 327 | 339 |
in := in.(*DeploymentStrategy) |
| ... | ... |
@@ -1,10 +1,6 @@ |
| 1 | 1 |
package generictrigger |
| 2 | 2 |
|
| 3 | 3 |
import ( |
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 |
- kapi "k8s.io/kubernetes/pkg/api" |
|
| 7 |
- kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
| 8 | 4 |
"k8s.io/kubernetes/pkg/runtime" |
| 9 | 5 |
utilruntime "k8s.io/kubernetes/pkg/util/runtime" |
| 10 | 6 |
"k8s.io/kubernetes/pkg/util/workqueue" |
| ... | ... |
@@ -13,7 +9,6 @@ import ( |
| 13 | 13 |
osclient "github.com/openshift/origin/pkg/client" |
| 14 | 14 |
oscache "github.com/openshift/origin/pkg/client/cache" |
| 15 | 15 |
deployapi "github.com/openshift/origin/pkg/deploy/api" |
| 16 |
- deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 17 | 16 |
) |
| 18 | 17 |
|
| 19 | 18 |
// DeploymentTriggerController processes all triggers for a deployment config |
| ... | ... |
@@ -21,8 +16,6 @@ import ( |
| 21 | 21 |
type DeploymentTriggerController struct {
|
| 22 | 22 |
// dn is used to update deployment configs. |
| 23 | 23 |
dn osclient.DeploymentConfigsNamespacer |
| 24 |
- // rn is used for getting the latest deployment for a config. |
|
| 25 |
- rn kclient.ReplicationControllersNamespacer |
|
| 26 | 24 |
|
| 27 | 25 |
// queue contains deployment configs that need to be synced. |
| 28 | 26 |
queue workqueue.RateLimitingInterface |
| ... | ... |
@@ -36,186 +29,19 @@ type DeploymentTriggerController struct {
|
| 36 | 36 |
codec runtime.Codec |
| 37 | 37 |
} |
| 38 | 38 |
|
| 39 |
-// fatalError is an error which can't be retried. |
|
| 40 |
-type fatalError string |
|
| 41 |
- |
|
| 42 |
-func (e fatalError) Error() string {
|
|
| 43 |
- return fmt.Sprintf("fatal error handling configuration: %s", string(e))
|
|
| 44 |
-} |
|
| 45 |
- |
|
| 46 | 39 |
// Handle processes deployment triggers for a deployment config. |
| 47 | 40 |
func (c *DeploymentTriggerController) Handle(config *deployapi.DeploymentConfig) error {
|
| 48 | 41 |
if len(config.Spec.Triggers) == 0 || config.Spec.Paused {
|
| 49 | 42 |
return nil |
| 50 | 43 |
} |
| 51 | 44 |
|
| 52 |
- // Try to decode this deployment config from the encoded annotation found in |
|
| 53 |
- // its latest deployment. |
|
| 54 |
- decoded, err := c.decodeFromLatest(config) |
|
| 55 |
- if err != nil {
|
|
| 56 |
- return err |
|
| 57 |
- } |
|
| 58 |
- |
|
| 59 |
- canTrigger, causes := canTrigger(config, decoded) |
|
| 60 |
- |
|
| 61 |
- // Return if we cannot trigger a new deployment. |
|
| 62 |
- if !canTrigger {
|
|
| 63 |
- return nil |
|
| 64 |
- } |
|
| 65 |
- |
|
| 66 |
- copied, err := deployutil.DeploymentConfigDeepCopy(config) |
|
| 67 |
- if err != nil {
|
|
| 68 |
- return err |
|
| 69 |
- } |
|
| 70 |
- |
|
| 71 |
- return c.update(copied, causes) |
|
| 72 |
-} |
|
| 73 |
- |
|
| 74 |
-// decodeFromLatest will try to return the decoded version of the current deploymentconfig found |
|
| 75 |
-// in the annotations of its latest deployment. If there is no previous deploymentconfig (ie. |
|
| 76 |
-// latestVersion == 0), the returned deploymentconfig will be the same. |
|
| 77 |
-func (c *DeploymentTriggerController) decodeFromLatest(config *deployapi.DeploymentConfig) (*deployapi.DeploymentConfig, error) {
|
|
| 78 |
- if config.Status.LatestVersion == 0 {
|
|
| 79 |
- return config, nil |
|
| 80 |
- } |
|
| 81 |
- |
|
| 82 |
- latestDeploymentName := deployutil.LatestDeploymentNameForConfig(config) |
|
| 83 |
- deployment, err := c.rn.ReplicationControllers(config.Namespace).Get(latestDeploymentName) |
|
| 84 |
- if err != nil {
|
|
| 85 |
- // If there's no deployment for the latest config, we have no basis of |
|
| 86 |
- // comparison. It's the responsibility of the deployment config controller |
|
| 87 |
- // to make the deployment for the config, so return early. |
|
| 88 |
- return nil, fmt.Errorf("couldn't retrieve deployment for deployment config %q: %v", deployutil.LabelForDeploymentConfig(config), err)
|
|
| 89 |
- } |
|
| 90 |
- |
|
| 91 |
- latest, err := deployutil.DecodeDeploymentConfig(deployment, c.codec) |
|
| 92 |
- if err != nil {
|
|
| 93 |
- return nil, fatalError(err.Error()) |
|
| 94 |
- } |
|
| 95 |
- return latest, nil |
|
| 96 |
-} |
|
| 97 |
- |
|
| 98 |
-// canTrigger is used by the trigger controller to determine if the provided config can trigger |
|
| 99 |
-// a deployment. |
|
| 100 |
-// |
|
| 101 |
-// Image change triggers are processed first. It is required for all of them to point to images |
|
| 102 |
-// that exist. Otherwise, this controller will wait for the images to land and be updated in the |
|
| 103 |
-// triggers that point to them by the image change controller. |
|
| 104 |
-// |
|
| 105 |
-// Config change triggers are processed last. If all images are resolved and an automatic trigger |
|
| 106 |
-// was updated, then it should be possible to trigger a new deployment without a config change |
|
| 107 |
-// trigger. Otherwise, if a config change trigger exists and the config is not deployed yet or it |
|
| 108 |
-// has a podtemplate change, then the controller should trigger a new deployment (assuming all |
|
| 109 |
-// image change triggers can trigger). |
|
| 110 |
-func canTrigger(config, decoded *deployapi.DeploymentConfig) (bool, []deployapi.DeploymentCause) {
|
|
| 111 |
- if decoded == nil {
|
|
| 112 |
- // The decoded deployment config will never be nil here but a sanity check |
|
| 113 |
- // never hurts. |
|
| 114 |
- return false, nil |
|
| 115 |
- } |
|
| 116 |
- ictCount, resolved, canTriggerByImageChange := 0, 0, false |
|
| 117 |
- var causes []deployapi.DeploymentCause |
|
| 118 |
- |
|
| 119 |
- // IMAGE CHANGE TRIGGERS |
|
| 120 |
- for _, t := range config.Spec.Triggers {
|
|
| 121 |
- if t.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 122 |
- continue |
|
| 123 |
- } |
|
| 124 |
- ictCount++ |
|
| 125 |
- |
|
| 126 |
- // If this is the initial deployment then we need to wait for the image change controller |
|
| 127 |
- // to resolve the image inside the pod template. |
|
| 128 |
- lastTriggered := t.ImageChangeParams.LastTriggeredImage |
|
| 129 |
- if len(lastTriggered) == 0 {
|
|
| 130 |
- continue |
|
| 131 |
- } |
|
| 132 |
- resolved++ |
|
| 133 |
- |
|
| 134 |
- // Non-automatic triggers should not be able to trigger deployments. |
|
| 135 |
- if !t.ImageChangeParams.Automatic {
|
|
| 136 |
- continue |
|
| 137 |
- } |
|
| 138 |
- |
|
| 139 |
- // We need stronger checks in order to validate that this template |
|
| 140 |
- // change is an image change. Look at the deserialized config's |
|
| 141 |
- // triggers and compare with the present trigger. Initial deployments |
|
| 142 |
- // should always trigger since there is no previous config to compare to. |
|
| 143 |
- if config.Status.LatestVersion > 0 {
|
|
| 144 |
- if !triggeredByDifferentImage(*t.ImageChangeParams, *decoded) {
|
|
| 145 |
- continue |
|
| 146 |
- } |
|
| 147 |
- } |
|
| 148 |
- |
|
| 149 |
- canTriggerByImageChange = true |
|
| 150 |
- causes = append(causes, deployapi.DeploymentCause{
|
|
| 151 |
- Type: deployapi.DeploymentTriggerOnImageChange, |
|
| 152 |
- ImageTrigger: &deployapi.DeploymentCauseImageTrigger{
|
|
| 153 |
- From: kapi.ObjectReference{
|
|
| 154 |
- Name: t.ImageChangeParams.From.Name, |
|
| 155 |
- Namespace: t.ImageChangeParams.From.Namespace, |
|
| 156 |
- Kind: "ImageStreamTag", |
|
| 157 |
- }, |
|
| 158 |
- }, |
|
| 159 |
- }) |
|
| 160 |
- } |
|
| 161 |
- |
|
| 162 |
- // We need to wait for all images to resolve before triggering a new deployment. |
|
| 163 |
- if ictCount != resolved {
|
|
| 164 |
- return false, nil |
|
| 45 |
+ request := &deployapi.DeploymentRequest{
|
|
| 46 |
+ Name: config.Name, |
|
| 47 |
+ Latest: true, |
|
| 48 |
+ Force: false, |
|
| 165 | 49 |
} |
| 166 | 50 |
|
| 167 |
- // CONFIG CHANGE TRIGGERS |
|
| 168 |
- canTriggerByConfigChange := false |
|
| 169 |
- // Our deployment config has a config change trigger and no image change has triggered. |
|
| 170 |
- // If an image change had happened, it would be enough to start a new deployment without |
|
| 171 |
- // caring about the config change trigger. |
|
| 172 |
- if deployutil.HasChangeTrigger(config) && !canTriggerByImageChange {
|
|
| 173 |
- // This is the initial deployment or the config has a template change. We need to |
|
| 174 |
- // kick a new deployment. |
|
| 175 |
- if config.Status.LatestVersion == 0 || !kapi.Semantic.DeepEqual(config.Spec.Template, decoded.Spec.Template) {
|
|
| 176 |
- canTriggerByConfigChange = true |
|
| 177 |
- causes = []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerOnConfigChange}}
|
|
| 178 |
- } |
|
| 179 |
- } |
|
| 180 |
- |
|
| 181 |
- return canTriggerByConfigChange || canTriggerByImageChange, causes |
|
| 182 |
-} |
|
| 183 |
- |
|
| 184 |
-// triggeredByDifferentImage compares the provided image change parameters with those found in the |
|
| 185 |
-// previous deployment config (the one we decoded from the annotations of its latest deployment) |
|
| 186 |
-// and returns whether the two deployment configs have been triggered by a different image change. |
|
| 187 |
-func triggeredByDifferentImage(ictParams deployapi.DeploymentTriggerImageChangeParams, previous deployapi.DeploymentConfig) bool {
|
|
| 188 |
- for _, t := range previous.Spec.Triggers {
|
|
| 189 |
- if t.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 190 |
- continue |
|
| 191 |
- } |
|
| 192 |
- |
|
| 193 |
- if t.ImageChangeParams.From.Name != ictParams.From.Name || |
|
| 194 |
- t.ImageChangeParams.From.Namespace != ictParams.From.Namespace {
|
|
| 195 |
- continue |
|
| 196 |
- } |
|
| 197 |
- if t.ImageChangeParams.LastTriggeredImage != ictParams.LastTriggeredImage {
|
|
| 198 |
- glog.V(4).Infof("Deployment config %q triggered by different image: %s -> %s", previous.Name, t.ImageChangeParams.LastTriggeredImage, ictParams.LastTriggeredImage)
|
|
| 199 |
- return true |
|
| 200 |
- } |
|
| 201 |
- return false |
|
| 202 |
- } |
|
| 203 |
- return false |
|
| 204 |
-} |
|
| 205 |
- |
|
| 206 |
-// update increments the latestVersion of the provided deployment config so the deployment config |
|
| 207 |
-// controller can run a new deployment and also updates the details of the deployment config. |
|
| 208 |
-func (c *DeploymentTriggerController) update(config *deployapi.DeploymentConfig, causes []deployapi.DeploymentCause) error {
|
|
| 209 |
- config.Status.LatestVersion++ |
|
| 210 |
- config.Status.Details = new(deployapi.DeploymentDetails) |
|
| 211 |
- config.Status.Details.Causes = causes |
|
| 212 |
- switch causes[0].Type {
|
|
| 213 |
- case deployapi.DeploymentTriggerOnConfigChange: |
|
| 214 |
- config.Status.Details.Message = "caused by a config change" |
|
| 215 |
- case deployapi.DeploymentTriggerOnImageChange: |
|
| 216 |
- config.Status.Details.Message = "caused by an image change" |
|
| 217 |
- } |
|
| 218 |
- _, err := c.dn.DeploymentConfigs(config.Namespace).UpdateStatus(config) |
|
| 51 |
+ _, err := c.dn.DeploymentConfigs(config.Namespace).Instantiate(request) |
|
| 219 | 52 |
return err |
| 220 | 53 |
} |
| 221 | 54 |
|
| ... | ... |
@@ -9,7 +9,6 @@ import ( |
| 9 | 9 |
ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient" |
| 10 | 10 |
"k8s.io/kubernetes/pkg/controller/framework" |
| 11 | 11 |
"k8s.io/kubernetes/pkg/runtime" |
| 12 |
- "k8s.io/kubernetes/pkg/util/diff" |
|
| 13 | 12 |
"k8s.io/kubernetes/pkg/watch" |
| 14 | 13 |
|
| 15 | 14 |
"github.com/openshift/origin/pkg/client/testclient" |
| ... | ... |
@@ -17,34 +16,31 @@ import ( |
| 17 | 17 |
_ "github.com/openshift/origin/pkg/deploy/api/install" |
| 18 | 18 |
testapi "github.com/openshift/origin/pkg/deploy/api/test" |
| 19 | 19 |
deployv1 "github.com/openshift/origin/pkg/deploy/api/v1" |
| 20 |
- deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 21 | 20 |
imageapi "github.com/openshift/origin/pkg/image/api" |
| 22 | 21 |
) |
| 23 | 22 |
|
| 24 | 23 |
var ( |
| 25 | 24 |
codec = kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion) |
| 26 |
- mock = &testclient.Fake{}
|
|
| 27 | 25 |
dcInformer = framework.NewSharedIndexInformer( |
| 28 | 26 |
&cache.ListWatch{
|
| 29 | 27 |
ListFunc: func(options kapi.ListOptions) (runtime.Object, error) {
|
| 30 |
- return mock.DeploymentConfigs(kapi.NamespaceAll).List(options) |
|
| 28 |
+ return (&testclient.Fake{}).DeploymentConfigs(kapi.NamespaceAll).List(options)
|
|
| 31 | 29 |
}, |
| 32 | 30 |
WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) {
|
| 33 |
- return mock.DeploymentConfigs(kapi.NamespaceAll).Watch(options) |
|
| 31 |
+ return (&testclient.Fake{}).DeploymentConfigs(kapi.NamespaceAll).Watch(options)
|
|
| 34 | 32 |
}, |
| 35 | 33 |
}, |
| 36 | 34 |
&deployapi.DeploymentConfig{},
|
| 37 | 35 |
2*time.Minute, |
| 38 | 36 |
cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc},
|
| 39 | 37 |
) |
| 40 |
- |
|
| 41 | 38 |
streamInformer = framework.NewSharedIndexInformer( |
| 42 | 39 |
&cache.ListWatch{
|
| 43 | 40 |
ListFunc: func(options kapi.ListOptions) (runtime.Object, error) {
|
| 44 |
- return mock.ImageStreams(kapi.NamespaceAll).List(options) |
|
| 41 |
+ return (&testclient.Fake{}).ImageStreams(kapi.NamespaceAll).List(options)
|
|
| 45 | 42 |
}, |
| 46 | 43 |
WatchFunc: func(options kapi.ListOptions) (watch.Interface, error) {
|
| 47 |
- return mock.ImageStreams(kapi.NamespaceAll).Watch(options) |
|
| 44 |
+ return (&testclient.Fake{}).ImageStreams(kapi.NamespaceAll).Watch(options)
|
|
| 48 | 45 |
}, |
| 49 | 46 |
}, |
| 50 | 47 |
&imageapi.ImageStream{},
|
| ... | ... |
@@ -53,13 +49,12 @@ var ( |
| 53 | 53 |
) |
| 54 | 54 |
) |
| 55 | 55 |
|
| 56 |
-// TestHandle_newConfigNoTriggers ensures that a change to a config with no |
|
| 57 |
-// triggers doesn't result in a new config version bump. |
|
| 58 |
-func TestHandle_newConfigNoTriggers(t *testing.T) {
|
|
| 56 |
+// TestHandle_noTriggers ensures that a change to a config with no |
|
| 57 |
+// triggers doesn't result in a config instantiation. |
|
| 58 |
+func TestHandle_noTriggers(t *testing.T) {
|
|
| 59 | 59 |
fake := &testclient.Fake{}
|
| 60 |
- kFake := &ktestclient.Fake{}
|
|
| 61 | 60 |
|
| 62 |
- controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, kFake, codec) |
|
| 61 |
+ controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, codec) |
|
| 63 | 62 |
|
| 64 | 63 |
config := testapi.OkDeploymentConfig(1) |
| 65 | 64 |
config.Namespace = kapi.NamespaceDefault |
| ... | ... |
@@ -68,596 +63,71 @@ func TestHandle_newConfigNoTriggers(t *testing.T) {
|
| 68 | 68 |
t.Fatalf("unexpected error: %v", err)
|
| 69 | 69 |
} |
| 70 | 70 |
if len(fake.Actions()) > 0 {
|
| 71 |
- t.Fatalf("unexpected actions by the Origin client: %v", fake.Actions())
|
|
| 72 |
- } |
|
| 73 |
- if len(kFake.Actions()) > 0 {
|
|
| 74 |
- t.Fatalf("unexpected actions by the Kube client: %v", kFake.Actions())
|
|
| 71 |
+ t.Fatalf("unexpected actions: %v", fake.Actions())
|
|
| 75 | 72 |
} |
| 76 | 73 |
} |
| 77 | 74 |
|
| 78 |
-// TestHandle_newConfigTriggers ensures that the creation of a new config |
|
| 79 |
-// (with version 0) with a config change trigger results in a version bump and |
|
| 80 |
-// cause update for initial deployment. |
|
| 81 |
-func TestHandle_newConfigTriggers(t *testing.T) {
|
|
| 82 |
- var updated *deployapi.DeploymentConfig |
|
| 83 |
- |
|
| 75 |
+// TestHandle_pausedConfig ensures that a paused config will not be instantiated. |
|
| 76 |
+func TestHandle_pausedConfig(t *testing.T) {
|
|
| 84 | 77 |
fake := &testclient.Fake{}
|
| 85 |
- fake.AddReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 86 |
- updated = action.(ktestclient.UpdateAction).GetObject().(*deployapi.DeploymentConfig) |
|
| 87 |
- return true, updated, nil |
|
| 88 |
- }) |
|
| 89 |
- kFake := &ktestclient.Fake{}
|
|
| 90 | 78 |
|
| 91 |
- controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, kFake, codec) |
|
| 79 |
+ controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, codec) |
|
| 92 | 80 |
|
| 93 |
- config := testapi.OkDeploymentConfig(0) |
|
| 81 |
+ config := testapi.OkDeploymentConfig(1) |
|
| 94 | 82 |
config.Namespace = kapi.NamespaceDefault |
| 95 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()}
|
|
| 83 |
+ config.Spec.Paused = true |
|
| 96 | 84 |
if err := controller.Handle(config); err != nil {
|
| 97 | 85 |
t.Fatalf("unexpected error: %v", err)
|
| 98 | 86 |
} |
| 99 |
- if updated == nil {
|
|
| 100 |
- t.Fatalf("expected config to be updated")
|
|
| 101 |
- } |
|
| 102 |
- if e, a := int64(1), updated.Status.LatestVersion; e != a {
|
|
| 103 |
- t.Fatalf("expected update to latestversion=%d, got %d", e, a)
|
|
| 104 |
- } |
|
| 105 |
- if updated.Status.Details == nil {
|
|
| 106 |
- t.Fatalf("expected config change details to be set")
|
|
| 107 |
- } else if updated.Status.Details.Causes == nil {
|
|
| 108 |
- t.Fatalf("expected config change causes to be set")
|
|
| 109 |
- } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange {
|
|
| 110 |
- t.Fatalf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type)
|
|
| 87 |
+ if len(fake.Actions()) > 0 {
|
|
| 88 |
+ t.Fatalf("unexpected actions: %v", fake.Actions())
|
|
| 111 | 89 |
} |
| 112 | 90 |
} |
| 113 | 91 |
|
| 114 |
-// TestHandle_changeWithTemplateDiff ensures that a pod template change to a |
|
| 115 |
-// config with a config change trigger results in a version bump and cause |
|
| 116 |
-// update. |
|
| 117 |
-func TestHandle_changeWithTemplateDiff(t *testing.T) {
|
|
| 118 |
- scenarios := []struct {
|
|
| 119 |
- name string |
|
| 120 |
- modify func(*deployapi.DeploymentConfig) |
|
| 121 |
- changeExpected bool |
|
| 122 |
- }{
|
|
| 123 |
- {
|
|
| 124 |
- name: "container name change", |
|
| 125 |
- changeExpected: true, |
|
| 126 |
- modify: func(config *deployapi.DeploymentConfig) {
|
|
| 127 |
- config.Spec.Template.Spec.Containers[1].Name = "modified" |
|
| 128 |
- }, |
|
| 129 |
- }, |
|
| 130 |
- {
|
|
| 131 |
- name: "template label change", |
|
| 132 |
- changeExpected: true, |
|
| 133 |
- modify: func(config *deployapi.DeploymentConfig) {
|
|
| 134 |
- config.Spec.Template.Labels["newkey"] = "value" |
|
| 135 |
- }, |
|
| 136 |
- }, |
|
| 137 |
- {
|
|
| 138 |
- name: "no diff", |
|
| 139 |
- changeExpected: false, |
|
| 140 |
- modify: func(config *deployapi.DeploymentConfig) {},
|
|
| 141 |
- }, |
|
| 142 |
- } |
|
| 143 |
- |
|
| 144 |
- for _, s := range scenarios {
|
|
| 145 |
- t.Logf("running scenario: %s", s.name)
|
|
| 146 |
- fake := &testclient.Fake{}
|
|
| 147 |
- kFake := &ktestclient.Fake{}
|
|
| 148 |
- |
|
| 149 |
- config := testapi.OkDeploymentConfig(1) |
|
| 150 |
- config.Namespace = kapi.NamespaceDefault |
|
| 151 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()}
|
|
| 152 |
- |
|
| 153 |
- versioned, err := kapi.Scheme.ConvertToVersion(config, deployv1.SchemeGroupVersion) |
|
| 154 |
- if err != nil {
|
|
| 155 |
- t.Errorf("unexpected conversion error: %v", err)
|
|
| 156 |
- continue |
|
| 157 |
- } |
|
| 158 |
- defaulted, err := kapi.Scheme.ConvertToVersion(versioned, deployapi.SchemeGroupVersion) |
|
| 159 |
- if err != nil {
|
|
| 160 |
- t.Errorf("unexpected conversion error: %v", err)
|
|
| 161 |
- continue |
|
| 162 |
- } |
|
| 163 |
- config = defaulted.(*deployapi.DeploymentConfig) |
|
| 164 |
- |
|
| 165 |
- deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)) |
|
| 166 |
- var updated *deployapi.DeploymentConfig |
|
| 167 |
- |
|
| 168 |
- fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 169 |
- updated = action.(ktestclient.UpdateAction).GetObject().(*deployapi.DeploymentConfig) |
|
| 170 |
- return true, updated, nil |
|
| 171 |
- }) |
|
| 172 |
- kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 173 |
- return true, deployment, nil |
|
| 174 |
- }) |
|
| 175 |
- |
|
| 176 |
- controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, kFake, codec) |
|
| 177 |
- |
|
| 178 |
- s.modify(config) |
|
| 179 |
- if err := controller.Handle(config); err != nil {
|
|
| 180 |
- t.Errorf("unexpected error: %v", err)
|
|
| 181 |
- continue |
|
| 182 |
- } |
|
| 92 |
+// TestHandle_configChangeTrigger ensures that a config with a config change |
|
| 93 |
+// trigger will be reconciled. |
|
| 94 |
+func TestHandle_configChangeTrigger(t *testing.T) {
|
|
| 95 |
+ updated := false |
|
| 183 | 96 |
|
| 184 |
- if !s.changeExpected {
|
|
| 185 |
- if updated != nil {
|
|
| 186 |
- t.Errorf("unexpected update to version %d: %s", updated.Status.LatestVersion, diff.ObjectReflectDiff(config, updated))
|
|
| 187 |
- } |
|
| 188 |
- continue |
|
| 189 |
- } |
|
| 190 |
- |
|
| 191 |
- // changeExpected == true |
|
| 192 |
- if updated == nil {
|
|
| 193 |
- t.Errorf("expected config to be updated")
|
|
| 194 |
- continue |
|
| 195 |
- } |
|
| 196 |
- if e, a := int64(2), updated.Status.LatestVersion; e != a {
|
|
| 197 |
- t.Errorf("expected update to latestversion=%d, got %d", e, a)
|
|
| 198 |
- continue |
|
| 199 |
- } |
|
| 200 |
- |
|
| 201 |
- if updated.Status.Details == nil {
|
|
| 202 |
- t.Errorf("expected config change details to be set")
|
|
| 203 |
- } else if updated.Status.Details.Causes == nil {
|
|
| 204 |
- t.Errorf("expected config change causes to be set")
|
|
| 205 |
- } else if updated.Status.Details.Causes[0].Type != deployapi.DeploymentTriggerOnConfigChange {
|
|
| 206 |
- t.Errorf("expected config change cause to be set to config change trigger, got %s", updated.Status.Details.Causes[0].Type)
|
|
| 207 |
- } |
|
| 208 |
- } |
|
| 209 |
-} |
|
| 210 |
- |
|
| 211 |
-// TestHandle_waitForImageController tests an initial deployment with unresolved image. The config |
|
| 212 |
-// change controller should never increment latestVersion, thus trigger a deployment for this config. |
|
| 213 |
-func TestHandle_waitForImageController(t *testing.T) {
|
|
| 214 | 97 |
fake := &testclient.Fake{}
|
| 215 |
- kFake := &ktestclient.Fake{}
|
|
| 216 |
- |
|
| 217 |
- fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 218 |
- t.Fatalf("an update should never run before the template image is resolved")
|
|
| 98 |
+ fake.AddReactor("update", "deploymentconfigs/instantiate", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 99 |
+ updated = true |
|
| 219 | 100 |
return true, nil, nil |
| 220 | 101 |
}) |
| 221 | 102 |
|
| 222 |
- controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, kFake, codec) |
|
| 103 |
+ controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, codec) |
|
| 223 | 104 |
|
| 224 | 105 |
config := testapi.OkDeploymentConfig(0) |
| 225 | 106 |
config.Namespace = kapi.NamespaceDefault |
| 226 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger(), testapi.OkImageChangeTrigger()}
|
|
| 227 |
- |
|
| 107 |
+ config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger()}
|
|
| 228 | 108 |
if err := controller.Handle(config); err != nil {
|
| 229 | 109 |
t.Fatalf("unexpected error: %v", err)
|
| 230 | 110 |
} |
| 231 |
-} |
|
| 232 |
- |
|
| 233 |
-// TestHandle_automaticImageUpdates tests automatic and non-automatic updates |
|
| 234 |
-// from image change triggers. |
|
| 235 |
-func TestHandle_automaticImageUpdates(t *testing.T) {
|
|
| 236 |
- tests := []struct {
|
|
| 237 |
- name string |
|
| 238 |
- auto bool |
|
| 239 |
- canTrigger bool |
|
| 240 |
- version int64 |
|
| 241 |
- expectedUpdate bool |
|
| 242 |
- }{
|
|
| 243 |
- {
|
|
| 244 |
- name: "initial deployment with unresolved image (auto: true)", |
|
| 245 |
- auto: true, |
|
| 246 |
- canTrigger: false, |
|
| 247 |
- version: 0, |
|
| 248 |
- expectedUpdate: false, |
|
| 249 |
- }, |
|
| 250 |
- {
|
|
| 251 |
- name: "initial deployment with unresolved image (auto: false)", |
|
| 252 |
- auto: false, |
|
| 253 |
- canTrigger: false, |
|
| 254 |
- version: 0, |
|
| 255 |
- expectedUpdate: false, |
|
| 256 |
- }, |
|
| 257 |
- {
|
|
| 258 |
- name: "initial deployment with resolved image (auto: true)", |
|
| 259 |
- auto: true, |
|
| 260 |
- canTrigger: true, |
|
| 261 |
- version: 0, |
|
| 262 |
- expectedUpdate: true, |
|
| 263 |
- }, |
|
| 264 |
- {
|
|
| 265 |
- name: "initial deployment with resolved image (auto: false)", |
|
| 266 |
- auto: false, |
|
| 267 |
- canTrigger: true, |
|
| 268 |
- version: 0, |
|
| 269 |
- expectedUpdate: true, |
|
| 270 |
- }, |
|
| 271 |
- } |
|
| 272 |
- |
|
| 273 |
- for _, test := range tests {
|
|
| 274 |
- updated := false |
|
| 275 |
- |
|
| 276 |
- fake := &testclient.Fake{}
|
|
| 277 |
- kFake := &ktestclient.Fake{}
|
|
| 278 |
- fake.PrependReactor("update", "deploymentconfigs/status", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 279 |
- updated = true |
|
| 280 |
- return true, nil, nil |
|
| 281 |
- }) |
|
| 282 |
- kFake.PrependReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 283 |
- // This will always return no template difference. We test template differences in TestHandle_changeWithTemplateDiff |
|
| 284 |
- config := testapi.OkDeploymentConfig(0) |
|
| 285 |
- deployment, _ := deployutil.MakeDeployment(config, kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion)) |
|
| 286 |
- return true, deployment, nil |
|
| 287 |
- }) |
|
| 288 |
- |
|
| 289 |
- controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, kFake, codec) |
|
| 290 |
- |
|
| 291 |
- config := testapi.OkDeploymentConfig(test.version) |
|
| 292 |
- config.Namespace = kapi.NamespaceDefault |
|
| 293 |
- ict := testapi.OkImageChangeTrigger() |
|
| 294 |
- ict.ImageChangeParams.Automatic = test.auto |
|
| 295 |
- if test.canTrigger {
|
|
| 296 |
- ict.ImageChangeParams.LastTriggeredImage = testapi.DockerImageReference |
|
| 297 |
- } |
|
| 298 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkConfigChangeTrigger(), ict}
|
|
| 299 |
- |
|
| 300 |
- if err := controller.Handle(config); err != nil {
|
|
| 301 |
- t.Errorf("%s: unexpected error: %v", test.name, err)
|
|
| 302 |
- continue |
|
| 303 |
- } |
|
| 304 |
- |
|
| 305 |
- if test.expectedUpdate != updated {
|
|
| 306 |
- t.Errorf("%s: expected update: %t, got update: %t", test.name, test.expectedUpdate, updated)
|
|
| 307 |
- } |
|
| 111 |
+ if !updated {
|
|
| 112 |
+ t.Fatalf("expected config to be instantiated")
|
|
| 308 | 113 |
} |
| 309 | 114 |
} |
| 310 | 115 |
|
| 311 |
-func TestCanTrigger(t *testing.T) {
|
|
| 312 |
- tests := []struct {
|
|
| 313 |
- name string |
|
| 314 |
- |
|
| 315 |
- config *deployapi.DeploymentConfig |
|
| 316 |
- decoded *deployapi.DeploymentConfig |
|
| 116 |
+// TestHandle_imageChangeTrigger ensures that a config with an image change |
|
| 117 |
+// trigger will be reconciled. |
|
| 118 |
+func TestHandle_imageChangeTrigger(t *testing.T) {
|
|
| 119 |
+ updated := false |
|
| 317 | 120 |
|
| 318 |
- expected bool |
|
| 319 |
- expectedCauses []deployapi.DeploymentCause |
|
| 320 |
- }{
|
|
| 321 |
- {
|
|
| 322 |
- name: "nil decoded config", |
|
| 323 |
- |
|
| 324 |
- config: testapi.OkDeploymentConfig(1), |
|
| 325 |
- decoded: nil, |
|
| 326 |
- |
|
| 327 |
- expected: false, |
|
| 328 |
- expectedCauses: nil, |
|
| 329 |
- }, |
|
| 330 |
- {
|
|
| 331 |
- name: "no trigger", |
|
| 332 |
- |
|
| 333 |
- config: &deployapi.DeploymentConfig{
|
|
| 334 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 335 |
- Template: testapi.OkPodTemplateChanged(), |
|
| 336 |
- }, |
|
| 337 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 338 |
- }, |
|
| 339 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 340 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 341 |
- Template: testapi.OkPodTemplate(), |
|
| 342 |
- }, |
|
| 343 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 344 |
- }, |
|
| 345 |
- |
|
| 346 |
- expected: false, |
|
| 347 |
- expectedCauses: nil, |
|
| 348 |
- }, |
|
| 349 |
- {
|
|
| 350 |
- name: "config change trigger only", |
|
| 351 |
- |
|
| 352 |
- config: &deployapi.DeploymentConfig{
|
|
| 353 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 354 |
- Template: testapi.OkPodTemplateChanged(), |
|
| 355 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 356 |
- testapi.OkConfigChangeTrigger(), |
|
| 357 |
- }, |
|
| 358 |
- }, |
|
| 359 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 360 |
- }, |
|
| 361 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 362 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 363 |
- Template: testapi.OkPodTemplate(), |
|
| 364 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 365 |
- testapi.OkConfigChangeTrigger(), |
|
| 366 |
- }, |
|
| 367 |
- }, |
|
| 368 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 369 |
- }, |
|
| 370 |
- |
|
| 371 |
- expected: true, |
|
| 372 |
- expectedCauses: testapi.OkConfigChangeDetails().Causes, |
|
| 373 |
- }, |
|
| 374 |
- {
|
|
| 375 |
- name: "config change trigger only [no change][initial]", |
|
| 376 |
- |
|
| 377 |
- config: &deployapi.DeploymentConfig{
|
|
| 378 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 379 |
- Template: testapi.OkPodTemplate(), |
|
| 380 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 381 |
- testapi.OkConfigChangeTrigger(), |
|
| 382 |
- }, |
|
| 383 |
- }, |
|
| 384 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 385 |
- }, |
|
| 386 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 387 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 388 |
- Template: testapi.OkPodTemplate(), |
|
| 389 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 390 |
- testapi.OkConfigChangeTrigger(), |
|
| 391 |
- }, |
|
| 392 |
- }, |
|
| 393 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 394 |
- }, |
|
| 395 |
- |
|
| 396 |
- expected: true, |
|
| 397 |
- expectedCauses: testapi.OkConfigChangeDetails().Causes, |
|
| 398 |
- }, |
|
| 399 |
- {
|
|
| 400 |
- name: "config change trigger only [no change]", |
|
| 401 |
- |
|
| 402 |
- config: &deployapi.DeploymentConfig{
|
|
| 403 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 404 |
- Template: testapi.OkPodTemplate(), |
|
| 405 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 406 |
- testapi.OkConfigChangeTrigger(), |
|
| 407 |
- }, |
|
| 408 |
- }, |
|
| 409 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 410 |
- }, |
|
| 411 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 412 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 413 |
- Template: testapi.OkPodTemplate(), |
|
| 414 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 415 |
- testapi.OkConfigChangeTrigger(), |
|
| 416 |
- }, |
|
| 417 |
- }, |
|
| 418 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 419 |
- }, |
|
| 420 |
- |
|
| 421 |
- expected: false, |
|
| 422 |
- expectedCauses: nil, |
|
| 423 |
- }, |
|
| 424 |
- {
|
|
| 425 |
- name: "image change trigger only [automatic=false]", |
|
| 426 |
- |
|
| 427 |
- config: &deployapi.DeploymentConfig{
|
|
| 428 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 429 |
- Template: testapi.OkPodTemplateChanged(), // Irrelevant change |
|
| 430 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 431 |
- testapi.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway |
|
| 432 |
- }, |
|
| 433 |
- }, |
|
| 434 |
- }, |
|
| 435 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 436 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 437 |
- Template: testapi.OkPodTemplate(), |
|
| 438 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 439 |
- testapi.OkNonAutomaticICT(), |
|
| 440 |
- }, |
|
| 441 |
- }, |
|
| 442 |
- }, |
|
| 443 |
- |
|
| 444 |
- expected: false, |
|
| 445 |
- expectedCauses: nil, |
|
| 446 |
- }, |
|
| 447 |
- {
|
|
| 448 |
- name: "image change trigger only [automatic=false][image triggered]", |
|
| 449 |
- |
|
| 450 |
- config: &deployapi.DeploymentConfig{
|
|
| 451 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 452 |
- Template: testapi.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false |
|
| 453 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 454 |
- testapi.OkTriggeredNonAutomatic(), |
|
| 455 |
- }, |
|
| 456 |
- }, |
|
| 457 |
- }, |
|
| 458 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 459 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 460 |
- Template: testapi.OkPodTemplate(), |
|
| 461 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 462 |
- testapi.OkNonAutomaticICT(), |
|
| 463 |
- }, |
|
| 464 |
- }, |
|
| 465 |
- }, |
|
| 466 |
- |
|
| 467 |
- expected: false, |
|
| 468 |
- expectedCauses: nil, |
|
| 469 |
- }, |
|
| 470 |
- {
|
|
| 471 |
- name: "image change trigger only [automatic=true]", |
|
| 472 |
- |
|
| 473 |
- config: &deployapi.DeploymentConfig{
|
|
| 474 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 475 |
- Template: testapi.OkPodTemplateChanged(), |
|
| 476 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 477 |
- testapi.OkTriggeredImageChange(), |
|
| 478 |
- }, |
|
| 479 |
- }, |
|
| 480 |
- }, |
|
| 481 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 482 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 483 |
- Template: testapi.OkPodTemplate(), |
|
| 484 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 485 |
- testapi.OkImageChangeTrigger(), |
|
| 486 |
- }, |
|
| 487 |
- }, |
|
| 488 |
- }, |
|
| 489 |
- |
|
| 490 |
- expected: true, |
|
| 491 |
- expectedCauses: testapi.OkImageChangeDetails().Causes, |
|
| 492 |
- }, |
|
| 493 |
- {
|
|
| 494 |
- name: "image change trigger only [automatic=true][no change]", |
|
| 495 |
- |
|
| 496 |
- config: &deployapi.DeploymentConfig{
|
|
| 497 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 498 |
- Template: testapi.OkPodTemplate(), |
|
| 499 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 500 |
- testapi.OkImageChangeTrigger(), |
|
| 501 |
- }, |
|
| 502 |
- }, |
|
| 503 |
- }, |
|
| 504 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 505 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 506 |
- Template: testapi.OkPodTemplate(), |
|
| 507 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 508 |
- testapi.OkImageChangeTrigger(), |
|
| 509 |
- }, |
|
| 510 |
- }, |
|
| 511 |
- }, |
|
| 512 |
- |
|
| 513 |
- expected: false, |
|
| 514 |
- expectedCauses: nil, |
|
| 515 |
- }, |
|
| 516 |
- {
|
|
| 517 |
- name: "config change and image change trigger [automatic=false][initial][image resolved]", |
|
| 518 |
- |
|
| 519 |
- config: &deployapi.DeploymentConfig{
|
|
| 520 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 521 |
- Template: testapi.OkPodTemplateChanged(), |
|
| 522 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 523 |
- testapi.OkConfigChangeTrigger(), |
|
| 524 |
- testapi.OkTriggeredNonAutomatic(), |
|
| 525 |
- }, |
|
| 526 |
- }, |
|
| 527 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 528 |
- }, |
|
| 529 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 530 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 531 |
- Template: testapi.OkPodTemplate(), |
|
| 532 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 533 |
- testapi.OkConfigChangeTrigger(), |
|
| 534 |
- testapi.OkNonAutomaticICT(), |
|
| 535 |
- }, |
|
| 536 |
- }, |
|
| 537 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 538 |
- }, |
|
| 539 |
- |
|
| 540 |
- expected: true, |
|
| 541 |
- expectedCauses: testapi.OkConfigChangeDetails().Causes, |
|
| 542 |
- }, |
|
| 543 |
- {
|
|
| 544 |
- name: "config change and image change trigger [automatic=false][initial]", |
|
| 545 |
- |
|
| 546 |
- config: &deployapi.DeploymentConfig{
|
|
| 547 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 548 |
- Template: testapi.OkPodTemplate(), |
|
| 549 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 550 |
- testapi.OkConfigChangeTrigger(), |
|
| 551 |
- testapi.OkNonAutomaticICT(), // Image is not resolved yet |
|
| 552 |
- }, |
|
| 553 |
- }, |
|
| 554 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 555 |
- }, |
|
| 556 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 557 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 558 |
- Template: testapi.OkPodTemplate(), |
|
| 559 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 560 |
- testapi.OkConfigChangeTrigger(), |
|
| 561 |
- testapi.OkNonAutomaticICT(), |
|
| 562 |
- }, |
|
| 563 |
- }, |
|
| 564 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 565 |
- }, |
|
| 566 |
- |
|
| 567 |
- expected: false, |
|
| 568 |
- expectedCauses: nil, |
|
| 569 |
- }, |
|
| 570 |
- {
|
|
| 571 |
- name: "config change and image change trigger [automatic=true][initial]", |
|
| 572 |
- |
|
| 573 |
- config: &deployapi.DeploymentConfig{
|
|
| 574 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 575 |
- Template: testapi.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated |
|
| 576 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 577 |
- testapi.OkConfigChangeTrigger(), |
|
| 578 |
- testapi.OkImageChangeTrigger(), |
|
| 579 |
- }, |
|
| 580 |
- }, |
|
| 581 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 582 |
- }, |
|
| 583 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 584 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 585 |
- Template: testapi.OkPodTemplate(), |
|
| 586 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 587 |
- testapi.OkConfigChangeTrigger(), |
|
| 588 |
- testapi.OkImageChangeTrigger(), |
|
| 589 |
- }, |
|
| 590 |
- }, |
|
| 591 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 592 |
- }, |
|
| 593 |
- |
|
| 594 |
- expected: false, |
|
| 595 |
- expectedCauses: nil, |
|
| 596 |
- }, |
|
| 597 |
- {
|
|
| 598 |
- name: "config change and image change trigger [automatic=true][initial][image triggered]", |
|
| 599 |
- |
|
| 600 |
- config: &deployapi.DeploymentConfig{
|
|
| 601 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 602 |
- Template: testapi.OkPodTemplateChanged(), |
|
| 603 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 604 |
- testapi.OkConfigChangeTrigger(), |
|
| 605 |
- testapi.OkTriggeredImageChange(), |
|
| 606 |
- }, |
|
| 607 |
- }, |
|
| 608 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 609 |
- }, |
|
| 610 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 611 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 612 |
- Template: testapi.OkPodTemplate(), |
|
| 613 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 614 |
- testapi.OkConfigChangeTrigger(), |
|
| 615 |
- testapi.OkImageChangeTrigger(), |
|
| 616 |
- }, |
|
| 617 |
- }, |
|
| 618 |
- Status: testapi.OkDeploymentConfigStatus(0), |
|
| 619 |
- }, |
|
| 620 |
- |
|
| 621 |
- expected: true, |
|
| 622 |
- expectedCauses: testapi.OkImageChangeDetails().Causes, |
|
| 623 |
- }, |
|
| 624 |
- {
|
|
| 625 |
- name: "config change and image change trigger [automatic=true][no change]", |
|
| 121 |
+ fake := &testclient.Fake{}
|
|
| 122 |
+ fake.AddReactor("update", "deploymentconfigs/instantiate", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 123 |
+ updated = true |
|
| 124 |
+ return true, nil, nil |
|
| 125 |
+ }) |
|
| 626 | 126 |
|
| 627 |
- config: &deployapi.DeploymentConfig{
|
|
| 628 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 629 |
- Template: testapi.OkPodTemplate(), |
|
| 630 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 631 |
- testapi.OkConfigChangeTrigger(), |
|
| 632 |
- testapi.OkImageChangeTrigger(), |
|
| 633 |
- }, |
|
| 634 |
- }, |
|
| 635 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 636 |
- }, |
|
| 637 |
- decoded: &deployapi.DeploymentConfig{
|
|
| 638 |
- Spec: deployapi.DeploymentConfigSpec{
|
|
| 639 |
- Template: testapi.OkPodTemplate(), |
|
| 640 |
- Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 641 |
- testapi.OkConfigChangeTrigger(), |
|
| 642 |
- testapi.OkImageChangeTrigger(), |
|
| 643 |
- }, |
|
| 644 |
- }, |
|
| 645 |
- Status: testapi.OkDeploymentConfigStatus(1), |
|
| 646 |
- }, |
|
| 127 |
+ controller := NewDeploymentTriggerController(dcInformer, streamInformer, fake, codec) |
|
| 647 | 128 |
|
| 648 |
- expected: false, |
|
| 649 |
- expectedCauses: nil, |
|
| 650 |
- }, |
|
| 129 |
+ config := testapi.OkDeploymentConfig(0) |
|
| 130 |
+ config.Namespace = kapi.NamespaceDefault |
|
| 131 |
+ config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{testapi.OkImageChangeTrigger()}
|
|
| 132 |
+ if err := controller.Handle(config); err != nil {
|
|
| 133 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 651 | 134 |
} |
| 652 |
- |
|
| 653 |
- for _, test := range tests {
|
|
| 654 |
- got, gotCauses := canTrigger(test.config, test.decoded) |
|
| 655 |
- if test.expected != got {
|
|
| 656 |
- t.Errorf("%s: expected to trigger: %t, got: %t", test.name, test.expected, got)
|
|
| 657 |
- continue |
|
| 658 |
- } |
|
| 659 |
- if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) {
|
|
| 660 |
- t.Errorf("%s: expected causes:\n%#v\ngot:\n%#v", test.name, test.expectedCauses, gotCauses)
|
|
| 661 |
- } |
|
| 135 |
+ if !updated {
|
|
| 136 |
+ t.Fatalf("expected config to be instantiated")
|
|
| 662 | 137 |
} |
| 663 | 138 |
} |
| ... | ... |
@@ -5,7 +5,6 @@ import ( |
| 5 | 5 |
|
| 6 | 6 |
"github.com/golang/glog" |
| 7 | 7 |
|
| 8 |
- kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
| 9 | 8 |
kcontroller "k8s.io/kubernetes/pkg/controller" |
| 10 | 9 |
"k8s.io/kubernetes/pkg/controller/framework" |
| 11 | 10 |
"k8s.io/kubernetes/pkg/runtime" |
| ... | ... |
@@ -29,10 +28,9 @@ const ( |
| 29 | 29 |
) |
| 30 | 30 |
|
| 31 | 31 |
// NewDeploymentTriggerController returns a new DeploymentTriggerController. |
| 32 |
-func NewDeploymentTriggerController(dcInformer, streamInformer framework.SharedIndexInformer, oc osclient.Interface, kc kclient.Interface, codec runtime.Codec) *DeploymentTriggerController {
|
|
| 32 |
+func NewDeploymentTriggerController(dcInformer, streamInformer framework.SharedIndexInformer, oc osclient.Interface, codec runtime.Codec) *DeploymentTriggerController {
|
|
| 33 | 33 |
c := &DeploymentTriggerController{
|
| 34 | 34 |
dn: oc, |
| 35 |
- rn: kc, |
|
| 36 | 35 |
|
| 37 | 36 |
queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), |
| 38 | 37 |
|
| ... | ... |
@@ -46,11 +44,10 @@ func NewDeploymentTriggerController(dcInformer, streamInformer framework.SharedI |
| 46 | 46 |
}) |
| 47 | 47 |
c.dcStoreSynced = dcInformer.HasSynced |
| 48 | 48 |
|
| 49 |
- // TODO: Re-enable in https://github.com/openshift/origin/pull/9349 |
|
| 50 |
- // streamInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
|
|
| 51 |
- // AddFunc: c.addImageStream, |
|
| 52 |
- // UpdateFunc: c.updateImageStream, |
|
| 53 |
- // }) |
|
| 49 |
+ streamInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
|
|
| 50 |
+ AddFunc: c.addImageStream, |
|
| 51 |
+ UpdateFunc: c.updateImageStream, |
|
| 52 |
+ }) |
|
| 54 | 53 |
|
| 55 | 54 |
return c |
| 56 | 55 |
} |
| ... | ... |
@@ -92,6 +89,9 @@ func (c *DeploymentTriggerController) waitForSyncedStore(ready chan<- struct{},
|
| 92 | 92 |
|
| 93 | 93 |
func (c *DeploymentTriggerController) addDeploymentConfig(obj interface{}) {
|
| 94 | 94 |
dc := obj.(*deployapi.DeploymentConfig) |
| 95 |
+ if len(dc.Spec.Triggers) == 0 || dc.Spec.Paused {
|
|
| 96 |
+ return |
|
| 97 |
+ } |
|
| 95 | 98 |
c.enqueueDeploymentConfig(dc) |
| 96 | 99 |
} |
| 97 | 100 |
|
| ... | ... |
@@ -103,6 +103,10 @@ func (c *DeploymentTriggerController) updateDeploymentConfig(old, cur interface{
|
| 103 | 103 |
return |
| 104 | 104 |
} |
| 105 | 105 |
|
| 106 |
+ if len(newDc.Spec.Triggers) == 0 || newDc.Spec.Paused {
|
|
| 107 |
+ return |
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 106 | 110 |
c.enqueueDeploymentConfig(newDc) |
| 107 | 111 |
} |
| 108 | 112 |
|
| 109 | 113 |
deleted file mode 100644 |
| ... | ... |
@@ -1,161 +0,0 @@ |
| 1 |
-package imagechange |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "fmt" |
|
| 5 |
- |
|
| 6 |
- "github.com/golang/glog" |
|
| 7 |
- |
|
| 8 |
- utilruntime "k8s.io/kubernetes/pkg/util/runtime" |
|
| 9 |
- "k8s.io/kubernetes/pkg/util/sets" |
|
| 10 |
- "k8s.io/kubernetes/pkg/util/workqueue" |
|
| 11 |
- |
|
| 12 |
- "github.com/openshift/origin/pkg/client" |
|
| 13 |
- oscache "github.com/openshift/origin/pkg/client/cache" |
|
| 14 |
- deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 15 |
- deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 16 |
- imageapi "github.com/openshift/origin/pkg/image/api" |
|
| 17 |
-) |
|
| 18 |
- |
|
| 19 |
-// ImageChangeController increments the version of a deployment config which has an image |
|
| 20 |
-// change trigger when a tag update to a triggered ImageStream is detected. |
|
| 21 |
-// |
|
| 22 |
-// Use the ImageChangeControllerFactory to create this controller. |
|
| 23 |
-type ImageChangeController struct {
|
|
| 24 |
- dn client.DeploymentConfigsNamespacer |
|
| 25 |
- |
|
| 26 |
- // queue contains deployment configs that need to be synced. |
|
| 27 |
- queue workqueue.RateLimitingInterface |
|
| 28 |
- |
|
| 29 |
- // streamLister provides a local cache for image streams. |
|
| 30 |
- streamLister oscache.StoreToImageStreamLister |
|
| 31 |
- // dcLister provides a local cache for deployment configs. |
|
| 32 |
- dcLister oscache.StoreToDeploymentConfigLister |
|
| 33 |
- |
|
| 34 |
- // streamStoreSynced makes sure the stream store is synced before reconcling any image stream. |
|
| 35 |
- streamStoreSynced func() bool |
|
| 36 |
- // dcStoreSynced makes sure the dc store is synced before reconcling any image stream. |
|
| 37 |
- dcStoreSynced func() bool |
|
| 38 |
-} |
|
| 39 |
- |
|
| 40 |
-// fatalError is an error which can't be retried. |
|
| 41 |
-type fatalError string |
|
| 42 |
- |
|
| 43 |
-func (e fatalError) Error() string {
|
|
| 44 |
- return fmt.Sprintf("fatal error handling image stream: %s", string(e))
|
|
| 45 |
-} |
|
| 46 |
- |
|
| 47 |
-// Handle processes image change triggers associated with imagestream. |
|
| 48 |
-func (c *ImageChangeController) Handle(stream *imageapi.ImageStream) error {
|
|
| 49 |
- configs, err := c.dcLister.GetConfigsForImageStream(stream) |
|
| 50 |
- if err != nil {
|
|
| 51 |
- return fmt.Errorf("couldn't get list of deployment configs while handling image stream %q: %v", imageapi.LabelForStream(stream), err)
|
|
| 52 |
- } |
|
| 53 |
- |
|
| 54 |
- // Find any configs which should be updated based on the new image state |
|
| 55 |
- var configsToUpdate []*deployapi.DeploymentConfig |
|
| 56 |
- for n, config := range configs {
|
|
| 57 |
- glog.V(4).Infof("Detecting image changes for deployment config %q", deployutil.LabelForDeploymentConfig(config))
|
|
| 58 |
- hasImageChange := false |
|
| 59 |
- |
|
| 60 |
- for j := range config.Spec.Triggers {
|
|
| 61 |
- // because config can be copied during this loop, make sure we load from config for subsequent loops |
|
| 62 |
- trigger := config.Spec.Triggers[j] |
|
| 63 |
- params := trigger.ImageChangeParams |
|
| 64 |
- |
|
| 65 |
- // Only automatic image change triggers should fire |
|
| 66 |
- if trigger.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 67 |
- continue |
|
| 68 |
- } |
|
| 69 |
- |
|
| 70 |
- // All initial deployments should have their images resolved in order to |
|
| 71 |
- // be able to work and not try to pull non-existent images from DockerHub. |
|
| 72 |
- // Deployments with automatic set to false that have been deployed at least |
|
| 73 |
- // once shouldn't have their images updated. |
|
| 74 |
- if (!params.Automatic || config.Spec.Paused) && len(params.LastTriggeredImage) > 0 {
|
|
| 75 |
- continue |
|
| 76 |
- } |
|
| 77 |
- |
|
| 78 |
- // Check if the image stream matches the trigger |
|
| 79 |
- if !triggerMatchesImage(config, params, stream) {
|
|
| 80 |
- continue |
|
| 81 |
- } |
|
| 82 |
- |
|
| 83 |
- _, tag, ok := imageapi.SplitImageStreamTag(params.From.Name) |
|
| 84 |
- if !ok {
|
|
| 85 |
- glog.Warningf("Invalid image stream tag %q in %q", params.From.Name, deployutil.LabelForDeploymentConfig(config))
|
|
| 86 |
- continue |
|
| 87 |
- } |
|
| 88 |
- |
|
| 89 |
- // Find the latest tag event for the trigger tag |
|
| 90 |
- latestEvent := imageapi.LatestTaggedImage(stream, tag) |
|
| 91 |
- if latestEvent == nil {
|
|
| 92 |
- glog.V(5).Infof("Couldn't find latest tag event for tag %q in image stream %q", tag, imageapi.LabelForStream(stream))
|
|
| 93 |
- continue |
|
| 94 |
- } |
|
| 95 |
- |
|
| 96 |
- // Ensure a change occurred |
|
| 97 |
- if len(latestEvent.DockerImageReference) == 0 || latestEvent.DockerImageReference == params.LastTriggeredImage {
|
|
| 98 |
- glog.V(4).Infof("No image changes for deployment config %q were detected", deployutil.LabelForDeploymentConfig(config))
|
|
| 99 |
- continue |
|
| 100 |
- } |
|
| 101 |
- |
|
| 102 |
- names := sets.NewString(params.ContainerNames...) |
|
| 103 |
- for i := range config.Spec.Template.Spec.Containers {
|
|
| 104 |
- container := &config.Spec.Template.Spec.Containers[i] |
|
| 105 |
- if !names.Has(container.Name) {
|
|
| 106 |
- continue |
|
| 107 |
- } |
|
| 108 |
- |
|
| 109 |
- if !hasImageChange {
|
|
| 110 |
- // create a copy prior to mutation |
|
| 111 |
- result, err := deployutil.DeploymentConfigDeepCopy(configs[n]) |
|
| 112 |
- if err != nil {
|
|
| 113 |
- utilruntime.HandleError(err) |
|
| 114 |
- continue |
|
| 115 |
- } |
|
| 116 |
- configs[n] = result |
|
| 117 |
- container = &configs[n].Spec.Template.Spec.Containers[i] |
|
| 118 |
- params = configs[n].Spec.Triggers[j].ImageChangeParams |
|
| 119 |
- } |
|
| 120 |
- |
|
| 121 |
- // Update the image |
|
| 122 |
- container.Image = latestEvent.DockerImageReference |
|
| 123 |
- // Log the last triggered image ID |
|
| 124 |
- params.LastTriggeredImage = latestEvent.DockerImageReference |
|
| 125 |
- hasImageChange = true |
|
| 126 |
- } |
|
| 127 |
- } |
|
| 128 |
- |
|
| 129 |
- if hasImageChange {
|
|
| 130 |
- configsToUpdate = append(configsToUpdate, configs[n]) |
|
| 131 |
- } |
|
| 132 |
- } |
|
| 133 |
- |
|
| 134 |
- // Attempt to regenerate all configs which may contain image updates |
|
| 135 |
- anyFailed := false |
|
| 136 |
- for _, config := range configsToUpdate {
|
|
| 137 |
- if _, err := c.dn.DeploymentConfigs(config.Namespace).Update(config); err != nil {
|
|
| 138 |
- utilruntime.HandleError(err) |
|
| 139 |
- anyFailed = true |
|
| 140 |
- } else {
|
|
| 141 |
- glog.V(4).Infof("Updated deployment config %q for trigger on image stream %q",
|
|
| 142 |
- deployutil.LabelForDeploymentConfig(config), imageapi.LabelForStream(stream)) |
|
| 143 |
- } |
|
| 144 |
- } |
|
| 145 |
- |
|
| 146 |
- if anyFailed {
|
|
| 147 |
- return fmt.Errorf("couldn't update some deployment configs for trigger on image stream %q", imageapi.LabelForStream(stream))
|
|
| 148 |
- } |
|
| 149 |
- |
|
| 150 |
- return nil |
|
| 151 |
-} |
|
| 152 |
- |
|
| 153 |
-// triggerMatchesImage decides whether a given trigger for config matches the provided image stream. |
|
| 154 |
-func triggerMatchesImage(config *deployapi.DeploymentConfig, params *deployapi.DeploymentTriggerImageChangeParams, stream *imageapi.ImageStream) bool {
|
|
| 155 |
- namespace := params.From.Namespace |
|
| 156 |
- if len(namespace) == 0 {
|
|
| 157 |
- namespace = config.Namespace |
|
| 158 |
- } |
|
| 159 |
- name, _, ok := imageapi.SplitImageStreamTag(params.From.Name) |
|
| 160 |
- return stream.Namespace == namespace && stream.Name == name && ok |
|
| 161 |
-} |
| 162 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,242 +0,0 @@ |
| 1 |
-package imagechange |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "flag" |
|
| 5 |
- "testing" |
|
| 6 |
- "time" |
|
| 7 |
- |
|
| 8 |
- kapi "k8s.io/kubernetes/pkg/api" |
|
| 9 |
- "k8s.io/kubernetes/pkg/client/cache" |
|
| 10 |
- ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient" |
|
| 11 |
- "k8s.io/kubernetes/pkg/controller/framework" |
|
| 12 |
- "k8s.io/kubernetes/pkg/runtime" |
|
| 13 |
- |
|
| 14 |
- oscache "github.com/openshift/origin/pkg/client/cache" |
|
| 15 |
- "github.com/openshift/origin/pkg/client/testclient" |
|
| 16 |
- deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 17 |
- testapi "github.com/openshift/origin/pkg/deploy/api/test" |
|
| 18 |
- imageapi "github.com/openshift/origin/pkg/image/api" |
|
| 19 |
-) |
|
| 20 |
- |
|
| 21 |
-var ( |
|
| 22 |
- dcInformer = framework.NewSharedIndexInformer( |
|
| 23 |
- &cache.ListWatch{},
|
|
| 24 |
- &deployapi.DeploymentConfig{},
|
|
| 25 |
- 2*time.Minute, |
|
| 26 |
- cache.Indexers{oscache.ImageStreamReferenceIndex: oscache.ImageStreamReferenceIndexFunc},
|
|
| 27 |
- ) |
|
| 28 |
- streamInformer = framework.NewSharedIndexInformer( |
|
| 29 |
- &cache.ListWatch{},
|
|
| 30 |
- &imageapi.ImageStream{},
|
|
| 31 |
- 2*time.Minute, |
|
| 32 |
- cache.Indexers{},
|
|
| 33 |
- ) |
|
| 34 |
-) |
|
| 35 |
- |
|
| 36 |
-func init() {
|
|
| 37 |
- flag.Set("v", "5")
|
|
| 38 |
-} |
|
| 39 |
- |
|
| 40 |
-func makeStream(name, tag, dir, image string) *imageapi.ImageStream {
|
|
| 41 |
- return &imageapi.ImageStream{
|
|
| 42 |
- ObjectMeta: kapi.ObjectMeta{Name: name, Namespace: kapi.NamespaceDefault},
|
|
| 43 |
- Status: imageapi.ImageStreamStatus{
|
|
| 44 |
- Tags: map[string]imageapi.TagEventList{
|
|
| 45 |
- tag: {
|
|
| 46 |
- Items: []imageapi.TagEvent{
|
|
| 47 |
- {
|
|
| 48 |
- DockerImageReference: dir, |
|
| 49 |
- Image: image, |
|
| 50 |
- }, |
|
| 51 |
- }, |
|
| 52 |
- }, |
|
| 53 |
- }, |
|
| 54 |
- }, |
|
| 55 |
- } |
|
| 56 |
-} |
|
| 57 |
- |
|
| 58 |
-// TestHandle_changeForNonAutomaticTag ensures that an image update for which |
|
| 59 |
-// there is a matching trigger results in a no-op due to the trigger's |
|
| 60 |
-// automatic flag being set to false. |
|
| 61 |
-func TestHandle_changeForNonAutomaticTag(t *testing.T) {
|
|
| 62 |
- fake := &testclient.Fake{}
|
|
| 63 |
- fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 64 |
- t.Fatalf("unexpected deploymentconfig update")
|
|
| 65 |
- return true, nil, nil |
|
| 66 |
- }) |
|
| 67 |
- |
|
| 68 |
- controller := NewImageChangeController(dcInformer, streamInformer, fake) |
|
| 69 |
- |
|
| 70 |
- config := testapi.OkDeploymentConfig(1) |
|
| 71 |
- config.Namespace = kapi.NamespaceDefault |
|
| 72 |
- config.Spec.Triggers[0].ImageChangeParams.Automatic = false |
|
| 73 |
- // The image has been resolved at least once before. |
|
| 74 |
- config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = testapi.DockerImageReference |
|
| 75 |
- controller.dcLister.Add(config) |
|
| 76 |
- |
|
| 77 |
- // verify no-op |
|
| 78 |
- tagUpdate := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID) |
|
| 79 |
- |
|
| 80 |
- if err := controller.Handle(tagUpdate); err != nil {
|
|
| 81 |
- t.Fatalf("unexpected err: %v", err)
|
|
| 82 |
- } |
|
| 83 |
- |
|
| 84 |
- if len(fake.Actions()) > 0 {
|
|
| 85 |
- t.Fatalf("unexpected actions: %v", fake.Actions())
|
|
| 86 |
- } |
|
| 87 |
-} |
|
| 88 |
- |
|
| 89 |
-// TestHandle_changeForInitialNonAutomaticDeployment ensures that an image update for which |
|
| 90 |
-// there is a matching trigger will actually update the deployment config if it hasn't been |
|
| 91 |
-// deployed before. |
|
| 92 |
-func TestHandle_changeForInitialNonAutomaticDeployment(t *testing.T) {
|
|
| 93 |
- fake := &testclient.Fake{}
|
|
| 94 |
- |
|
| 95 |
- controller := NewImageChangeController(dcInformer, streamInformer, fake) |
|
| 96 |
- |
|
| 97 |
- config := testapi.OkDeploymentConfig(0) |
|
| 98 |
- config.Namespace = kapi.NamespaceDefault |
|
| 99 |
- config.Spec.Triggers[0].ImageChangeParams.Automatic = false |
|
| 100 |
- config.Spec.Triggers[0].ImageChangeParams.From.Namespace = kapi.NamespaceDefault |
|
| 101 |
- controller.dcLister.Indexer.Add(config) |
|
| 102 |
- |
|
| 103 |
- tagUpdate := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID) |
|
| 104 |
- |
|
| 105 |
- if err := controller.Handle(tagUpdate); err != nil {
|
|
| 106 |
- t.Fatalf("unexpected err: %v", err)
|
|
| 107 |
- } |
|
| 108 |
- |
|
| 109 |
- actions := fake.Actions() |
|
| 110 |
- if len(actions) != 1 {
|
|
| 111 |
- t.Fatalf("unexpected amount of actions: expected 1, got %d (%v)", len(actions), actions)
|
|
| 112 |
- } |
|
| 113 |
- if !actions[0].Matches("update", "deploymentconfigs") {
|
|
| 114 |
- t.Fatalf("unexpected action: %v", actions[0])
|
|
| 115 |
- } |
|
| 116 |
-} |
|
| 117 |
- |
|
| 118 |
-// TestHandle_changeForUnregisteredTag ensures that an image update for which |
|
| 119 |
-// there is a matching trigger results in a no-op due to the tag specified on |
|
| 120 |
-// the trigger not matching the tags defined on the image stream. |
|
| 121 |
-func TestHandle_changeForUnregisteredTag(t *testing.T) {
|
|
| 122 |
- fake := &testclient.Fake{}
|
|
| 123 |
- fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 124 |
- t.Fatalf("unexpected deploymentconfig update")
|
|
| 125 |
- return true, nil, nil |
|
| 126 |
- }) |
|
| 127 |
- |
|
| 128 |
- controller := NewImageChangeController(dcInformer, streamInformer, fake) |
|
| 129 |
- |
|
| 130 |
- config := testapi.OkDeploymentConfig(0) |
|
| 131 |
- controller.dcLister.Add(&config) |
|
| 132 |
- |
|
| 133 |
- // verify no-op |
|
| 134 |
- tagUpdate := makeStream(testapi.ImageStreamName, "unrecognized", testapi.DockerImageReference, testapi.ImageID) |
|
| 135 |
- |
|
| 136 |
- if err := controller.Handle(tagUpdate); err != nil {
|
|
| 137 |
- t.Fatalf("unexpected err: %v", err)
|
|
| 138 |
- } |
|
| 139 |
- |
|
| 140 |
- if len(fake.Actions()) > 0 {
|
|
| 141 |
- t.Fatalf("unexpected actions: %v", fake.Actions())
|
|
| 142 |
- } |
|
| 143 |
-} |
|
| 144 |
- |
|
| 145 |
-// TestHandle_matchScenarios comprehensively tests trigger definitions against |
|
| 146 |
-// image stream updates to ensure that the image change triggers match (or don't |
|
| 147 |
-// match) properly. |
|
| 148 |
-func TestHandle_matchScenarios(t *testing.T) {
|
|
| 149 |
- tests := []struct {
|
|
| 150 |
- name string |
|
| 151 |
- |
|
| 152 |
- param *deployapi.DeploymentTriggerImageChangeParams |
|
| 153 |
- matches bool |
|
| 154 |
- }{
|
|
| 155 |
- {
|
|
| 156 |
- name: "automatic=true, initial trigger", |
|
| 157 |
- |
|
| 158 |
- param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 159 |
- Automatic: true, |
|
| 160 |
- ContainerNames: []string{"container1"},
|
|
| 161 |
- From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 162 |
- LastTriggeredImage: "", |
|
| 163 |
- }, |
|
| 164 |
- matches: true, |
|
| 165 |
- }, |
|
| 166 |
- {
|
|
| 167 |
- name: "automatic=false, initial trigger", |
|
| 168 |
- |
|
| 169 |
- param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 170 |
- Automatic: false, |
|
| 171 |
- ContainerNames: []string{"container1"},
|
|
| 172 |
- From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 173 |
- LastTriggeredImage: "", |
|
| 174 |
- }, |
|
| 175 |
- matches: true, |
|
| 176 |
- }, |
|
| 177 |
- {
|
|
| 178 |
- name: "(no-op) automatic=false, already triggered", |
|
| 179 |
- |
|
| 180 |
- param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 181 |
- Automatic: false, |
|
| 182 |
- ContainerNames: []string{"container1"},
|
|
| 183 |
- From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 184 |
- LastTriggeredImage: testapi.DockerImageReference, |
|
| 185 |
- }, |
|
| 186 |
- matches: false, |
|
| 187 |
- }, |
|
| 188 |
- {
|
|
| 189 |
- name: "(no-op) automatic=true, image is already deployed", |
|
| 190 |
- |
|
| 191 |
- param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 192 |
- Automatic: true, |
|
| 193 |
- ContainerNames: []string{"container1"},
|
|
| 194 |
- From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag(testapi.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 195 |
- LastTriggeredImage: testapi.DockerImageReference, |
|
| 196 |
- }, |
|
| 197 |
- matches: false, |
|
| 198 |
- }, |
|
| 199 |
- {
|
|
| 200 |
- name: "(no-op) trigger doesn't match the stream", |
|
| 201 |
- |
|
| 202 |
- param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 203 |
- Automatic: true, |
|
| 204 |
- ContainerNames: []string{"container1"},
|
|
| 205 |
- From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("other-stream", imageapi.DefaultImageTag)},
|
|
| 206 |
- LastTriggeredImage: "", |
|
| 207 |
- }, |
|
| 208 |
- matches: false, |
|
| 209 |
- }, |
|
| 210 |
- } |
|
| 211 |
- |
|
| 212 |
- for _, test := range tests {
|
|
| 213 |
- updated := false |
|
| 214 |
- |
|
| 215 |
- fake := &testclient.Fake{}
|
|
| 216 |
- fake.AddReactor("update", "deploymentconfigs", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 217 |
- if !test.matches {
|
|
| 218 |
- t.Fatal("unexpected deploymentconfig update")
|
|
| 219 |
- } |
|
| 220 |
- updated = true |
|
| 221 |
- return true, nil, nil |
|
| 222 |
- }) |
|
| 223 |
- |
|
| 224 |
- controller := NewImageChangeController(dcInformer, streamInformer, fake) |
|
| 225 |
- |
|
| 226 |
- config := testapi.OkDeploymentConfig(1) |
|
| 227 |
- config.Namespace = kapi.NamespaceDefault |
|
| 228 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{{Type: deployapi.DeploymentTriggerOnImageChange, ImageChangeParams: test.param}}
|
|
| 229 |
- controller.dcLister.Add(config) |
|
| 230 |
- |
|
| 231 |
- t.Logf("running test %q", test.name)
|
|
| 232 |
- stream := makeStream(testapi.ImageStreamName, imageapi.DefaultImageTag, testapi.DockerImageReference, testapi.ImageID) |
|
| 233 |
- if err := controller.Handle(stream); err != nil {
|
|
| 234 |
- t.Fatalf("unexpected error: %v", err)
|
|
| 235 |
- } |
|
| 236 |
- |
|
| 237 |
- // assert updates occurred |
|
| 238 |
- if test.matches && !updated {
|
|
| 239 |
- t.Fatal("expected an update")
|
|
| 240 |
- } |
|
| 241 |
- } |
|
| 242 |
-} |
| 243 | 1 |
deleted file mode 100644 |
| ... | ... |
@@ -1,184 +0,0 @@ |
| 1 |
-package imagechange |
|
| 2 |
- |
|
| 3 |
-import ( |
|
| 4 |
- "time" |
|
| 5 |
- |
|
| 6 |
- "github.com/golang/glog" |
|
| 7 |
- |
|
| 8 |
- kcontroller "k8s.io/kubernetes/pkg/controller" |
|
| 9 |
- "k8s.io/kubernetes/pkg/controller/framework" |
|
| 10 |
- utilruntime "k8s.io/kubernetes/pkg/util/runtime" |
|
| 11 |
- "k8s.io/kubernetes/pkg/util/wait" |
|
| 12 |
- "k8s.io/kubernetes/pkg/util/workqueue" |
|
| 13 |
- |
|
| 14 |
- osclient "github.com/openshift/origin/pkg/client" |
|
| 15 |
- deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 16 |
- deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 17 |
- imageapi "github.com/openshift/origin/pkg/image/api" |
|
| 18 |
-) |
|
| 19 |
- |
|
| 20 |
-const ( |
|
| 21 |
- // We must avoid creating processing image stream until the deployment config and image |
|
| 22 |
- // stream stores have synced. |
|
| 23 |
- storeSyncedPollPeriod = 100 * time.Millisecond |
|
| 24 |
- // MaxRetries is the number of times an image stream will be retried before it is dropped |
|
| 25 |
- // out of the queue. |
|
| 26 |
- MaxRetries = 5 |
|
| 27 |
-) |
|
| 28 |
- |
|
| 29 |
-// NewImageChangeController returns a new ImageChangeController. |
|
| 30 |
-func NewImageChangeController(dcInformer, streamInformer framework.SharedIndexInformer, oc osclient.Interface) *ImageChangeController {
|
|
| 31 |
- c := &ImageChangeController{
|
|
| 32 |
- dn: oc, |
|
| 33 |
- |
|
| 34 |
- queue: workqueue.NewRateLimitingQueue(workqueue.DefaultControllerRateLimiter()), |
|
| 35 |
- } |
|
| 36 |
- |
|
| 37 |
- c.streamLister.Indexer = streamInformer.GetIndexer() |
|
| 38 |
- streamInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
|
|
| 39 |
- AddFunc: c.addImageStream, |
|
| 40 |
- UpdateFunc: c.updateImageStream, |
|
| 41 |
- }) |
|
| 42 |
- c.streamStoreSynced = streamInformer.HasSynced |
|
| 43 |
- |
|
| 44 |
- c.dcLister.Indexer = dcInformer.GetIndexer() |
|
| 45 |
- dcInformer.AddEventHandler(framework.ResourceEventHandlerFuncs{
|
|
| 46 |
- AddFunc: c.addDeploymentConfig, |
|
| 47 |
- UpdateFunc: c.updateDeploymentConfig, |
|
| 48 |
- }) |
|
| 49 |
- c.dcStoreSynced = dcInformer.HasSynced |
|
| 50 |
- |
|
| 51 |
- return c |
|
| 52 |
-} |
|
| 53 |
- |
|
| 54 |
-// Run begins watching and syncing. |
|
| 55 |
-func (c *ImageChangeController) Run(workers int, stopCh <-chan struct{}) {
|
|
| 56 |
- defer utilruntime.HandleCrash() |
|
| 57 |
- |
|
| 58 |
- // Wait for the dc store to sync before starting any work in this controller. |
|
| 59 |
- ready := make(chan struct{})
|
|
| 60 |
- go c.waitForSyncedStore(ready, stopCh) |
|
| 61 |
- select {
|
|
| 62 |
- case <-ready: |
|
| 63 |
- case <-stopCh: |
|
| 64 |
- return |
|
| 65 |
- } |
|
| 66 |
- |
|
| 67 |
- for i := 0; i < workers; i++ {
|
|
| 68 |
- go wait.Until(c.worker, time.Second, stopCh) |
|
| 69 |
- } |
|
| 70 |
- <-stopCh |
|
| 71 |
- glog.Infof("Shutting down image change controller")
|
|
| 72 |
- c.queue.ShutDown() |
|
| 73 |
-} |
|
| 74 |
- |
|
| 75 |
-func (c *ImageChangeController) waitForSyncedStore(ready chan<- struct{}, stopCh <-chan struct{}) {
|
|
| 76 |
- defer utilruntime.HandleCrash() |
|
| 77 |
- |
|
| 78 |
- for !c.streamStoreSynced() || !c.dcStoreSynced() {
|
|
| 79 |
- glog.V(4).Infof("Waiting for the image stream and deployment config caches to sync before starting the image change controller workers")
|
|
| 80 |
- select {
|
|
| 81 |
- case <-time.After(storeSyncedPollPeriod): |
|
| 82 |
- case <-stopCh: |
|
| 83 |
- return |
|
| 84 |
- } |
|
| 85 |
- } |
|
| 86 |
- close(ready) |
|
| 87 |
-} |
|
| 88 |
- |
|
| 89 |
-func (c *ImageChangeController) addImageStream(obj interface{}) {
|
|
| 90 |
- stream := obj.(*imageapi.ImageStream) |
|
| 91 |
- c.enqueueImageStream(stream) |
|
| 92 |
-} |
|
| 93 |
- |
|
| 94 |
-func (c *ImageChangeController) updateImageStream(old, cur interface{}) {
|
|
| 95 |
- // A periodic relist will send update events for all known streams. |
|
| 96 |
- newStream := cur.(*imageapi.ImageStream) |
|
| 97 |
- oldStream := old.(*imageapi.ImageStream) |
|
| 98 |
- if newStream.ResourceVersion == oldStream.ResourceVersion {
|
|
| 99 |
- return |
|
| 100 |
- } |
|
| 101 |
- |
|
| 102 |
- c.enqueueImageStream(newStream) |
|
| 103 |
-} |
|
| 104 |
- |
|
| 105 |
-// addDeploymentConfig is used for making sure that new deployment configs with triggers pointing |
|
| 106 |
-// to existing images will be deployed as soon as they are created. |
|
| 107 |
-func (c *ImageChangeController) addDeploymentConfig(obj interface{}) {
|
|
| 108 |
- dc := obj.(*deployapi.DeploymentConfig) |
|
| 109 |
- for _, stream := range c.streamLister.GetStreamsForConfig(dc) {
|
|
| 110 |
- glog.V(4).Infof("Reconciling stream %q for config %q\n", imageapi.LabelForStream(stream), deployutil.LabelForDeploymentConfig(dc))
|
|
| 111 |
- c.enqueueImageStream(stream) |
|
| 112 |
- } |
|
| 113 |
-} |
|
| 114 |
- |
|
| 115 |
-// updateDeploymentConfig is used for making sure that deployment configs with new triggers |
|
| 116 |
-// pointing to existing images will be deployed as soon as they are updated. |
|
| 117 |
-func (c *ImageChangeController) updateDeploymentConfig(old, cur interface{}) {
|
|
| 118 |
- // A periodic relist will send update events for all known configs. |
|
| 119 |
- newDc := cur.(*deployapi.DeploymentConfig) |
|
| 120 |
- oldDc := old.(*deployapi.DeploymentConfig) |
|
| 121 |
- if newDc.ResourceVersion == oldDc.ResourceVersion {
|
|
| 122 |
- return |
|
| 123 |
- } |
|
| 124 |
- |
|
| 125 |
- for _, stream := range c.streamLister.GetStreamsForConfig(newDc) {
|
|
| 126 |
- glog.V(4).Infof("Reconciling stream %q for config %q\n", imageapi.LabelForStream(stream), deployutil.LabelForDeploymentConfig(newDc))
|
|
| 127 |
- c.enqueueImageStream(stream) |
|
| 128 |
- } |
|
| 129 |
-} |
|
| 130 |
- |
|
| 131 |
-func (c *ImageChangeController) enqueueImageStream(stream *imageapi.ImageStream) {
|
|
| 132 |
- key, err := kcontroller.KeyFunc(stream) |
|
| 133 |
- if err != nil {
|
|
| 134 |
- glog.Errorf("Couldn't get key for object %+v: %v", stream, err)
|
|
| 135 |
- return |
|
| 136 |
- } |
|
| 137 |
- c.queue.Add(key) |
|
| 138 |
-} |
|
| 139 |
- |
|
| 140 |
-func (c *ImageChangeController) worker() {
|
|
| 141 |
- for {
|
|
| 142 |
- if quit := c.work(); quit {
|
|
| 143 |
- return |
|
| 144 |
- } |
|
| 145 |
- } |
|
| 146 |
-} |
|
| 147 |
- |
|
| 148 |
-func (c *ImageChangeController) work() bool {
|
|
| 149 |
- key, quit := c.queue.Get() |
|
| 150 |
- if quit {
|
|
| 151 |
- return true |
|
| 152 |
- } |
|
| 153 |
- defer c.queue.Done(key) |
|
| 154 |
- |
|
| 155 |
- stream, err := c.getByKey(key.(string)) |
|
| 156 |
- if err != nil {
|
|
| 157 |
- glog.Error(err.Error()) |
|
| 158 |
- } |
|
| 159 |
- |
|
| 160 |
- if stream == nil {
|
|
| 161 |
- return false |
|
| 162 |
- } |
|
| 163 |
- |
|
| 164 |
- if err := c.Handle(stream); err != nil {
|
|
| 165 |
- utilruntime.HandleError(err) |
|
| 166 |
- } |
|
| 167 |
- |
|
| 168 |
- return false |
|
| 169 |
-} |
|
| 170 |
- |
|
| 171 |
-func (c *ImageChangeController) getByKey(key string) (*imageapi.ImageStream, error) {
|
|
| 172 |
- obj, exists, err := c.streamLister.Indexer.GetByKey(key) |
|
| 173 |
- if err != nil {
|
|
| 174 |
- glog.Infof("Unable to retrieve image stream %q from store: %v", key, err)
|
|
| 175 |
- c.queue.Add(key) |
|
| 176 |
- return nil, err |
|
| 177 |
- } |
|
| 178 |
- if !exists {
|
|
| 179 |
- glog.Infof("Image stream %q has been deleted", key)
|
|
| 180 |
- return nil, nil |
|
| 181 |
- } |
|
| 182 |
- |
|
| 183 |
- return obj.(*imageapi.ImageStream), nil |
|
| 184 |
-} |
| ... | ... |
@@ -7,7 +7,7 @@ import ( |
| 7 | 7 |
"k8s.io/kubernetes/pkg/api/errors" |
| 8 | 8 |
"k8s.io/kubernetes/pkg/api/rest" |
| 9 | 9 |
"k8s.io/kubernetes/pkg/apis/extensions" |
| 10 |
- kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
| 10 |
+ extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" |
|
| 11 | 11 |
"k8s.io/kubernetes/pkg/fields" |
| 12 | 12 |
"k8s.io/kubernetes/pkg/labels" |
| 13 | 13 |
"k8s.io/kubernetes/pkg/registry/generic" |
| ... | ... |
@@ -18,7 +18,6 @@ import ( |
| 18 | 18 |
"github.com/openshift/origin/pkg/deploy/api" |
| 19 | 19 |
"github.com/openshift/origin/pkg/deploy/registry/deployconfig" |
| 20 | 20 |
"github.com/openshift/origin/pkg/util/restoptions" |
| 21 |
- extvalidation "k8s.io/kubernetes/pkg/apis/extensions/validation" |
|
| 22 | 21 |
) |
| 23 | 22 |
|
| 24 | 23 |
// REST contains the REST storage for DeploymentConfig objects. |
| ... | ... |
@@ -29,7 +28,7 @@ type REST struct {
|
| 29 | 29 |
// NewREST returns a deploymentConfigREST containing the REST storage for DeploymentConfig objects, |
| 30 | 30 |
// a statusREST containing the REST storage for changing the status of a DeploymentConfig, |
| 31 | 31 |
// and a scaleREST containing the REST storage for the Scale subresources of DeploymentConfigs. |
| 32 |
-func NewREST(optsGetter restoptions.Getter, rcNamespacer kclient.ReplicationControllersNamespacer) (*REST, *StatusREST, *ScaleREST, error) {
|
|
| 32 |
+func NewREST(optsGetter restoptions.Getter) (*REST, *StatusREST, *ScaleREST, error) {
|
|
| 33 | 33 |
store := ®istry.Store{
|
| 34 | 34 |
NewFunc: func() runtime.Object { return &api.DeploymentConfig{} },
|
| 35 | 35 |
NewListFunc: func() runtime.Object { return &api.DeploymentConfigList{} },
|
| ... | ... |
@@ -54,18 +53,14 @@ func NewREST(optsGetter restoptions.Getter, rcNamespacer kclient.ReplicationCont |
| 54 | 54 |
statusStore := *store |
| 55 | 55 |
statusStore.UpdateStrategy = deployconfig.StatusStrategy |
| 56 | 56 |
statusREST := &StatusREST{store: &statusStore}
|
| 57 |
- scaleREST := &ScaleREST{
|
|
| 58 |
- registry: deployconfig.NewRegistry(deploymentConfigREST), |
|
| 59 |
- rcNamespacer: rcNamespacer, |
|
| 60 |
- } |
|
| 57 |
+ scaleREST := &ScaleREST{registry: deployconfig.NewRegistry(deploymentConfigREST)}
|
|
| 61 | 58 |
|
| 62 | 59 |
return deploymentConfigREST, statusREST, scaleREST, nil |
| 63 | 60 |
} |
| 64 | 61 |
|
| 65 | 62 |
// ScaleREST contains the REST storage for the Scale subresource of DeploymentConfigs. |
| 66 | 63 |
type ScaleREST struct {
|
| 67 |
- registry deployconfig.Registry |
|
| 68 |
- rcNamespacer kclient.ReplicationControllersNamespacer |
|
| 64 |
+ registry deployconfig.Registry |
|
| 69 | 65 |
} |
| 70 | 66 |
|
| 71 | 67 |
// ScaleREST implements Patcher |
| ... | ... |
@@ -3,7 +3,6 @@ package etcd |
| 3 | 3 |
import ( |
| 4 | 4 |
"testing" |
| 5 | 5 |
|
| 6 |
- "k8s.io/kubernetes/pkg/client/unversioned/testclient" |
|
| 7 | 6 |
"k8s.io/kubernetes/pkg/fields" |
| 8 | 7 |
"k8s.io/kubernetes/pkg/labels" |
| 9 | 8 |
"k8s.io/kubernetes/pkg/registry/registrytest" |
| ... | ... |
@@ -18,7 +17,7 @@ import ( |
| 18 | 18 |
|
| 19 | 19 |
func newStorage(t *testing.T) (*REST, *etcdtesting.EtcdTestServer) {
|
| 20 | 20 |
etcdStorage, server := registrytest.NewEtcdStorage(t, "") |
| 21 |
- storage, _, _, err := NewREST(restoptions.NewSimpleGetter(etcdStorage), testclient.NewSimpleFake()) |
|
| 21 |
+ storage, _, _, err := NewREST(restoptions.NewSimpleGetter(etcdStorage)) |
|
| 22 | 22 |
if err != nil {
|
| 23 | 23 |
t.Fatal(err) |
| 24 | 24 |
} |
| ... | ... |
@@ -68,6 +68,8 @@ func (strategy) PrepareForUpdate(ctx kapi.Context, obj, old runtime.Object) {
|
| 68 | 68 |
newDc.Status.LatestVersion = newVersion |
| 69 | 69 |
} |
| 70 | 70 |
|
| 71 |
+ // TODO: Disallow lastTriggeredImage updates from this update path. |
|
| 72 |
+ |
|
| 71 | 73 |
// Any changes to the spec or labels, increment the generation number, any changes |
| 72 | 74 |
// to the status should reflect the generation number of the corresponding object |
| 73 | 75 |
// (should be handled by the controller). |
| 74 | 76 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,295 @@ |
| 0 |
+package instantiate |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "fmt" |
|
| 4 |
+ |
|
| 5 |
+ "github.com/golang/glog" |
|
| 6 |
+ |
|
| 7 |
+ "k8s.io/kubernetes/pkg/admission" |
|
| 8 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 9 |
+ "k8s.io/kubernetes/pkg/api/errors" |
|
| 10 |
+ "k8s.io/kubernetes/pkg/api/rest" |
|
| 11 |
+ "k8s.io/kubernetes/pkg/api/unversioned" |
|
| 12 |
+ kclient "k8s.io/kubernetes/pkg/client/unversioned" |
|
| 13 |
+ "k8s.io/kubernetes/pkg/registry/generic/registry" |
|
| 14 |
+ "k8s.io/kubernetes/pkg/runtime" |
|
| 15 |
+ utilerrors "k8s.io/kubernetes/pkg/util/errors" |
|
| 16 |
+ "k8s.io/kubernetes/pkg/util/sets" |
|
| 17 |
+ |
|
| 18 |
+ "github.com/openshift/origin/pkg/client" |
|
| 19 |
+ deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 20 |
+ "github.com/openshift/origin/pkg/deploy/api/validation" |
|
| 21 |
+ deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 22 |
+ imageapi "github.com/openshift/origin/pkg/image/api" |
|
| 23 |
+) |
|
| 24 |
+ |
|
| 25 |
+func NewREST(store registry.Store, oc client.Interface, kc kclient.Interface, decoder runtime.Decoder, admission admission.Interface) *REST {
|
|
| 26 |
+ store.UpdateStrategy = Strategy |
|
| 27 |
+ return &REST{store: &store, isn: oc, rn: kc, decoder: decoder, admit: admission}
|
|
| 28 |
+} |
|
| 29 |
+ |
|
| 30 |
+// REST implements the Creater interface. |
|
| 31 |
+var _ = rest.Creater(&REST{})
|
|
| 32 |
+ |
|
| 33 |
+type REST struct {
|
|
| 34 |
+ store *registry.Store |
|
| 35 |
+ isn client.ImageStreamsNamespacer |
|
| 36 |
+ rn kclient.ReplicationControllersNamespacer |
|
| 37 |
+ decoder runtime.Decoder |
|
| 38 |
+ admit admission.Interface |
|
| 39 |
+} |
|
| 40 |
+ |
|
| 41 |
+func (s *REST) New() runtime.Object {
|
|
| 42 |
+ return &deployapi.DeploymentRequest{}
|
|
| 43 |
+} |
|
| 44 |
+ |
|
| 45 |
+// Create instantiates a deployment config |
|
| 46 |
+func (r *REST) Create(ctx kapi.Context, obj runtime.Object) (runtime.Object, error) {
|
|
| 47 |
+ req, ok := obj.(*deployapi.DeploymentRequest) |
|
| 48 |
+ if !ok {
|
|
| 49 |
+ return nil, errors.NewBadRequest(fmt.Sprintf("wrong object passed for requesting a new deployment: %#v", obj))
|
|
| 50 |
+ } |
|
| 51 |
+ |
|
| 52 |
+ configObj, err := r.store.Get(ctx, req.Name) |
|
| 53 |
+ if err != nil {
|
|
| 54 |
+ return nil, err |
|
| 55 |
+ } |
|
| 56 |
+ config := configObj.(*deployapi.DeploymentConfig) |
|
| 57 |
+ old := config |
|
| 58 |
+ |
|
| 59 |
+ if errs := validation.ValidateRequestForDeploymentConfig(req, config); len(errs) > 0 {
|
|
| 60 |
+ return nil, errors.NewInvalid(deployapi.Kind("DeploymentRequest"), req.Name, errs)
|
|
| 61 |
+ } |
|
| 62 |
+ |
|
| 63 |
+ // We need to process the deployment config before we can determine if it is possible to trigger |
|
| 64 |
+ // a deployment. |
|
| 65 |
+ if req.Latest {
|
|
| 66 |
+ if err := processTriggers(config, r.isn, req.Force); err != nil {
|
|
| 67 |
+ return nil, err |
|
| 68 |
+ } |
|
| 69 |
+ } |
|
| 70 |
+ |
|
| 71 |
+ canTrigger, causes, err := canTrigger(config, r.rn, r.decoder, req.Force) |
|
| 72 |
+ if err != nil {
|
|
| 73 |
+ return nil, err |
|
| 74 |
+ } |
|
| 75 |
+ // If we cannot trigger then there is nothing to do here. |
|
| 76 |
+ if !canTrigger {
|
|
| 77 |
+ return &unversioned.Status{
|
|
| 78 |
+ Message: fmt.Sprintf("deployment config %q cannot be instantiated", config.Name),
|
|
| 79 |
+ Code: int32(204), |
|
| 80 |
+ }, nil |
|
| 81 |
+ } |
|
| 82 |
+ glog.V(4).Infof("New deployment for %q caused by %#v", config.Name, causes)
|
|
| 83 |
+ |
|
| 84 |
+ config.Status.Details = new(deployapi.DeploymentDetails) |
|
| 85 |
+ config.Status.Details.Causes = causes |
|
| 86 |
+ switch causes[0].Type {
|
|
| 87 |
+ case deployapi.DeploymentTriggerOnConfigChange: |
|
| 88 |
+ config.Status.Details.Message = "config change" |
|
| 89 |
+ case deployapi.DeploymentTriggerOnImageChange: |
|
| 90 |
+ config.Status.Details.Message = "image change" |
|
| 91 |
+ case deployapi.DeploymentTriggerManual: |
|
| 92 |
+ config.Status.Details.Message = "manual change" |
|
| 93 |
+ } |
|
| 94 |
+ config.Status.LatestVersion++ |
|
| 95 |
+ |
|
| 96 |
+ userInfo, _ := kapi.UserFrom(ctx) |
|
| 97 |
+ attrs := admission.NewAttributesRecord(config, old, deployapi.Kind("DeploymentConfig").WithVersion(""), config.Namespace, config.Name, deployapi.Resource("DeploymentConfig").WithVersion(""), "", admission.Update, userInfo)
|
|
| 98 |
+ if err := r.admit.Admit(attrs); err != nil {
|
|
| 99 |
+ return nil, err |
|
| 100 |
+ } |
|
| 101 |
+ |
|
| 102 |
+ updated, _, err := r.store.Update(ctx, config.Name, rest.DefaultUpdatedObjectInfo(config, kapi.Scheme)) |
|
| 103 |
+ return updated, err |
|
| 104 |
+} |
|
| 105 |
+ |
|
| 106 |
+// processTriggers will go over all deployment triggers that require processing and update |
|
| 107 |
+// the deployment config accordingly. This contains the work that the image change controller |
|
| 108 |
+// had been doing up to the point we got the /instantiate endpoint. |
|
| 109 |
+func processTriggers(config *deployapi.DeploymentConfig, isn client.ImageStreamsNamespacer, force bool) error {
|
|
| 110 |
+ errs := []error{}
|
|
| 111 |
+ |
|
| 112 |
+ // Process any image change triggers. |
|
| 113 |
+ for _, trigger := range config.Spec.Triggers {
|
|
| 114 |
+ if trigger.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 115 |
+ continue |
|
| 116 |
+ } |
|
| 117 |
+ |
|
| 118 |
+ params := trigger.ImageChangeParams |
|
| 119 |
+ |
|
| 120 |
+ // Forced deployments should always try to resolve the images in the template. |
|
| 121 |
+ // On the other hand, paused deployments or non-automatic triggers shouldn't. |
|
| 122 |
+ if !force && (config.Spec.Paused || !params.Automatic) {
|
|
| 123 |
+ continue |
|
| 124 |
+ } |
|
| 125 |
+ |
|
| 126 |
+ // Tag references are already validated |
|
| 127 |
+ name, tag, _ := imageapi.SplitImageStreamTag(params.From.Name) |
|
| 128 |
+ stream, err := isn.ImageStreams(params.From.Namespace).Get(name) |
|
| 129 |
+ if err != nil {
|
|
| 130 |
+ if !errors.IsNotFound(err) {
|
|
| 131 |
+ errs = append(errs, err) |
|
| 132 |
+ } |
|
| 133 |
+ continue |
|
| 134 |
+ } |
|
| 135 |
+ |
|
| 136 |
+ // Find the latest tag event for the trigger reference. |
|
| 137 |
+ latestEvent := imageapi.LatestTaggedImage(stream, tag) |
|
| 138 |
+ if latestEvent == nil {
|
|
| 139 |
+ continue |
|
| 140 |
+ } |
|
| 141 |
+ |
|
| 142 |
+ // Ensure a change occurred |
|
| 143 |
+ latestRef := latestEvent.DockerImageReference |
|
| 144 |
+ if len(latestRef) == 0 || latestRef == params.LastTriggeredImage {
|
|
| 145 |
+ continue |
|
| 146 |
+ } |
|
| 147 |
+ |
|
| 148 |
+ // Update containers |
|
| 149 |
+ names := sets.NewString(params.ContainerNames...) |
|
| 150 |
+ for i := range config.Spec.Template.Spec.Containers {
|
|
| 151 |
+ container := &config.Spec.Template.Spec.Containers[i] |
|
| 152 |
+ if !names.Has(container.Name) {
|
|
| 153 |
+ continue |
|
| 154 |
+ } |
|
| 155 |
+ |
|
| 156 |
+ if container.Image != latestRef {
|
|
| 157 |
+ // Update the image |
|
| 158 |
+ container.Image = latestRef |
|
| 159 |
+ // Log the last triggered image ID |
|
| 160 |
+ params.LastTriggeredImage = latestRef |
|
| 161 |
+ } |
|
| 162 |
+ } |
|
| 163 |
+ } |
|
| 164 |
+ |
|
| 165 |
+ if err := utilerrors.NewAggregate(errs); err != nil {
|
|
| 166 |
+ return errors.NewInternalError(err) |
|
| 167 |
+ } |
|
| 168 |
+ |
|
| 169 |
+ return nil |
|
| 170 |
+} |
|
| 171 |
+ |
|
| 172 |
+// canTrigger determines if we can trigger a new deployment for config based on the various deployment triggers. |
|
| 173 |
+func canTrigger( |
|
| 174 |
+ config *deployapi.DeploymentConfig, |
|
| 175 |
+ rn kclient.ReplicationControllersNamespacer, |
|
| 176 |
+ decoder runtime.Decoder, |
|
| 177 |
+ force bool, |
|
| 178 |
+) (bool, []deployapi.DeploymentCause, error) {
|
|
| 179 |
+ |
|
| 180 |
+ decoded, err := decodeFromLatestDeployment(config, rn, decoder) |
|
| 181 |
+ if err != nil {
|
|
| 182 |
+ return false, nil, err |
|
| 183 |
+ } |
|
| 184 |
+ |
|
| 185 |
+ ictCount, resolved, canTriggerByImageChange := 0, 0, false |
|
| 186 |
+ var causes []deployapi.DeploymentCause |
|
| 187 |
+ |
|
| 188 |
+ for _, t := range config.Spec.Triggers {
|
|
| 189 |
+ if t.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 190 |
+ continue |
|
| 191 |
+ } |
|
| 192 |
+ ictCount++ |
|
| 193 |
+ |
|
| 194 |
+ // If the image is yet to be resolved then we cannot process this trigger. |
|
| 195 |
+ lastTriggered := t.ImageChangeParams.LastTriggeredImage |
|
| 196 |
+ if len(lastTriggered) == 0 {
|
|
| 197 |
+ continue |
|
| 198 |
+ } |
|
| 199 |
+ resolved++ |
|
| 200 |
+ |
|
| 201 |
+ // Non-automatic triggers should not be able to trigger deployments. |
|
| 202 |
+ if !t.ImageChangeParams.Automatic {
|
|
| 203 |
+ continue |
|
| 204 |
+ } |
|
| 205 |
+ |
|
| 206 |
+ // We need stronger checks in order to validate that this template |
|
| 207 |
+ // change is an image change. Look at the deserialized config's |
|
| 208 |
+ // triggers and compare with the present trigger. Initial deployments |
|
| 209 |
+ // should always trigger - there is no previous config to use for the |
|
| 210 |
+ // comparison. |
|
| 211 |
+ if config.Status.LatestVersion > 0 && !triggeredByDifferentImage(*t.ImageChangeParams, *decoded) {
|
|
| 212 |
+ continue |
|
| 213 |
+ } |
|
| 214 |
+ |
|
| 215 |
+ canTriggerByImageChange = true |
|
| 216 |
+ causes = append(causes, deployapi.DeploymentCause{
|
|
| 217 |
+ Type: deployapi.DeploymentTriggerOnImageChange, |
|
| 218 |
+ ImageTrigger: &deployapi.DeploymentCauseImageTrigger{
|
|
| 219 |
+ From: kapi.ObjectReference{
|
|
| 220 |
+ Name: t.ImageChangeParams.From.Name, |
|
| 221 |
+ Namespace: t.ImageChangeParams.From.Namespace, |
|
| 222 |
+ Kind: "ImageStreamTag", |
|
| 223 |
+ }, |
|
| 224 |
+ }, |
|
| 225 |
+ }) |
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ if ictCount != resolved {
|
|
| 229 |
+ err = errors.NewBadRequest(fmt.Sprintf("cannot trigger a deployment for %q because it contains unresolved images", config.Name))
|
|
| 230 |
+ return false, nil, err |
|
| 231 |
+ } |
|
| 232 |
+ |
|
| 233 |
+ if force {
|
|
| 234 |
+ return true, []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerManual}}, nil
|
|
| 235 |
+ } |
|
| 236 |
+ |
|
| 237 |
+ canTriggerByConfigChange := false |
|
| 238 |
+ if deployutil.HasChangeTrigger(config) && // Our deployment config has a config change trigger |
|
| 239 |
+ len(causes) == 0 && // and no other trigger has triggered. |
|
| 240 |
+ (config.Status.LatestVersion == 0 || // Either it's the initial deployment |
|
| 241 |
+ !kapi.Semantic.DeepEqual(config.Spec.Template, decoded.Spec.Template)) /* or a config change happened so we need to trigger */ {
|
|
| 242 |
+ |
|
| 243 |
+ canTriggerByConfigChange = true |
|
| 244 |
+ causes = []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerOnConfigChange}}
|
|
| 245 |
+ } |
|
| 246 |
+ |
|
| 247 |
+ return canTriggerByConfigChange || canTriggerByImageChange, causes, nil |
|
| 248 |
+} |
|
| 249 |
+ |
|
| 250 |
+// decodeFromLatestDeployment will try to return the decoded version of the current deploymentconfig |
|
| 251 |
+// found in the annotations of its latest deployment. If there is no previous deploymentconfig (ie. |
|
| 252 |
+// latestVersion == 0), the returned deploymentconfig will be the same. |
|
| 253 |
+func decodeFromLatestDeployment(config *deployapi.DeploymentConfig, rn kclient.ReplicationControllersNamespacer, decoder runtime.Decoder) (*deployapi.DeploymentConfig, error) {
|
|
| 254 |
+ if config.Status.LatestVersion == 0 {
|
|
| 255 |
+ return config, nil |
|
| 256 |
+ } |
|
| 257 |
+ |
|
| 258 |
+ latestDeploymentName := deployutil.LatestDeploymentNameForConfig(config) |
|
| 259 |
+ deployment, err := rn.ReplicationControllers(config.Namespace).Get(latestDeploymentName) |
|
| 260 |
+ if err != nil {
|
|
| 261 |
+ // If there's no deployment for the latest config, we have no basis of |
|
| 262 |
+ // comparison. It's the responsibility of the deployment config controller |
|
| 263 |
+ // to make the deployment for the config, so return early. |
|
| 264 |
+ return nil, err |
|
| 265 |
+ } |
|
| 266 |
+ decoded, err := deployutil.DecodeDeploymentConfig(deployment, decoder) |
|
| 267 |
+ if err != nil {
|
|
| 268 |
+ return nil, errors.NewBadRequest(err.Error()) |
|
| 269 |
+ } |
|
| 270 |
+ return decoded, nil |
|
| 271 |
+} |
|
| 272 |
+ |
|
| 273 |
+// triggeredByDifferentImage compares the provided image change parameters with those found in the |
|
| 274 |
+// previous deployment config (the one we decoded from the annotations of its latest deployment) |
|
| 275 |
+// and returns whether the two deployment configs have been triggered by a different image change. |
|
| 276 |
+func triggeredByDifferentImage(ictParams deployapi.DeploymentTriggerImageChangeParams, previous deployapi.DeploymentConfig) bool {
|
|
| 277 |
+ for _, t := range previous.Spec.Triggers {
|
|
| 278 |
+ if t.Type != deployapi.DeploymentTriggerOnImageChange {
|
|
| 279 |
+ continue |
|
| 280 |
+ } |
|
| 281 |
+ |
|
| 282 |
+ if t.ImageChangeParams.From.Name != ictParams.From.Name || |
|
| 283 |
+ t.ImageChangeParams.From.Namespace != ictParams.From.Namespace {
|
|
| 284 |
+ continue |
|
| 285 |
+ } |
|
| 286 |
+ |
|
| 287 |
+ if t.ImageChangeParams.LastTriggeredImage != ictParams.LastTriggeredImage {
|
|
| 288 |
+ glog.V(4).Infof("Deployment config %q triggered by different image: %s -> %s", previous.Name, t.ImageChangeParams.LastTriggeredImage, ictParams.LastTriggeredImage)
|
|
| 289 |
+ return true |
|
| 290 |
+ } |
|
| 291 |
+ return false |
|
| 292 |
+ } |
|
| 293 |
+ return false |
|
| 294 |
+} |
| 0 | 295 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,692 @@ |
| 0 |
+package instantiate |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "testing" |
|
| 4 |
+ |
|
| 5 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 6 |
+ "k8s.io/kubernetes/pkg/api/errors" |
|
| 7 |
+ ktestclient "k8s.io/kubernetes/pkg/client/unversioned/testclient" |
|
| 8 |
+ "k8s.io/kubernetes/pkg/runtime" |
|
| 9 |
+ |
|
| 10 |
+ "github.com/openshift/origin/pkg/client/testclient" |
|
| 11 |
+ deployapi "github.com/openshift/origin/pkg/deploy/api" |
|
| 12 |
+ _ "github.com/openshift/origin/pkg/deploy/api/install" |
|
| 13 |
+ deploytest "github.com/openshift/origin/pkg/deploy/api/test" |
|
| 14 |
+ deployv1 "github.com/openshift/origin/pkg/deploy/api/v1" |
|
| 15 |
+ deployutil "github.com/openshift/origin/pkg/deploy/util" |
|
| 16 |
+ imageapi "github.com/openshift/origin/pkg/image/api" |
|
| 17 |
+) |
|
| 18 |
+ |
|
| 19 |
+var codec = kapi.Codecs.LegacyCodec(deployv1.SchemeGroupVersion) |
|
| 20 |
+ |
|
| 21 |
+// TestProcess_changeForNonAutomaticTag ensures that an image update for which |
|
| 22 |
+// there is a matching trigger results in a no-op due to the trigger's |
|
| 23 |
+// automatic flag being set to false or updates the config if forced. |
|
| 24 |
+func TestProcess_changeForNonAutomaticTag(t *testing.T) {
|
|
| 25 |
+ tests := []struct {
|
|
| 26 |
+ name string |
|
| 27 |
+ force bool |
|
| 28 |
+ |
|
| 29 |
+ expected bool |
|
| 30 |
+ expectedErr bool |
|
| 31 |
+ }{
|
|
| 32 |
+ {
|
|
| 33 |
+ name: "normal update", |
|
| 34 |
+ force: false, |
|
| 35 |
+ |
|
| 36 |
+ expected: false, |
|
| 37 |
+ expectedErr: false, |
|
| 38 |
+ }, |
|
| 39 |
+ {
|
|
| 40 |
+ name: "forced update", |
|
| 41 |
+ force: true, |
|
| 42 |
+ |
|
| 43 |
+ expected: true, |
|
| 44 |
+ expectedErr: false, |
|
| 45 |
+ }, |
|
| 46 |
+ } |
|
| 47 |
+ |
|
| 48 |
+ for _, test := range tests {
|
|
| 49 |
+ config := deploytest.OkDeploymentConfig(1) |
|
| 50 |
+ config.Namespace = kapi.NamespaceDefault |
|
| 51 |
+ config.Spec.Triggers[0].ImageChangeParams.Automatic = false |
|
| 52 |
+ // The image has been resolved at least once before. |
|
| 53 |
+ config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = deploytest.DockerImageReference |
|
| 54 |
+ |
|
| 55 |
+ stream := deploytest.OkStreamForConfig(config) |
|
| 56 |
+ config.Spec.Triggers[0].ImageChangeParams.LastTriggeredImage = "someotherresolveddockerimagereference" |
|
| 57 |
+ |
|
| 58 |
+ fake := &testclient.Fake{}
|
|
| 59 |
+ fake.AddReactor("get", "imagestreams", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 60 |
+ if !test.expected {
|
|
| 61 |
+ t.Errorf("unexpected imagestream call")
|
|
| 62 |
+ } |
|
| 63 |
+ return true, stream, nil |
|
| 64 |
+ }) |
|
| 65 |
+ |
|
| 66 |
+ image := config.Spec.Template.Spec.Containers[0].Image |
|
| 67 |
+ |
|
| 68 |
+ // Force equals to false; we shouldn't update the config anyway |
|
| 69 |
+ err := processTriggers(config, fake, test.force) |
|
| 70 |
+ if err == nil && test.expectedErr {
|
|
| 71 |
+ t.Errorf("%s: expected an error", test.name)
|
|
| 72 |
+ continue |
|
| 73 |
+ } |
|
| 74 |
+ if err != nil && !test.expectedErr {
|
|
| 75 |
+ t.Errorf("%s: unexpected error: %v", test.name, err)
|
|
| 76 |
+ continue |
|
| 77 |
+ } |
|
| 78 |
+ if test.expected && config.Spec.Template.Spec.Containers[0].Image == image {
|
|
| 79 |
+ t.Errorf("%s: expected an image update but got none", test.name)
|
|
| 80 |
+ } else if !test.expected && config.Spec.Template.Spec.Containers[0].Image != image {
|
|
| 81 |
+ t.Errorf("%s: didn't expect an image update but got %s", test.name, image)
|
|
| 82 |
+ } |
|
| 83 |
+ } |
|
| 84 |
+} |
|
| 85 |
+ |
|
| 86 |
+// TestProcess_changeForUnregisteredTag ensures that an image update for which |
|
| 87 |
+// there is a matching trigger results in a no-op due to the tag specified on |
|
| 88 |
+// the trigger not matching the tags defined on the image stream. |
|
| 89 |
+func TestProcess_changeForUnregisteredTag(t *testing.T) {
|
|
| 90 |
+ config := deploytest.OkDeploymentConfig(0) |
|
| 91 |
+ stream := deploytest.OkStreamForConfig(config) |
|
| 92 |
+ // The image has been resolved at least once before. |
|
| 93 |
+ config.Spec.Triggers[0].ImageChangeParams.From.Name = imageapi.JoinImageStreamTag(stream.Name, "unrelatedtag") |
|
| 94 |
+ |
|
| 95 |
+ fake := &testclient.Fake{}
|
|
| 96 |
+ fake.AddReactor("get", "imagestreams", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 97 |
+ return true, stream, nil |
|
| 98 |
+ }) |
|
| 99 |
+ |
|
| 100 |
+ image := config.Spec.Template.Spec.Containers[0].Image |
|
| 101 |
+ |
|
| 102 |
+ // verify no-op; should be the same for force=true and force=false |
|
| 103 |
+ if err := processTriggers(config, fake, false); err != nil {
|
|
| 104 |
+ t.Fatalf("unexpected error: %v", err)
|
|
| 105 |
+ } |
|
| 106 |
+ if image != config.Spec.Template.Spec.Containers[0].Image {
|
|
| 107 |
+ t.Fatalf("unexpected image update: %#v", config.Spec.Template.Spec.Containers[0].Image)
|
|
| 108 |
+ } |
|
| 109 |
+ |
|
| 110 |
+ if err := processTriggers(config, fake, true); err != nil {
|
|
| 111 |
+ t.Fatalf("unexpected error when forced: %v", err)
|
|
| 112 |
+ } |
|
| 113 |
+ if image != config.Spec.Template.Spec.Containers[0].Image {
|
|
| 114 |
+ t.Fatalf("unexpected image update when forced: %#v", config.Spec.Template.Spec.Containers[0].Image)
|
|
| 115 |
+ } |
|
| 116 |
+} |
|
| 117 |
+ |
|
| 118 |
+// TestProcess_matchScenarios comprehensively tests trigger definitions against |
|
| 119 |
+// image stream updates to ensure that the image change triggers match (or don't |
|
| 120 |
+// match) properly. |
|
| 121 |
+func TestProcess_matchScenarios(t *testing.T) {
|
|
| 122 |
+ tests := []struct {
|
|
| 123 |
+ name string |
|
| 124 |
+ |
|
| 125 |
+ param *deployapi.DeploymentTriggerImageChangeParams |
|
| 126 |
+ notFound bool |
|
| 127 |
+ |
|
| 128 |
+ expected bool |
|
| 129 |
+ }{
|
|
| 130 |
+ {
|
|
| 131 |
+ name: "automatic=true, initial trigger, explicit namespace", |
|
| 132 |
+ |
|
| 133 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 134 |
+ Automatic: true, |
|
| 135 |
+ ContainerNames: []string{"container1"},
|
|
| 136 |
+ From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 137 |
+ LastTriggeredImage: "", |
|
| 138 |
+ }, |
|
| 139 |
+ |
|
| 140 |
+ expected: true, |
|
| 141 |
+ }, |
|
| 142 |
+ {
|
|
| 143 |
+ name: "automatic=true, initial trigger, implicit namespace", |
|
| 144 |
+ |
|
| 145 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 146 |
+ Automatic: true, |
|
| 147 |
+ ContainerNames: []string{"container1"},
|
|
| 148 |
+ From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 149 |
+ LastTriggeredImage: "", |
|
| 150 |
+ }, |
|
| 151 |
+ |
|
| 152 |
+ expected: true, |
|
| 153 |
+ }, |
|
| 154 |
+ {
|
|
| 155 |
+ name: "automatic=false, initial trigger", |
|
| 156 |
+ |
|
| 157 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 158 |
+ Automatic: false, |
|
| 159 |
+ ContainerNames: []string{"container1"},
|
|
| 160 |
+ From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 161 |
+ LastTriggeredImage: "", |
|
| 162 |
+ }, |
|
| 163 |
+ |
|
| 164 |
+ expected: false, |
|
| 165 |
+ }, |
|
| 166 |
+ {
|
|
| 167 |
+ name: "(no-op) automatic=false, already triggered", |
|
| 168 |
+ |
|
| 169 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 170 |
+ Automatic: false, |
|
| 171 |
+ ContainerNames: []string{"container1"},
|
|
| 172 |
+ From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 173 |
+ LastTriggeredImage: deploytest.DockerImageReference, |
|
| 174 |
+ }, |
|
| 175 |
+ |
|
| 176 |
+ expected: false, |
|
| 177 |
+ }, |
|
| 178 |
+ {
|
|
| 179 |
+ name: "(no-op) automatic=true, image is already deployed", |
|
| 180 |
+ |
|
| 181 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 182 |
+ Automatic: true, |
|
| 183 |
+ ContainerNames: []string{"container1"},
|
|
| 184 |
+ From: kapi.ObjectReference{Name: imageapi.JoinImageStreamTag(deploytest.ImageStreamName, imageapi.DefaultImageTag)},
|
|
| 185 |
+ LastTriggeredImage: deploytest.DockerImageReference, |
|
| 186 |
+ }, |
|
| 187 |
+ |
|
| 188 |
+ expected: false, |
|
| 189 |
+ }, |
|
| 190 |
+ {
|
|
| 191 |
+ name: "(no-op) trigger doesn't match the stream", |
|
| 192 |
+ |
|
| 193 |
+ param: &deployapi.DeploymentTriggerImageChangeParams{
|
|
| 194 |
+ Automatic: true, |
|
| 195 |
+ ContainerNames: []string{"container1"},
|
|
| 196 |
+ From: kapi.ObjectReference{Namespace: kapi.NamespaceDefault, Name: imageapi.JoinImageStreamTag("other-stream", imageapi.DefaultImageTag)},
|
|
| 197 |
+ LastTriggeredImage: "", |
|
| 198 |
+ }, |
|
| 199 |
+ notFound: true, |
|
| 200 |
+ |
|
| 201 |
+ expected: false, |
|
| 202 |
+ }, |
|
| 203 |
+ } |
|
| 204 |
+ |
|
| 205 |
+ for i := range tests {
|
|
| 206 |
+ test := tests[i] |
|
| 207 |
+ t.Logf("running test %q", test.name)
|
|
| 208 |
+ |
|
| 209 |
+ fake := &testclient.Fake{}
|
|
| 210 |
+ fake.AddReactor("get", "imagestreams", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 211 |
+ if test.notFound {
|
|
| 212 |
+ name := action.(ktestclient.GetAction).GetName() |
|
| 213 |
+ return true, nil, errors.NewNotFound(imageapi.Resource("ImageStream"), name)
|
|
| 214 |
+ } |
|
| 215 |
+ stream := fakeStream(deploytest.ImageStreamName, imageapi.DefaultImageTag, deploytest.DockerImageReference, deploytest.ImageID) |
|
| 216 |
+ return true, stream, nil |
|
| 217 |
+ }) |
|
| 218 |
+ |
|
| 219 |
+ config := deploytest.OkDeploymentConfig(1) |
|
| 220 |
+ config.Namespace = kapi.NamespaceDefault |
|
| 221 |
+ config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{
|
|
| 222 |
+ {
|
|
| 223 |
+ Type: deployapi.DeploymentTriggerOnImageChange, |
|
| 224 |
+ ImageChangeParams: test.param, |
|
| 225 |
+ }, |
|
| 226 |
+ } |
|
| 227 |
+ |
|
| 228 |
+ image := config.Spec.Template.Spec.Containers[0].Image |
|
| 229 |
+ |
|
| 230 |
+ err := processTriggers(config, fake, false) |
|
| 231 |
+ if err != nil {
|
|
| 232 |
+ t.Errorf("unexpected error: %v", err)
|
|
| 233 |
+ continue |
|
| 234 |
+ } |
|
| 235 |
+ if test.expected && config.Spec.Template.Spec.Containers[0].Image == image {
|
|
| 236 |
+ t.Errorf("%s: expected an image update but got none", test.name)
|
|
| 237 |
+ } else if !test.expected && config.Spec.Template.Spec.Containers[0].Image != image {
|
|
| 238 |
+ t.Errorf("%s: didn't expect an image update but got %s", test.name, image)
|
|
| 239 |
+ } |
|
| 240 |
+ } |
|
| 241 |
+} |
|
| 242 |
+ |
|
| 243 |
+func fakeStream(name, tag, dir, image string) *imageapi.ImageStream {
|
|
| 244 |
+ return &imageapi.ImageStream{
|
|
| 245 |
+ ObjectMeta: kapi.ObjectMeta{Name: name, Namespace: kapi.NamespaceDefault},
|
|
| 246 |
+ Status: imageapi.ImageStreamStatus{
|
|
| 247 |
+ Tags: map[string]imageapi.TagEventList{
|
|
| 248 |
+ tag: {
|
|
| 249 |
+ Items: []imageapi.TagEvent{
|
|
| 250 |
+ {
|
|
| 251 |
+ DockerImageReference: dir, |
|
| 252 |
+ Image: image, |
|
| 253 |
+ }, |
|
| 254 |
+ }, |
|
| 255 |
+ }, |
|
| 256 |
+ }, |
|
| 257 |
+ }, |
|
| 258 |
+ } |
|
| 259 |
+} |
|
| 260 |
+ |
|
| 261 |
+func TestCanTrigger(t *testing.T) {
|
|
| 262 |
+ tests := []struct {
|
|
| 263 |
+ name string |
|
| 264 |
+ |
|
| 265 |
+ config *deployapi.DeploymentConfig |
|
| 266 |
+ decoded *deployapi.DeploymentConfig |
|
| 267 |
+ force bool |
|
| 268 |
+ |
|
| 269 |
+ expected bool |
|
| 270 |
+ expectedCauses []deployapi.DeploymentCause |
|
| 271 |
+ expectedErr bool |
|
| 272 |
+ }{
|
|
| 273 |
+ {
|
|
| 274 |
+ name: "no trigger [w/ podtemplate change]", |
|
| 275 |
+ |
|
| 276 |
+ config: &deployapi.DeploymentConfig{
|
|
| 277 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 278 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 279 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{},
|
|
| 280 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 281 |
+ }, |
|
| 282 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 283 |
+ }, |
|
| 284 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 285 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 286 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 287 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{},
|
|
| 288 |
+ Template: deploytest.OkPodTemplate(), |
|
| 289 |
+ }, |
|
| 290 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 291 |
+ }, |
|
| 292 |
+ force: false, |
|
| 293 |
+ |
|
| 294 |
+ expected: false, |
|
| 295 |
+ expectedCauses: nil, |
|
| 296 |
+ }, |
|
| 297 |
+ {
|
|
| 298 |
+ name: "forced updated", |
|
| 299 |
+ |
|
| 300 |
+ config: &deployapi.DeploymentConfig{
|
|
| 301 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 302 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 303 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 304 |
+ }, |
|
| 305 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 306 |
+ }, |
|
| 307 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 308 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 309 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 310 |
+ Template: deploytest.OkPodTemplate(), |
|
| 311 |
+ }, |
|
| 312 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 313 |
+ }, |
|
| 314 |
+ force: true, |
|
| 315 |
+ |
|
| 316 |
+ expected: true, |
|
| 317 |
+ expectedCauses: []deployapi.DeploymentCause{{Type: deployapi.DeploymentTriggerManual}},
|
|
| 318 |
+ }, |
|
| 319 |
+ {
|
|
| 320 |
+ name: "config change trigger only [w/ podtemplate change]", |
|
| 321 |
+ |
|
| 322 |
+ config: &deployapi.DeploymentConfig{
|
|
| 323 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 324 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 325 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 326 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 327 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 328 |
+ }, |
|
| 329 |
+ }, |
|
| 330 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 331 |
+ }, |
|
| 332 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 333 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 334 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 335 |
+ Template: deploytest.OkPodTemplate(), |
|
| 336 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 337 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 338 |
+ }, |
|
| 339 |
+ }, |
|
| 340 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 341 |
+ }, |
|
| 342 |
+ force: false, |
|
| 343 |
+ |
|
| 344 |
+ expected: true, |
|
| 345 |
+ expectedCauses: deploytest.OkConfigChangeDetails().Causes, |
|
| 346 |
+ }, |
|
| 347 |
+ {
|
|
| 348 |
+ name: "config change trigger only [no change][initial]", |
|
| 349 |
+ |
|
| 350 |
+ config: &deployapi.DeploymentConfig{
|
|
| 351 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 352 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 353 |
+ Template: deploytest.OkPodTemplate(), |
|
| 354 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 355 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 356 |
+ }, |
|
| 357 |
+ }, |
|
| 358 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 359 |
+ }, |
|
| 360 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 361 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 362 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 363 |
+ Template: deploytest.OkPodTemplate(), |
|
| 364 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 365 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 366 |
+ }, |
|
| 367 |
+ }, |
|
| 368 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 369 |
+ }, |
|
| 370 |
+ force: false, |
|
| 371 |
+ |
|
| 372 |
+ expected: true, |
|
| 373 |
+ expectedCauses: deploytest.OkConfigChangeDetails().Causes, |
|
| 374 |
+ }, |
|
| 375 |
+ {
|
|
| 376 |
+ name: "config change trigger only [no change]", |
|
| 377 |
+ |
|
| 378 |
+ config: &deployapi.DeploymentConfig{
|
|
| 379 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 380 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 381 |
+ Template: deploytest.OkPodTemplate(), |
|
| 382 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 383 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 384 |
+ }, |
|
| 385 |
+ }, |
|
| 386 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 387 |
+ }, |
|
| 388 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 389 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 390 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 391 |
+ Template: deploytest.OkPodTemplate(), |
|
| 392 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 393 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 394 |
+ }, |
|
| 395 |
+ }, |
|
| 396 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 397 |
+ }, |
|
| 398 |
+ force: false, |
|
| 399 |
+ |
|
| 400 |
+ expected: false, |
|
| 401 |
+ expectedCauses: nil, |
|
| 402 |
+ }, |
|
| 403 |
+ {
|
|
| 404 |
+ name: "image change trigger only [automatic=false][w/ podtemplate change]", |
|
| 405 |
+ |
|
| 406 |
+ config: &deployapi.DeploymentConfig{
|
|
| 407 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 408 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 409 |
+ Template: deploytest.OkPodTemplateChanged(), // Irrelevant change |
|
| 410 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 411 |
+ deploytest.OkNonAutomaticICT(), // Image still to be resolved but it's false anyway |
|
| 412 |
+ }, |
|
| 413 |
+ }, |
|
| 414 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 415 |
+ }, |
|
| 416 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 417 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 418 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 419 |
+ Template: deploytest.OkPodTemplate(), |
|
| 420 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 421 |
+ deploytest.OkNonAutomaticICT(), |
|
| 422 |
+ }, |
|
| 423 |
+ }, |
|
| 424 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 425 |
+ }, |
|
| 426 |
+ force: false, |
|
| 427 |
+ |
|
| 428 |
+ expected: false, |
|
| 429 |
+ expectedCauses: nil, |
|
| 430 |
+ expectedErr: true, |
|
| 431 |
+ }, |
|
| 432 |
+ {
|
|
| 433 |
+ name: "image change trigger only [automatic=false][w/ image change]", |
|
| 434 |
+ |
|
| 435 |
+ config: &deployapi.DeploymentConfig{
|
|
| 436 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 437 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 438 |
+ Template: deploytest.OkPodTemplateChanged(), // Image has been updated in the template but automatic=false |
|
| 439 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 440 |
+ deploytest.OkTriggeredNonAutomatic(), |
|
| 441 |
+ }, |
|
| 442 |
+ }, |
|
| 443 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 444 |
+ }, |
|
| 445 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 446 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 447 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 448 |
+ Template: deploytest.OkPodTemplate(), |
|
| 449 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 450 |
+ deploytest.OkNonAutomaticICT(), |
|
| 451 |
+ }, |
|
| 452 |
+ }, |
|
| 453 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 454 |
+ }, |
|
| 455 |
+ force: false, |
|
| 456 |
+ |
|
| 457 |
+ expected: false, |
|
| 458 |
+ expectedCauses: nil, |
|
| 459 |
+ }, |
|
| 460 |
+ {
|
|
| 461 |
+ name: "image change trigger only [automatic=true][w/ image change]", |
|
| 462 |
+ |
|
| 463 |
+ config: &deployapi.DeploymentConfig{
|
|
| 464 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 465 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 466 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 467 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 468 |
+ deploytest.OkTriggeredImageChange(), |
|
| 469 |
+ }, |
|
| 470 |
+ }, |
|
| 471 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 472 |
+ }, |
|
| 473 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 474 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 475 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 476 |
+ Template: deploytest.OkPodTemplate(), |
|
| 477 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 478 |
+ deploytest.OkImageChangeTrigger(), |
|
| 479 |
+ }, |
|
| 480 |
+ }, |
|
| 481 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 482 |
+ }, |
|
| 483 |
+ force: false, |
|
| 484 |
+ |
|
| 485 |
+ expected: true, |
|
| 486 |
+ expectedCauses: deploytest.OkImageChangeDetails().Causes, |
|
| 487 |
+ }, |
|
| 488 |
+ {
|
|
| 489 |
+ name: "image change trigger only [automatic=true][no change]", |
|
| 490 |
+ |
|
| 491 |
+ config: &deployapi.DeploymentConfig{
|
|
| 492 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 493 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 494 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 495 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 496 |
+ deploytest.OkTriggeredImageChange(), |
|
| 497 |
+ }, |
|
| 498 |
+ }, |
|
| 499 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 500 |
+ }, |
|
| 501 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 502 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 503 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 504 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 505 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 506 |
+ deploytest.OkTriggeredImageChange(), |
|
| 507 |
+ }, |
|
| 508 |
+ }, |
|
| 509 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 510 |
+ }, |
|
| 511 |
+ force: false, |
|
| 512 |
+ |
|
| 513 |
+ expected: false, |
|
| 514 |
+ expectedCauses: nil, |
|
| 515 |
+ }, |
|
| 516 |
+ {
|
|
| 517 |
+ name: "config change and image change trigger [automatic=false][initial][w/ image change]", |
|
| 518 |
+ |
|
| 519 |
+ config: &deployapi.DeploymentConfig{
|
|
| 520 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 521 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 522 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 523 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 524 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 525 |
+ deploytest.OkTriggeredNonAutomatic(), |
|
| 526 |
+ }, |
|
| 527 |
+ }, |
|
| 528 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 529 |
+ }, |
|
| 530 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 531 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 532 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 533 |
+ Template: deploytest.OkPodTemplate(), |
|
| 534 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 535 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 536 |
+ deploytest.OkNonAutomaticICT(), |
|
| 537 |
+ }, |
|
| 538 |
+ }, |
|
| 539 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 540 |
+ }, |
|
| 541 |
+ force: false, |
|
| 542 |
+ |
|
| 543 |
+ expected: true, |
|
| 544 |
+ expectedCauses: deploytest.OkConfigChangeDetails().Causes, |
|
| 545 |
+ }, |
|
| 546 |
+ {
|
|
| 547 |
+ name: "config change and image change trigger [automatic=false][initial][no change]", |
|
| 548 |
+ |
|
| 549 |
+ config: &deployapi.DeploymentConfig{
|
|
| 550 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 551 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 552 |
+ Template: deploytest.OkPodTemplate(), |
|
| 553 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 554 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 555 |
+ deploytest.OkNonAutomaticICT(), // Image is not resolved yet |
|
| 556 |
+ }, |
|
| 557 |
+ }, |
|
| 558 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 559 |
+ }, |
|
| 560 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 561 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 562 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 563 |
+ Template: deploytest.OkPodTemplate(), |
|
| 564 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 565 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 566 |
+ deploytest.OkNonAutomaticICT(), |
|
| 567 |
+ }, |
|
| 568 |
+ }, |
|
| 569 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 570 |
+ }, |
|
| 571 |
+ force: false, |
|
| 572 |
+ |
|
| 573 |
+ expected: false, |
|
| 574 |
+ expectedCauses: nil, |
|
| 575 |
+ expectedErr: true, |
|
| 576 |
+ }, |
|
| 577 |
+ {
|
|
| 578 |
+ name: "config change and image change trigger [automatic=true][initial][w/ podtemplate change]", |
|
| 579 |
+ |
|
| 580 |
+ config: &deployapi.DeploymentConfig{
|
|
| 581 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 582 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 583 |
+ Template: deploytest.OkPodTemplateChanged(), // Pod template has changed but the image in the template is yet to be updated |
|
| 584 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 585 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 586 |
+ deploytest.OkImageChangeTrigger(), |
|
| 587 |
+ }, |
|
| 588 |
+ }, |
|
| 589 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 590 |
+ }, |
|
| 591 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 592 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 593 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 594 |
+ Template: deploytest.OkPodTemplate(), |
|
| 595 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 596 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 597 |
+ deploytest.OkImageChangeTrigger(), |
|
| 598 |
+ }, |
|
| 599 |
+ }, |
|
| 600 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 601 |
+ }, |
|
| 602 |
+ force: false, |
|
| 603 |
+ |
|
| 604 |
+ expected: false, |
|
| 605 |
+ expectedCauses: nil, |
|
| 606 |
+ expectedErr: true, |
|
| 607 |
+ }, |
|
| 608 |
+ {
|
|
| 609 |
+ name: "config change and image change trigger [automatic=true][initial][w/ image change]", |
|
| 610 |
+ |
|
| 611 |
+ config: &deployapi.DeploymentConfig{
|
|
| 612 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 613 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 614 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 615 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 616 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 617 |
+ deploytest.OkTriggeredImageChange(), |
|
| 618 |
+ }, |
|
| 619 |
+ }, |
|
| 620 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 621 |
+ }, |
|
| 622 |
+ decoded: &deployapi.DeploymentConfig{
|
|
| 623 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 624 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 625 |
+ Template: deploytest.OkPodTemplate(), |
|
| 626 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 627 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 628 |
+ deploytest.OkImageChangeTrigger(), |
|
| 629 |
+ }, |
|
| 630 |
+ }, |
|
| 631 |
+ Status: deploytest.OkDeploymentConfigStatus(0), |
|
| 632 |
+ }, |
|
| 633 |
+ force: false, |
|
| 634 |
+ |
|
| 635 |
+ expected: true, |
|
| 636 |
+ expectedCauses: deploytest.OkImageChangeDetails().Causes, |
|
| 637 |
+ }, |
|
| 638 |
+ {
|
|
| 639 |
+ name: "config change and image change trigger [automatic=true][no change]", |
|
| 640 |
+ |
|
| 641 |
+ config: &deployapi.DeploymentConfig{
|
|
| 642 |
+ ObjectMeta: kapi.ObjectMeta{Name: "config"},
|
|
| 643 |
+ Spec: deployapi.DeploymentConfigSpec{
|
|
| 644 |
+ Template: deploytest.OkPodTemplateChanged(), |
|
| 645 |
+ Triggers: []deployapi.DeploymentTriggerPolicy{
|
|
| 646 |
+ deploytest.OkConfigChangeTrigger(), |
|
| 647 |
+ deploytest.OkTriggeredImageChange(), |
|
| 648 |
+ }, |
|
| 649 |
+ }, |
|
| 650 |
+ Status: deploytest.OkDeploymentConfigStatus(1), |
|
| 651 |
+ }, |
|
| 652 |
+ force: false, |
|
| 653 |
+ |
|
| 654 |
+ expected: false, |
|
| 655 |
+ expectedCauses: nil, |
|
| 656 |
+ }, |
|
| 657 |
+ } |
|
| 658 |
+ |
|
| 659 |
+ for _, test := range tests {
|
|
| 660 |
+ t.Logf("running scenario %q", test.name)
|
|
| 661 |
+ |
|
| 662 |
+ fake := &ktestclient.Fake{}
|
|
| 663 |
+ fake.AddReactor("get", "replicationcontrollers", func(action ktestclient.Action) (handled bool, ret runtime.Object, err error) {
|
|
| 664 |
+ config := test.decoded |
|
| 665 |
+ if config == nil {
|
|
| 666 |
+ config = test.config |
|
| 667 |
+ } |
|
| 668 |
+ config = deploytest.RoundTripConfig(t, config) |
|
| 669 |
+ deployment, _ := deployutil.MakeDeployment(config, codec) |
|
| 670 |
+ return true, deployment, nil |
|
| 671 |
+ }) |
|
| 672 |
+ |
|
| 673 |
+ test.config = deploytest.RoundTripConfig(t, test.config) |
|
| 674 |
+ |
|
| 675 |
+ got, gotCauses, err := canTrigger(test.config, fake, codec, test.force) |
|
| 676 |
+ if err != nil && !test.expectedErr {
|
|
| 677 |
+ t.Errorf("unexpected error: %v", err)
|
|
| 678 |
+ continue |
|
| 679 |
+ } |
|
| 680 |
+ if err == nil && test.expectedErr {
|
|
| 681 |
+ t.Errorf("expected an error")
|
|
| 682 |
+ continue |
|
| 683 |
+ } |
|
| 684 |
+ if test.expected != got {
|
|
| 685 |
+ t.Errorf("expected to trigger: %t, got: %t", test.expected, got)
|
|
| 686 |
+ } |
|
| 687 |
+ if !kapi.Semantic.DeepEqual(test.expectedCauses, gotCauses) {
|
|
| 688 |
+ t.Errorf("expected causes:\n%#v\ngot:\n%#v", test.expectedCauses, gotCauses)
|
|
| 689 |
+ } |
|
| 690 |
+ } |
|
| 691 |
+} |
| 0 | 692 |
new file mode 100644 |
| ... | ... |
@@ -0,0 +1,73 @@ |
| 0 |
+package instantiate |
|
| 1 |
+ |
|
| 2 |
+import ( |
|
| 3 |
+ "reflect" |
|
| 4 |
+ |
|
| 5 |
+ kapi "k8s.io/kubernetes/pkg/api" |
|
| 6 |
+ "k8s.io/kubernetes/pkg/runtime" |
|
| 7 |
+ "k8s.io/kubernetes/pkg/util/validation/field" |
|
| 8 |
+ |
|
| 9 |
+ "github.com/openshift/origin/pkg/deploy/api" |
|
| 10 |
+ "github.com/openshift/origin/pkg/deploy/api/validation" |
|
| 11 |
+) |
|
| 12 |
+ |
|
| 13 |
+type strategy struct {
|
|
| 14 |
+ runtime.ObjectTyper |
|
| 15 |
+} |
|
| 16 |
+ |
|
| 17 |
+var Strategy = strategy{kapi.Scheme}
|
|
| 18 |
+ |
|
| 19 |
+func (strategy) NamespaceScoped() bool {
|
|
| 20 |
+ return true |
|
| 21 |
+} |
|
| 22 |
+ |
|
| 23 |
+func (strategy) AllowCreateOnUpdate() bool {
|
|
| 24 |
+ return false |
|
| 25 |
+} |
|
| 26 |
+ |
|
| 27 |
+func (strategy) AllowUnconditionalUpdate() bool {
|
|
| 28 |
+ return false |
|
| 29 |
+} |
|
| 30 |
+ |
|
| 31 |
+func (strategy) GenerateName(base string) string {
|
|
| 32 |
+ return base |
|
| 33 |
+} |
|
| 34 |
+ |
|
| 35 |
+// PrepareForCreate is a no-op for the instantiate endpoint. |
|
| 36 |
+func (strategy) PrepareForCreate(ctx kapi.Context, obj runtime.Object) {
|
|
| 37 |
+} |
|
| 38 |
+ |
|
| 39 |
+// PrepareForUpdate clears fields that are not allowed to be set by the instantiate endpoint. |
|
| 40 |
+func (strategy) PrepareForUpdate(ctx kapi.Context, obj, old runtime.Object) {
|
|
| 41 |
+ newDc := obj.(*api.DeploymentConfig) |
|
| 42 |
+ oldDc := old.(*api.DeploymentConfig) |
|
| 43 |
+ |
|
| 44 |
+ // Allow the status fields that need to be updated in every instantiation. |
|
| 45 |
+ oldStatus := oldDc.Status |
|
| 46 |
+ oldStatus.LatestVersion = newDc.Status.LatestVersion |
|
| 47 |
+ oldStatus.Details = newDc.Status.Details |
|
| 48 |
+ newDc.Status = oldStatus |
|
| 49 |
+ |
|
| 50 |
+ if !reflect.DeepEqual(oldDc.Spec, newDc.Spec) || newDc.Status.LatestVersion != oldDc.Status.LatestVersion {
|
|
| 51 |
+ newDc.Generation = oldDc.Generation + 1 |
|
| 52 |
+ } |
|
| 53 |
+} |
|
| 54 |
+ |
|
| 55 |
+// Canonicalize normalizes the object after validation. |
|
| 56 |
+func (strategy) Canonicalize(obj runtime.Object) {
|
|
| 57 |
+} |
|
| 58 |
+ |
|
| 59 |
+// CheckGracefulDelete allows a deployment config to be gracefully deleted. |
|
| 60 |
+func (strategy) CheckGracefulDelete(obj runtime.Object, options *kapi.DeleteOptions) bool {
|
|
| 61 |
+ return false |
|
| 62 |
+} |
|
| 63 |
+ |
|
| 64 |
+// Validate is a no-op for the instantiate endpoint. |
|
| 65 |
+func (strategy) Validate(ctx kapi.Context, obj runtime.Object) field.ErrorList {
|
|
| 66 |
+ return validation.ValidateDeploymentConfig(obj.(*api.DeploymentConfig)) |
|
| 67 |
+} |
|
| 68 |
+ |
|
| 69 |
+// ValidateUpdate is the default update validation for the instantiate endpoint. |
|
| 70 |
+func (strategy) ValidateUpdate(ctx kapi.Context, obj, old runtime.Object) field.ErrorList {
|
|
| 71 |
+ return validation.ValidateDeploymentConfigUpdate(obj.(*api.DeploymentConfig), old.(*api.DeploymentConfig)) |
|
| 72 |
+} |
| ... | ... |
@@ -417,8 +417,8 @@ var _ = g.Describe("deploymentconfigs", func() {
|
| 417 | 417 |
g.By(fmt.Sprintf("checking the history for substrings\n%s", out))
|
| 418 | 418 |
o.Expect(out).To(o.ContainSubstring("deploymentconfigs \"deployment-simple\""))
|
| 419 | 419 |
o.Expect(out).To(o.ContainSubstring("REVISION STATUS CAUSE"))
|
| 420 |
- o.Expect(out).To(o.ContainSubstring("1 Complete caused by a config change"))
|
|
| 421 |
- o.Expect(out).To(o.ContainSubstring("2 Complete caused by a config change"))
|
|
| 420 |
+ o.Expect(out).To(o.ContainSubstring("1 Complete config change"))
|
|
| 421 |
+ o.Expect(out).To(o.ContainSubstring("2 Complete config change"))
|
|
| 422 | 422 |
}) |
| 423 | 423 |
}) |
| 424 | 424 |
|
| ... | ... |
@@ -448,10 +448,10 @@ var _ = g.Describe("deploymentconfigs", func() {
|
| 448 | 448 |
generation = strings.Trim(generation, "\"") |
| 449 | 449 |
g.By(fmt.Sprintf("checking the generation for %s: %s", resource, generation))
|
| 450 | 450 |
|
| 451 |
- return strings.Contains(generation, "1") && strings.Contains(version, "1"), nil |
|
| 451 |
+ return strings.Contains(generation, "2") && strings.Contains(version, "1"), nil |
|
| 452 | 452 |
}) |
| 453 | 453 |
if err == wait.ErrWaitTimeout {
|
| 454 |
- err = fmt.Errorf("expected generation: 1, got: %s, expected latestVersion: 1, got: %s", generation, version)
|
|
| 454 |
+ err = fmt.Errorf("expected generation: 2, got: %s, expected latestVersion: 1, got: %s", generation, version)
|
|
| 455 | 455 |
} |
| 456 | 456 |
o.Expect(err).NotTo(o.HaveOccurred()) |
| 457 | 457 |
|
| ... | ... |
@@ -470,10 +470,10 @@ var _ = g.Describe("deploymentconfigs", func() {
|
| 470 | 470 |
generation = strings.Trim(generation, "\"") |
| 471 | 471 |
g.By(fmt.Sprintf("checking the generation for %s: %s", resource, generation))
|
| 472 | 472 |
|
| 473 |
- return strings.Contains(generation, "2"), nil |
|
| 473 |
+ return strings.Contains(generation, "3"), nil |
|
| 474 | 474 |
}) |
| 475 | 475 |
if err == wait.ErrWaitTimeout {
|
| 476 |
- err = fmt.Errorf("expected generation: 2, got: %s", generation)
|
|
| 476 |
+ err = fmt.Errorf("expected generation: 3, got: %s", generation)
|
|
| 477 | 477 |
} |
| 478 | 478 |
o.Expect(err).NotTo(o.HaveOccurred()) |
| 479 | 479 |
|
| ... | ... |
@@ -497,10 +497,10 @@ var _ = g.Describe("deploymentconfigs", func() {
|
| 497 | 497 |
generation = strings.Trim(generation, "\"") |
| 498 | 498 |
g.By(fmt.Sprintf("checking the generation for %s: %s", resource, generation))
|
| 499 | 499 |
|
| 500 |
- return strings.Contains(generation, "3") && strings.Contains(version, "2"), nil |
|
| 500 |
+ return strings.Contains(generation, "4") && strings.Contains(version, "2"), nil |
|
| 501 | 501 |
}) |
| 502 | 502 |
if err == wait.ErrWaitTimeout {
|
| 503 |
- err = fmt.Errorf("expected generation: 3, got: %s, expected latestVersion: 2, got: %s", generation, version)
|
|
| 503 |
+ err = fmt.Errorf("expected generation: 4, got: %s, expected latestVersion: 2, got: %s", generation, version)
|
|
| 504 | 504 |
} |
| 505 | 505 |
o.Expect(err).NotTo(o.HaveOccurred()) |
| 506 | 506 |
|
| ... | ... |
@@ -156,7 +156,8 @@ func TestClusterReaderCoverage(t *testing.T) {
|
| 156 | 156 |
// remove resources without read APIs |
| 157 | 157 |
nonreadingResources := []unversioned.GroupResource{
|
| 158 | 158 |
buildapi.Resource("buildconfigs/instantiatebinary"), buildapi.Resource("buildconfigs/instantiate"), buildapi.Resource("builds/clone"),
|
| 159 |
- deployapi.Resource("deploymentconfigrollbacks"), deployapi.Resource("generatedeploymentconfigs"), deployapi.Resource("deploymentconfigs/rollback"),
|
|
| 159 |
+ deployapi.Resource("deploymentconfigrollbacks"), deployapi.Resource("generatedeploymentconfigs"),
|
|
| 160 |
+ deployapi.Resource("deploymentconfigs/rollback"), deployapi.Resource("deploymentconfigs/instantiate"),
|
|
| 160 | 161 |
imageapi.Resource("imagestreamimports"), imageapi.Resource("imagestreammappings"),
|
| 161 | 162 |
extensionsapi.Resource("deployments/rollback"),
|
| 162 | 163 |
kapi.Resource("pods/attach"), kapi.Resource("namespaces/finalize"),
|
| ... | ... |
@@ -48,11 +48,7 @@ func TestTriggers_manual(t *testing.T) {
|
| 48 | 48 |
|
| 49 | 49 |
config := deploytest.OkDeploymentConfig(0) |
| 50 | 50 |
config.Namespace = namespace |
| 51 |
- config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{
|
|
| 52 |
- {
|
|
| 53 |
- Type: deployapi.DeploymentTriggerManual, |
|
| 54 |
- }, |
|
| 55 |
- } |
|
| 51 |
+ config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{{Type: deployapi.DeploymentTriggerManual}}
|
|
| 56 | 52 |
|
| 57 | 53 |
dc, err := osClient.DeploymentConfigs(namespace).Create(config) |
| 58 | 54 |
if err != nil {
|
| ... | ... |
@@ -65,25 +61,27 @@ func TestTriggers_manual(t *testing.T) {
|
| 65 | 65 |
} |
| 66 | 66 |
defer rcWatch.Stop() |
| 67 | 67 |
|
| 68 |
- retryErr := kclient.RetryOnConflict(wait.Backoff{Steps: maxUpdateRetries}, func() error {
|
|
| 69 |
- config, err := osClient.DeploymentConfigs(namespace).Generate(config.Name) |
|
| 70 |
- if err != nil {
|
|
| 71 |
- return err |
|
| 72 |
- } |
|
| 73 |
- if config.Status.LatestVersion != 1 {
|
|
| 74 |
- t.Fatalf("Generated deployment should have version 1: %#v", config)
|
|
| 75 |
- } |
|
| 76 |
- t.Logf("config(1): %#v", config)
|
|
| 77 |
- updatedConfig, err := osClient.DeploymentConfigs(namespace).Update(config) |
|
| 78 |
- if err != nil {
|
|
| 79 |
- return err |
|
| 80 |
- } |
|
| 81 |
- t.Logf("config(2): %#v", updatedConfig)
|
|
| 82 |
- return nil |
|
| 83 |
- }) |
|
| 84 |
- if retryErr != nil {
|
|
| 85 |
- t.Fatal(err) |
|
| 68 |
+ request := &deployapi.DeploymentRequest{
|
|
| 69 |
+ Name: config.Name, |
|
| 70 |
+ Latest: false, |
|
| 71 |
+ Force: true, |
|
| 72 |
+ } |
|
| 73 |
+ config, err = osClient.DeploymentConfigs(namespace).Instantiate(request) |
|
| 74 |
+ if err != nil {
|
|
| 75 |
+ t.Fatalf("Couldn't instantiate deployment config %q: %v", config.Name, err)
|
|
| 76 |
+ } |
|
| 77 |
+ if config.Status.LatestVersion != 1 {
|
|
| 78 |
+ t.Fatal("Instantiated deployment config should have version 1")
|
|
| 79 |
+ } |
|
| 80 |
+ if config.Status.Details == nil || len(config.Status.Details.Causes) == 0 {
|
|
| 81 |
+ t.Fatal("Instantiated deployment config should have a cause of deployment")
|
|
| 86 | 82 |
} |
| 83 |
+ gotType := config.Status.Details.Causes[0].Type |
|
| 84 |
+ if gotType != deployapi.DeploymentTriggerManual {
|
|
| 85 |
+ t.Fatalf("Instantiated deployment config should have a %q cause of deployment instead of %q",
|
|
| 86 |
+ deployapi.DeploymentTriggerManual, gotType) |
|
| 87 |
+ } |
|
| 88 |
+ |
|
| 87 | 89 |
event := <-rcWatch.ResultChan() |
| 88 | 90 |
if e, a := watchapi.Added, event.Type; e != a {
|
| 89 | 91 |
t.Fatalf("expected watch event type %s, got %s", e, a)
|
| ... | ... |
@@ -205,7 +203,7 @@ waitForNewConfig: |
| 205 | 205 |
} |
| 206 | 206 |
|
| 207 | 207 |
// TestTriggers_imageChange_nonAutomatic ensures that a deployment config with a non-automatic |
| 208 |
-// trigger will have its image updated without starting a new deployment. |
|
| 208 |
+// trigger will have its image updated when a deployment is started manually. |
|
| 209 | 209 |
func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
|
| 210 | 210 |
testutil.RequireEtcd(t) |
| 211 | 211 |
defer testutil.DumpEtcdOnFailure(t) |
| ... | ... |
@@ -221,18 +219,18 @@ func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
|
| 221 | 221 |
if err != nil {
|
| 222 | 222 |
t.Fatalf("error getting cluster admin client config: %v", err)
|
| 223 | 223 |
} |
| 224 |
- openshiftProjectAdminClient, err := testserver.CreateNewProject(openshiftClusterAdminClient, *openshiftClusterAdminClientConfig, testutil.Namespace(), "bob") |
|
| 224 |
+ oc, err := testserver.CreateNewProject(openshiftClusterAdminClient, *openshiftClusterAdminClientConfig, testutil.Namespace(), "bob") |
|
| 225 | 225 |
if err != nil {
|
| 226 | 226 |
t.Fatalf("error creating project: %v", err)
|
| 227 | 227 |
} |
| 228 | 228 |
|
| 229 | 229 |
imageStream := &imageapi.ImageStream{ObjectMeta: kapi.ObjectMeta{Name: deploytest.ImageStreamName}}
|
| 230 | 230 |
|
| 231 |
- if imageStream, err = openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
|
|
| 231 |
+ if imageStream, err = oc.ImageStreams(testutil.Namespace()).Create(imageStream); err != nil {
|
|
| 232 | 232 |
t.Fatalf("Couldn't create imagestream: %v", err)
|
| 233 | 233 |
} |
| 234 | 234 |
|
| 235 |
- imageWatch, err := openshiftProjectAdminClient.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
|
|
| 235 |
+ imageWatch, err := oc.ImageStreams(testutil.Namespace()).Watch(kapi.ListOptions{})
|
|
| 236 | 236 |
if err != nil {
|
| 237 | 237 |
t.Fatalf("Couldn't subscribe to imagestreams: %v", err)
|
| 238 | 238 |
} |
| ... | ... |
@@ -252,32 +250,36 @@ func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
|
| 252 | 252 |
DockerImageReference: pullSpec, |
| 253 | 253 |
}, |
| 254 | 254 |
} |
| 255 |
- updated := "" |
|
| 256 | 255 |
|
| 257 | 256 |
createTagEvent := func(mapping *imageapi.ImageStreamMapping) {
|
| 258 |
- if err := openshiftProjectAdminClient.ImageStreamMappings(testutil.Namespace()).Create(mapping); err != nil {
|
|
| 257 |
+ if err := oc.ImageStreamMappings(testutil.Namespace()).Create(mapping); err != nil {
|
|
| 259 | 258 |
t.Fatalf("unexpected error: %v", err)
|
| 260 | 259 |
} |
| 261 | 260 |
|
| 262 | 261 |
t.Log("Waiting for image stream mapping to be reflected in the image stream status...")
|
| 263 | 262 |
|
| 263 |
+ timeout := time.After(time.Minute) |
|
| 264 |
+ |
|
| 264 | 265 |
for {
|
| 265 | 266 |
select {
|
| 266 | 267 |
case event := <-imageWatch.ResultChan(): |
| 267 | 268 |
stream := event.Object.(*imageapi.ImageStream) |
| 268 | 269 |
tagEventList, ok := stream.Status.Tags[imageapi.DefaultImageTag] |
| 269 |
- if ok {
|
|
| 270 |
- if updated != tagEventList.Items[0].DockerImageReference {
|
|
| 271 |
- updated = tagEventList.Items[0].DockerImageReference |
|
| 272 |
- return |
|
| 273 |
- } |
|
| 270 |
+ if ok && len(tagEventList.Items) > 0 && tagEventList.Items[0].DockerImageReference == mapping.Image.DockerImageReference {
|
|
| 271 |
+ t.Logf("imagestream %q now has status with tags: %#v", stream.Name, stream.Status.Tags)
|
|
| 272 |
+ return |
|
| 274 | 273 |
} |
| 275 |
- t.Logf("Still waiting for latest tag status update on imagestream %q", stream.Name)
|
|
| 274 |
+ if len(tagEventList.Items) > 0 {
|
|
| 275 |
+ t.Logf("want: %s, got: %s", mapping.Image.DockerImageReference, tagEventList.Items[0].DockerImageReference)
|
|
| 276 |
+ } |
|
| 277 |
+ t.Logf("Still waiting for latest tag status update on imagestream %q with tags: %#v", stream.Name, tagEventList)
|
|
| 278 |
+ case <-timeout: |
|
| 279 |
+ t.Fatalf("timed out waiting for image stream %q to be updated", imageStream.Name)
|
|
| 276 | 280 |
} |
| 277 | 281 |
} |
| 278 | 282 |
} |
| 279 | 283 |
|
| 280 |
- configWatch, err := openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
|
|
| 284 |
+ configWatch, err := oc.DeploymentConfigs(testutil.Namespace()).Watch(kapi.ListOptions{})
|
|
| 281 | 285 |
if err != nil {
|
| 282 | 286 |
t.Fatalf("Couldn't subscribe to deploymentconfigs: %v", err)
|
| 283 | 287 |
} |
| ... | ... |
@@ -287,18 +289,20 @@ func TestTriggers_imageChange_nonAutomatic(t *testing.T) {
|
| 287 | 287 |
config.Namespace = testutil.Namespace() |
| 288 | 288 |
config.Spec.Triggers = []deployapi.DeploymentTriggerPolicy{deploytest.OkImageChangeTrigger()}
|
| 289 | 289 |
config.Spec.Triggers[0].ImageChangeParams.Automatic = false |
| 290 |
- if config, err = openshiftProjectAdminClient.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
|
|
| 290 |
+ if config, err = oc.DeploymentConfigs(testutil.Namespace()).Create(config); err != nil {
|
|
| 291 | 291 |
t.Fatalf("Couldn't create deploymentconfig: %v", err)
|
| 292 | 292 |
} |
| 293 | 293 |
|
| 294 | 294 |
createTagEvent(mapping) |
| 295 | 295 |
|
| 296 | 296 |
var newConfig *deployapi.DeploymentConfig |
| 297 |
- t.Log("Waiting for the initial deploymentconfig update in response to the imagestream update")
|
|
| 297 |
+ t.Log("Waiting for the first imagestream update - no deployment should run")
|
|
| 298 | 298 |
|
| 299 |
- timeout := time.After(30 * time.Second) |
|
| 299 |
+ timeout := time.After(20 * time.Second) |
|
| 300 | 300 |
|
| 301 |
- // This is the initial deployment with automatic=false in its ICT - it should be updated to pullSpec |
|
| 301 |
+ // Deployment config with automatic=false in its ICT - no deployment should trigger. |
|
| 302 |
+ // We don't really care about the initial update since it's not going to be deployed |
|
| 303 |
+ // anyway. |
|
| 302 | 304 |
out: |
| 303 | 305 |
for {
|
| 304 | 306 |
select {
|
| ... | ... |
@@ -313,21 +317,21 @@ out: |
| 313 | 313 |
t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
|
| 314 | 314 |
} |
| 315 | 315 |
|
| 316 |
- if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
|
|
| 317 |
- break out |
|
| 318 |
- } |
|
| 319 | 316 |
case <-timeout: |
| 320 |
- t.Fatalf("timed out waiting for the image update to happen")
|
|
| 317 |
+ break out |
|
| 321 | 318 |
} |
| 322 | 319 |
} |
| 323 | 320 |
|
| 324 |
- t.Log("Waiting for the second imagestream update - it shouldn't update the deploymentconfig")
|
|
| 321 |
+ t.Log("Waiting for the second imagestream update - no deployment should run")
|
|
| 325 | 322 |
|
| 326 | 323 |
// Subsequent updates to the image shouldn't update the pod template image |
| 327 | 324 |
mapping.Image.Name = "sha256:thisupdatedimageshouldneverlandinthepodtemplate" |
| 328 | 325 |
mapping.Image.DockerImageReference = fmt.Sprintf("registry:8080/%s/%s@%s", testutil.Namespace(), deploytest.ImageStreamName, mapping.Image.Name)
|
| 329 | 326 |
createTagEvent(mapping) |
| 330 | 327 |
|
| 328 |
+ timeout = time.After(20 * time.Second) |
|
| 329 |
+ |
|
| 330 |
+loop: |
|
| 331 | 331 |
for {
|
| 332 | 332 |
select {
|
| 333 | 333 |
case event := <-configWatch.ResultChan(): |
| ... | ... |
@@ -341,13 +345,36 @@ out: |
| 341 | 341 |
t.Fatalf("unexpected latestVersion update - the config has no config change trigger")
|
| 342 | 342 |
} |
| 343 | 343 |
|
| 344 |
- if e, a := updated, newConfig.Spec.Template.Spec.Containers[0].Image; e == a {
|
|
| 345 |
- t.Fatalf("unexpected image update, expected initial image to be the same: %#v", newConfig)
|
|
| 346 |
- } |
|
| 347 | 344 |
case <-timeout: |
| 348 |
- return |
|
| 345 |
+ break loop |
|
| 349 | 346 |
} |
| 350 | 347 |
} |
| 348 |
+ |
|
| 349 |
+ t.Log("Instantiate the deployment config - the latest image should be picked up and a new deployment should run")
|
|
| 350 |
+ request := &deployapi.DeploymentRequest{
|
|
| 351 |
+ Name: config.Name, |
|
| 352 |
+ Latest: true, |
|
| 353 |
+ Force: true, |
|
| 354 |
+ } |
|
| 355 |
+ if _, err = oc.DeploymentConfigs(config.Namespace).Instantiate(request); err != nil {
|
|
| 356 |
+ t.Fatalf("Couldn't instantiate deployment config %q: %v", config.Name, err)
|
|
| 357 |
+ } |
|
| 358 |
+ config, err = oc.DeploymentConfigs(config.Namespace).Get(config.Name) |
|
| 359 |
+ if err != nil {
|
|
| 360 |
+ t.Fatalf("Unexpected error: %v", err)
|
|
| 361 |
+ } |
|
| 362 |
+ if exp, got := mapping.Image.DockerImageReference, config.Spec.Template.Spec.Containers[0].Image; exp != got {
|
|
| 363 |
+ t.Fatalf("Expected image %q instead of %q to be updated in deployment config %q", exp, got, config.Name)
|
|
| 364 |
+ } |
|
| 365 |
+ if exp, got := int64(1), config.Status.LatestVersion; exp != got {
|
|
| 366 |
+ t.Fatalf("Expected latestVersion for deployment config %q to be %d, got %d", config.Name, exp, got)
|
|
| 367 |
+ } |
|
| 368 |
+ if config.Status.Details == nil || len(config.Status.Details.Causes) == 0 {
|
|
| 369 |
+ t.Fatalf("Expected a cause of deployment for deployment config %q", config.Name)
|
|
| 370 |
+ } |
|
| 371 |
+ if gotType, expectedType := config.Status.Details.Causes[0].Type, deployapi.DeploymentTriggerManual; gotType != expectedType {
|
|
| 372 |
+ t.Fatalf("Instantiated deployment config should have a %q cause of deployment instead of %q", expectedType, gotType)
|
|
| 373 |
+ } |
|
| 351 | 374 |
} |
| 352 | 375 |
|
| 353 | 376 |
// TestTriggers_MultipleICTs ensures that a deployment config with more than one ImageChange trigger |
| ... | ... |
@@ -462,18 +489,18 @@ out: |
| 462 | 462 |
} |
| 463 | 463 |
container := newConfig.Spec.Template.Spec.Containers[0] |
| 464 | 464 |
if e, a := updatedPullSpec, container.Image; e == a {
|
| 465 |
- break out |
|
| 465 |
+ t.Fatalf("unexpected image update: %#v", newConfig)
|
|
| 466 | 466 |
} |
| 467 | 467 |
|
| 468 | 468 |
case <-timeout: |
| 469 |
- t.Fatalf("timed out waiting for the first image update to happen")
|
|
| 469 |
+ break out |
|
| 470 | 470 |
} |
| 471 | 471 |
} |
| 472 | 472 |
|
| 473 | 473 |
t.Log("Should trigger a new deployment in response to the second imagestream update")
|
| 474 |
- updatedImage = "sampleImage" |
|
| 475 |
- updatedPullSpec = "samplePullSpec" |
|
| 476 |
- createTagEvent(secondImageStream.Name, imageapi.DefaultImageTag, updatedImage, updatedPullSpec) |
|
| 474 |
+ secondImage := "sampleImage" |
|
| 475 |
+ secondPullSpec := "samplePullSpec" |
|
| 476 |
+ createTagEvent(secondImageStream.Name, imageapi.DefaultImageTag, secondImage, secondPullSpec) |
|
| 477 | 477 |
for {
|
| 478 | 478 |
inner: |
| 479 | 479 |
select {
|
| ... | ... |
@@ -489,13 +516,20 @@ out: |
| 489 | 489 |
break inner |
| 490 | 490 |
case newConfig.Status.LatestVersion > 1: |
| 491 | 491 |
t.Fatalf("unexpected latestVersion %d for %#v", newConfig.Status.LatestVersion, newConfig)
|
| 492 |
+ default: |
|
| 493 |
+ // Keep on |
|
| 492 | 494 |
} |
| 493 | 495 |
|
| 494 |
- container := newConfig.Spec.Template.Spec.Containers[1] |
|
| 496 |
+ container := newConfig.Spec.Template.Spec.Containers[0] |
|
| 495 | 497 |
if e, a := updatedPullSpec, container.Image; e != a {
|
| 496 | 498 |
t.Fatalf("unexpected image for pod template container %q; expected %q, got %q", container.Name, e, a)
|
| 497 | 499 |
} |
| 498 | 500 |
|
| 501 |
+ container = newConfig.Spec.Template.Spec.Containers[1] |
|
| 502 |
+ if e, a := secondPullSpec, container.Image; e != a {
|
|
| 503 |
+ t.Fatalf("unexpected image for pod template container %q; expected %q, got %q", container.Name, e, a)
|
|
| 504 |
+ } |
|
| 505 |
+ |
|
| 499 | 506 |
return |
| 500 | 507 |
|
| 501 | 508 |
case <-timeout: |
| ... | ... |
@@ -543,7 +577,8 @@ func TestTriggers_configChange(t *testing.T) {
|
| 543 | 543 |
defer rcWatch.Stop() |
| 544 | 544 |
|
| 545 | 545 |
// submit the initial deployment config |
| 546 |
- if _, err := osClient.DeploymentConfigs(namespace).Create(config); err != nil {
|
|
| 546 |
+ config, err = osClient.DeploymentConfigs(namespace).Create(config) |
|
| 547 |
+ if err != nil {
|
|
| 547 | 548 |
t.Fatalf("Couldn't create DeploymentConfig: %v", err)
|
| 548 | 549 |
} |
| 549 | 550 |
|
| ... | ... |
@@ -559,28 +594,50 @@ func TestTriggers_configChange(t *testing.T) {
|
| 559 | 559 |
t.Fatalf("Expected deployment annotated with deploymentConfig '%s', got '%s'", e, a)
|
| 560 | 560 |
} |
| 561 | 561 |
|
| 562 |
- assertEnvVarEquals("ENV1", "VAL1", deployment, t)
|
|
| 563 |
- |
|
| 562 |
+ // before we update the config, we need to update the state of the existing deployment |
|
| 563 |
+ // this is required to be done manually since the deployment and deployer pod controllers are not run in this test |
|
| 564 |
+ // get this live or conflicts will never end up resolved |
|
| 564 | 565 |
retryErr := kclient.RetryOnConflict(wait.Backoff{Steps: maxUpdateRetries}, func() error {
|
| 565 |
- // before we update the config, we need to update the state of the existing deployment |
|
| 566 |
- // this is required to be done manually since the deployment and deployer pod controllers are not run in this test |
|
| 567 |
- // get this live or conflicts will never end up resolved |
|
| 568 | 566 |
liveDeployment, err := kubeClient.ReplicationControllers(deployment.Namespace).Get(deployment.Name) |
| 569 | 567 |
if err != nil {
|
| 570 | 568 |
return err |
| 571 | 569 |
} |
| 570 |
+ |
|
| 572 | 571 |
liveDeployment.Annotations[deployapi.DeploymentStatusAnnotation] = string(deployapi.DeploymentStatusComplete) |
| 572 |
+ |
|
| 573 | 573 |
// update the deployment |
| 574 |
- if _, err := kubeClient.ReplicationControllers(namespace).Update(liveDeployment); err != nil {
|
|
| 574 |
+ _, err = kubeClient.ReplicationControllers(namespace).Update(liveDeployment) |
|
| 575 |
+ return err |
|
| 576 |
+ }) |
|
| 577 |
+ if retryErr != nil {
|
|
| 578 |
+ t.Fatal(retryErr) |
|
| 579 |
+ } |
|
| 580 |
+ |
|
| 581 |
+ event = <-rcWatch.ResultChan() |
|
| 582 |
+ if e, a := watchapi.Modified, event.Type; e != a {
|
|
| 583 |
+ t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 584 |
+ } |
|
| 585 |
+ |
|
| 586 |
+ assertEnvVarEquals("ENV1", "VAL1", deployment, t)
|
|
| 587 |
+ |
|
| 588 |
+ // Update the config with a new environment variable and observe a new deployment |
|
| 589 |
+ // coming up. |
|
| 590 |
+ retryErr = kclient.RetryOnConflict(wait.Backoff{Steps: maxUpdateRetries}, func() error {
|
|
| 591 |
+ latest, err := osClient.DeploymentConfigs(namespace).Get(config.Name) |
|
| 592 |
+ if err != nil {
|
|
| 575 | 593 |
return err |
| 576 | 594 |
} |
| 577 | 595 |
|
| 578 |
- event = <-rcWatch.ResultChan() |
|
| 579 |
- if e, a := watchapi.Modified, event.Type; e != a {
|
|
| 580 |
- t.Fatalf("expected watch event type %s, got %s", e, a)
|
|
| 596 |
+ for i, e := range latest.Spec.Template.Spec.Containers[0].Env {
|
|
| 597 |
+ if e.Name == "ENV1" {
|
|
| 598 |
+ latest.Spec.Template.Spec.Containers[0].Env[i].Value = "UPDATED" |
|
| 599 |
+ break |
|
| 600 |
+ } |
|
| 581 | 601 |
} |
| 582 | 602 |
|
| 583 |
- return nil |
|
| 603 |
+ // update the config |
|
| 604 |
+ _, err = osClient.DeploymentConfigs(namespace).Update(latest) |
|
| 605 |
+ return err |
|
| 584 | 606 |
}) |
| 585 | 607 |
if retryErr != nil {
|
| 586 | 608 |
t.Fatal(retryErr) |
| ... | ... |
@@ -657,9 +657,7 @@ items: |
| 657 | 657 |
- "" |
| 658 | 658 |
attributeRestrictions: null |
| 659 | 659 |
resources: |
| 660 |
- - deploymentconfigrollbacks |
|
| 661 | 660 |
- deploymentconfigs |
| 662 |
- - deploymentconfigs/rollback |
|
| 663 | 661 |
- deploymentconfigs/scale |
| 664 | 662 |
- generatedeploymentconfigs |
| 665 | 663 |
verbs: |
| ... | ... |
@@ -675,6 +673,15 @@ items: |
| 675 | 675 |
- "" |
| 676 | 676 |
attributeRestrictions: null |
| 677 | 677 |
resources: |
| 678 |
+ - deploymentconfigrollbacks |
|
| 679 |
+ - deploymentconfigs/instantiate |
|
| 680 |
+ - deploymentconfigs/rollback |
|
| 681 |
+ verbs: |
|
| 682 |
+ - create |
|
| 683 |
+ - apiGroups: |
|
| 684 |
+ - "" |
|
| 685 |
+ attributeRestrictions: null |
|
| 686 |
+ resources: |
|
| 678 | 687 |
- deploymentconfigs/log |
| 679 | 688 |
- deploymentconfigs/status |
| 680 | 689 |
verbs: |
| ... | ... |
@@ -1008,9 +1015,7 @@ items: |
| 1008 | 1008 |
- "" |
| 1009 | 1009 |
attributeRestrictions: null |
| 1010 | 1010 |
resources: |
| 1011 |
- - deploymentconfigrollbacks |
|
| 1012 | 1011 |
- deploymentconfigs |
| 1013 |
- - deploymentconfigs/rollback |
|
| 1014 | 1012 |
- deploymentconfigs/scale |
| 1015 | 1013 |
- generatedeploymentconfigs |
| 1016 | 1014 |
verbs: |
| ... | ... |
@@ -1026,6 +1031,15 @@ items: |
| 1026 | 1026 |
- "" |
| 1027 | 1027 |
attributeRestrictions: null |
| 1028 | 1028 |
resources: |
| 1029 |
+ - deploymentconfigrollbacks |
|
| 1030 |
+ - deploymentconfigs/instantiate |
|
| 1031 |
+ - deploymentconfigs/rollback |
|
| 1032 |
+ verbs: |
|
| 1033 |
+ - create |
|
| 1034 |
+ - apiGroups: |
|
| 1035 |
+ - "" |
|
| 1036 |
+ attributeRestrictions: null |
|
| 1037 |
+ resources: |
|
| 1029 | 1038 |
- deploymentconfigs/log |
| 1030 | 1039 |
- deploymentconfigs/status |
| 1031 | 1040 |
verbs: |