mirror of https://github.com/knative/client.git
update: Change default to server-side generated revision names (extended) (#1240)
* update: Change default to server-side generated revision names Fixes #1144 * update: Fix wait loop for synthetic events for which the generations are already in sync * fix assertion as a service label change does not create a new revision * fix: --cluster-local does not create a new revision but just changes a service's label * chore: Fixed formatting * update: Check generation in update already before doing a watch * fixed lint issue * fix test assertions
This commit is contained in:
parent
09c5129c96
commit
5f68d61295
|
|
@ -37,6 +37,10 @@
|
||||||
| 🐣
|
| 🐣
|
||||||
| Do not print `serviceUID` and `configUID` labels in service export results
|
| Do not print `serviceUID` and `configUID` labels in service export results
|
||||||
| https://github.com/knative/client/pull/1194[#1194]
|
| https://github.com/knative/client/pull/1194[#1194]
|
||||||
|
|
||||||
|
| ✨
|
||||||
|
| Use server-side generated revision names by default now. For BYO revision names use `--revision-name` for service commands
|
||||||
|
| https://github.com/knative/client/issues/1240[#1240]
|
||||||
|===
|
|===
|
||||||
|
|
||||||
## v0.20.0 (2021-01-14)
|
## v0.20.0 (2021-01-14)
|
||||||
|
|
|
||||||
|
|
@ -58,7 +58,7 @@ kn service apply s0 --filename my-svc.yml
|
||||||
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
||||||
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
||||||
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
||||||
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants. (default "{{.Service}}-{{.Random 5}}-{{.Generation}}")
|
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
|
||||||
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
||||||
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
||||||
--scale-max int Maximum number of replicas.
|
--scale-max int Maximum number of replicas.
|
||||||
|
|
|
||||||
|
|
@ -83,7 +83,7 @@ kn service create NAME --image IMAGE
|
||||||
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
||||||
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
||||||
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
||||||
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants. (default "{{.Service}}-{{.Random 5}}-{{.Generation}}")
|
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
|
||||||
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
||||||
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
||||||
--scale-max int Maximum number of replicas.
|
--scale-max int Maximum number of replicas.
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ kn service update NAME
|
||||||
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
-p, --port string The port where application listens on, in the format 'NAME:PORT', where 'NAME' is optional. Examples: '--port h2c:8080' , '--port 8080'.
|
||||||
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
--pull-secret string Image pull secret to set. An empty argument ("") clears the pull secret. The referenced secret must exist in the service's namespace.
|
||||||
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
--request strings The resource requirement requests for this Service. For example, 'cpu=100m,memory=256Mi'. You can use this flag multiple times. To unset a resource request, append "-" to the resource name, e.g. '--request cpu-'.
|
||||||
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants. (default "{{.Service}}-{{.Random 5}}-{{.Generation}}")
|
--revision-name string The revision name to set. Must start with the service name and a dash as a prefix. Empty revision name will result in the server generating a name for the revision. Accepts golang templates, allowing {{.Service}} for the service name, {{.Generation}} for the generation, and {{.Random [n]}} for n random consonants (e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})
|
||||||
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
--scale string Set the Minimum and Maximum number of replicas. You can use this flag to set both to a single value, or set a range with min/max values, or set either min or max values without specifying the other. Example: --scale 5 (scale-min = 5, scale-max = 5) or --scale 1..5 (scale-min = 1, scale-max = 5) or --scale 1.. (scale-min = 1, scale-max = unchanged) or --scale ..5 (scale-min = unchanged, scale-max = 5)
|
||||||
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
--scale-init int Initial number of replicas with which a service starts. Can be 0 or a positive integer.
|
||||||
--scale-max int Maximum number of replicas.
|
--scale-max int Maximum number of replicas.
|
||||||
|
|
|
||||||
|
|
@ -104,9 +104,6 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
|
||||||
|
|
||||||
knflags.AddBothBoolFlagsUnhidden(command.Flags(), &p.ClusterLocal, "cluster-local", "", false,
|
knflags.AddBothBoolFlagsUnhidden(command.Flags(), &p.ClusterLocal, "cluster-local", "", false,
|
||||||
"Specify that the service be private. (--no-cluster-local will make the service publicly available)")
|
"Specify that the service be private. (--no-cluster-local will make the service publicly available)")
|
||||||
//TODO: Need to also not change revision when already set (solution to issue #646)
|
|
||||||
p.markFlagMakesRevision("cluster-local")
|
|
||||||
p.markFlagMakesRevision("no-cluster-local")
|
|
||||||
|
|
||||||
command.Flags().IntVar(&p.ConcurrencyTarget, "concurrency-target", 0,
|
command.Flags().IntVar(&p.ConcurrencyTarget, "concurrency-target", 0,
|
||||||
"Recommendation for when to scale up based on the concurrent number of incoming request. "+
|
"Recommendation for when to scale up based on the concurrent number of incoming request. "+
|
||||||
|
|
@ -140,11 +137,12 @@ func (p *ConfigurationEditFlags) addSharedFlags(command *cobra.Command) {
|
||||||
"precedence over the \"label\" flag.")
|
"precedence over the \"label\" flag.")
|
||||||
p.markFlagMakesRevision("label-revision")
|
p.markFlagMakesRevision("label-revision")
|
||||||
|
|
||||||
command.Flags().StringVar(&p.RevisionName, "revision-name", "{{.Service}}-{{.Random 5}}-{{.Generation}}",
|
command.Flags().StringVar(&p.RevisionName, "revision-name", "",
|
||||||
"The revision name to set. Must start with the service name and a dash as a prefix. "+
|
"The revision name to set. Must start with the service name and a dash as a prefix. "+
|
||||||
"Empty revision name will result in the server generating a name for the revision. "+
|
"Empty revision name will result in the server generating a name for the revision. "+
|
||||||
"Accepts golang templates, allowing {{.Service}} for the service name, "+
|
"Accepts golang templates, allowing {{.Service}} for the service name, "+
|
||||||
"{{.Generation}} for the generation, and {{.Random [n]}} for n random consonants.")
|
"{{.Generation}} for the generation, and {{.Random [n]}} for n random consonants "+
|
||||||
|
"(e.g. {{.Service}}-{{.Random 5}}-{{.Generation}})")
|
||||||
p.markFlagMakesRevision("revision-name")
|
p.markFlagMakesRevision("revision-name")
|
||||||
|
|
||||||
knflags.AddBothBoolFlagsUnhidden(command.Flags(), &p.LockToDigest, "lock-to-digest", "", true,
|
knflags.AddBothBoolFlagsUnhidden(command.Flags(), &p.LockToDigest, "lock-to-digest", "", true,
|
||||||
|
|
@ -206,30 +204,31 @@ func (p *ConfigurationEditFlags) Apply(
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
name, err := servinglib.GenerateRevisionName(p.RevisionName, service)
|
name := ""
|
||||||
if err != nil {
|
if p.RevisionName != "" {
|
||||||
return err
|
name, err = servinglib.GenerateRevisionName(p.RevisionName, service)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if p.AnyMutation(cmd) {
|
||||||
|
template.Name = name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if p.AnyMutation(cmd) {
|
|
||||||
template.Name = name
|
|
||||||
}
|
|
||||||
|
|
||||||
imageSet := false
|
|
||||||
if cmd.Flags().Changed("image") {
|
|
||||||
imageSet = true
|
|
||||||
}
|
|
||||||
_, userImagePresent := template.Annotations[servinglib.UserImageAnnotationKey]
|
_, userImagePresent := template.Annotations[servinglib.UserImageAnnotationKey]
|
||||||
freezeMode := userImagePresent || cmd.Flags().Changed("lock-to-digest")
|
freezeMode := userImagePresent || cmd.Flags().Changed("lock-to-digest")
|
||||||
if p.LockToDigest && p.AnyMutation(cmd) && freezeMode {
|
if p.LockToDigest && p.AnyMutation(cmd) && freezeMode {
|
||||||
servinglib.SetUserImageAnnot(template)
|
servinglib.SetUserImageAnnot(template)
|
||||||
if !imageSet {
|
if !cmd.Flags().Changed("image") {
|
||||||
err = servinglib.FreezeImageToDigest(template, baseRevision)
|
err = servinglib.FreezeImageToDigest(template, baseRevision)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !p.LockToDigest {
|
}
|
||||||
|
|
||||||
|
if !p.LockToDigest {
|
||||||
servinglib.UnsetUserImageAnnot(template)
|
servinglib.UnsetUserImageAnnot(template)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -155,10 +155,14 @@ func createService(client clientservingv1.KnServingClient, service *servingv1.Se
|
||||||
}
|
}
|
||||||
|
|
||||||
func replaceService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer, targetFlag string) error {
|
func replaceService(client clientservingv1.KnServingClient, service *servingv1.Service, waitFlags commands.WaitFlags, out io.Writer, targetFlag string) error {
|
||||||
err := prepareAndUpdateService(client, service)
|
changed, err := prepareAndUpdateService(client, service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if !changed {
|
||||||
|
fmt.Fprintf(out, "Service '%s' replaced in namespace '%s' (unchanged).\n", service.Name, client.Namespace())
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return waitIfRequested(client, waitFlags, service.Name, "Replacing", "replaced", targetFlag, out)
|
return waitIfRequested(client, waitFlags, service.Name, "Replacing", "replaced", targetFlag, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -171,12 +175,12 @@ func waitIfRequested(client clientservingv1.KnServingClient, waitFlags commands.
|
||||||
return waitForServiceToGetReady(client, serviceName, waitFlags.TimeoutInSeconds, verbDone, out)
|
return waitForServiceToGetReady(client, serviceName, waitFlags.TimeoutInSeconds, verbDone, out)
|
||||||
}
|
}
|
||||||
|
|
||||||
func prepareAndUpdateService(client clientservingv1.KnServingClient, service *servingv1.Service) error {
|
func prepareAndUpdateService(client clientservingv1.KnServingClient, service *servingv1.Service) (bool, error) {
|
||||||
var retries = 0
|
var retries = 0
|
||||||
for {
|
for {
|
||||||
existingService, err := client.GetService(service.Name)
|
existingService, err := client.GetService(service.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy over some annotations that we want to keep around. Erase others
|
// Copy over some annotations that we want to keep around. Erase others
|
||||||
|
|
@ -200,16 +204,16 @@ func prepareAndUpdateService(client clientservingv1.KnServingClient, service *se
|
||||||
}
|
}
|
||||||
|
|
||||||
service.ResourceVersion = existingService.ResourceVersion
|
service.ResourceVersion = existingService.ResourceVersion
|
||||||
err = client.UpdateService(service)
|
changed, err := client.UpdateService(service)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Retry to update when a resource version conflict exists
|
// Retry to update when a resource version conflict exists
|
||||||
if apierrors.IsConflict(err) && retries < MaxUpdateRetries {
|
if apierrors.IsConflict(err) && retries < MaxUpdateRetries {
|
||||||
retries++
|
retries++
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return err
|
return changed, err
|
||||||
}
|
}
|
||||||
return nil
|
return changed, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,6 +137,9 @@ func TestServiceCreateImage(t *testing.T) {
|
||||||
!strings.Contains(output, commands.FakeNamespace) {
|
!strings.Contains(output, commands.FakeNamespace) {
|
||||||
t.Fatalf("wrong stdout message: %v", output)
|
t.Fatalf("wrong stdout message: %v", output)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// No revision name set by default
|
||||||
|
assert.Assert(t, template.Name == "")
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceCreateWithMultipleImages(t *testing.T) {
|
func TestServiceCreateWithMultipleImages(t *testing.T) {
|
||||||
|
|
|
||||||
|
|
@ -131,7 +131,7 @@ func recordServiceUpdateWithSuccess(r *clientservingv1.ServingRecorder, svcName
|
||||||
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
||||||
r.CreateService(newService, nil)
|
r.CreateService(newService, nil)
|
||||||
r.GetService(svcName, newService, nil)
|
r.GetService(svcName, newService, nil)
|
||||||
r.UpdateService(updatedService, nil)
|
r.UpdateService(updatedService, true, nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestServiceUpdateEnvFromAddingWithConfigMap(t *testing.T) {
|
func TestServiceUpdateEnvFromAddingWithConfigMap(t *testing.T) {
|
||||||
|
|
@ -283,7 +283,7 @@ func TestServiceUpdateEnvFromRemovalWithConfigMap(t *testing.T) {
|
||||||
r.GetService(svcName, updatedService1, nil)
|
r.GetService(svcName, updatedService1, nil)
|
||||||
//r.UpdateService(updatedService2, nil) // since an error happens, update is not triggered here
|
//r.UpdateService(updatedService2, nil) // since an error happens, update is not triggered here
|
||||||
r.GetService(svcName, updatedService2, nil)
|
r.GetService(svcName, updatedService2, nil)
|
||||||
r.UpdateService(updatedService3, nil)
|
r.UpdateService(updatedService3, true, nil)
|
||||||
|
|
||||||
output, err := executeServiceCommand(client,
|
output, err := executeServiceCommand(client,
|
||||||
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
||||||
|
|
@ -372,7 +372,7 @@ func TestServiceUpdateEnvFromRemovalWithEmptyName(t *testing.T) {
|
||||||
r.CreateService(newService, nil)
|
r.CreateService(newService, nil)
|
||||||
r.GetService(svcName, newService, nil)
|
r.GetService(svcName, newService, nil)
|
||||||
r.GetService(svcName, newService, nil)
|
r.GetService(svcName, newService, nil)
|
||||||
r.UpdateService(updatedService1, nil)
|
r.UpdateService(updatedService1, true, nil)
|
||||||
|
|
||||||
output, err := executeServiceCommand(client,
|
output, err := executeServiceCommand(client,
|
||||||
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
||||||
|
|
@ -625,11 +625,11 @@ func TestServiceUpdateEnvFromRemovalWithSecret(t *testing.T) {
|
||||||
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
||||||
r.CreateService(newService, nil)
|
r.CreateService(newService, nil)
|
||||||
r.GetService(svcName, newService, nil)
|
r.GetService(svcName, newService, nil)
|
||||||
r.UpdateService(updatedService1, nil)
|
r.UpdateService(updatedService1, true, nil)
|
||||||
r.GetService(svcName, updatedService1, nil)
|
r.GetService(svcName, updatedService1, nil)
|
||||||
//r.UpdateService(updatedService2, nil) // since an error happens, update is not triggered here
|
//r.UpdateService(updatedService2, nil) // since an error happens, update is not triggered here
|
||||||
r.GetService(svcName, updatedService2, nil)
|
r.GetService(svcName, updatedService2, nil)
|
||||||
r.UpdateService(updatedService3, nil)
|
r.UpdateService(updatedService3, true, nil)
|
||||||
|
|
||||||
output, err := executeServiceCommand(client,
|
output, err := executeServiceCommand(client,
|
||||||
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
||||||
|
|
@ -1383,9 +1383,9 @@ func TestServiceUpdateWithRemovingMount(t *testing.T) {
|
||||||
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
r.GetService(svcName, nil, errors.NewNotFound(servingv1.Resource("service"), svcName))
|
||||||
r.CreateService(newService, nil)
|
r.CreateService(newService, nil)
|
||||||
r.GetService(svcName, newService, nil)
|
r.GetService(svcName, newService, nil)
|
||||||
r.UpdateService(updatedService1, nil)
|
r.UpdateService(updatedService1, true, nil)
|
||||||
r.GetService(svcName, updatedService1, nil)
|
r.GetService(svcName, updatedService1, nil)
|
||||||
r.UpdateService(updatedService2, nil)
|
r.UpdateService(updatedService2, true, nil)
|
||||||
|
|
||||||
output, err := executeServiceCommand(client,
|
output, err := executeServiceCommand(client,
|
||||||
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
"create", svcName, "--image", "gcr.io/foo/bar:baz",
|
||||||
|
|
|
||||||
|
|
@ -109,12 +109,19 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Do the actual update with retry in case of conflicts
|
// Do the actual update with retry in case of conflicts
|
||||||
err = client.UpdateServiceWithRetry(name, updateFunc, MaxUpdateRetries)
|
changed, err := client.UpdateServiceWithRetry(name, updateFunc, MaxUpdateRetries)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
out := cmd.OutOrStdout()
|
out := cmd.OutOrStdout()
|
||||||
|
|
||||||
|
// No need to wait if not changed
|
||||||
|
if !changed {
|
||||||
|
fmt.Fprintf(out, "Service '%s' updated in namespace '%s'.\n", args[0], namespace)
|
||||||
|
fmt.Fprintln(out, "No new revision has been created.")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
if waitFlags.Wait && targetFlag == "" {
|
if waitFlags.Wait && targetFlag == "" {
|
||||||
fmt.Fprintf(out, "Updating Service '%s' in namespace '%s':\n", args[0], namespace)
|
fmt.Fprintf(out, "Updating Service '%s' in namespace '%s':\n", args[0], namespace)
|
||||||
fmt.Fprintln(out, "")
|
fmt.Fprintln(out, "")
|
||||||
|
|
|
||||||
|
|
@ -62,10 +62,12 @@ func fakeServiceUpdate(original *servingv1.Service, args []string) (
|
||||||
if !ok {
|
if !ok {
|
||||||
return true, nil, fmt.Errorf("wrong kind of action %v", action)
|
return true, nil, fmt.Errorf("wrong kind of action %v", action)
|
||||||
}
|
}
|
||||||
updated, ok = updateAction.GetObject().(*servingv1.Service)
|
given, ok := updateAction.GetObject().(*servingv1.Service)
|
||||||
if !ok {
|
if !ok {
|
||||||
return true, nil, errors.New("was passed the wrong object")
|
return true, nil, errors.New("was passed the wrong object")
|
||||||
}
|
}
|
||||||
|
updated = given.DeepCopy()
|
||||||
|
updated.Generation = given.Generation + 1
|
||||||
return true, updated, nil
|
return true, updated, nil
|
||||||
})
|
})
|
||||||
fakeServing.AddReactor("get", "services",
|
fakeServing.AddReactor("get", "services",
|
||||||
|
|
@ -271,7 +273,7 @@ func TestServiceUpdateRevisionNameGenerated(t *testing.T) {
|
||||||
|
|
||||||
// Test prefix added by command
|
// Test prefix added by command
|
||||||
action, updated, _, err := fakeServiceUpdate(orig, []string{
|
action, updated, _, err := fakeServiceUpdate(orig, []string{
|
||||||
"service", "update", "foo", "--image", "gcr.io/foo/quux:xyzzy", "--namespace", "bar", "--no-wait"})
|
"service", "update", "foo", "--image", "gcr.io/foo/quux:xyzzy", "--namespace", "bar", "--no-wait", "--revision-name", "{{.Service}}-{{.Random 5}}-{{.Generation}}"})
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
if !action.Matches("update", "services") {
|
if !action.Matches("update", "services") {
|
||||||
t.Fatalf("Bad action %v", action)
|
t.Fatalf("Bad action %v", action)
|
||||||
|
|
@ -282,6 +284,24 @@ func TestServiceUpdateRevisionNameGenerated(t *testing.T) {
|
||||||
assert.Assert(t, !(template.Name == "foo-asdf"))
|
assert.Assert(t, !(template.Name == "foo-asdf"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestServiceUpdateRevisionNameDefault(t *testing.T) {
|
||||||
|
orig := newEmptyService()
|
||||||
|
|
||||||
|
template := orig.Spec.Template
|
||||||
|
template.Name = "foo-asdf"
|
||||||
|
|
||||||
|
// Test prefix added by command
|
||||||
|
action, updated, _, err := fakeServiceUpdate(orig, []string{
|
||||||
|
"service", "update", "foo", "--image", "gcr.io/foo/quux:xyzzy"})
|
||||||
|
assert.NilError(t, err)
|
||||||
|
if !action.Matches("update", "services") {
|
||||||
|
t.Fatalf("Bad action %v", action)
|
||||||
|
}
|
||||||
|
|
||||||
|
template = updated.Spec.Template
|
||||||
|
assert.Assert(t, cmp.Equal(template.Name, ""))
|
||||||
|
}
|
||||||
|
|
||||||
func TestServiceUpdateRevisionNameCleared(t *testing.T) {
|
func TestServiceUpdateRevisionNameCleared(t *testing.T) {
|
||||||
orig := newEmptyService()
|
orig := newEmptyService()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -62,12 +62,12 @@ type KnServingClient interface {
|
||||||
|
|
||||||
// UpdateService updates the given service. For a more robust variant with automatic
|
// UpdateService updates the given service. For a more robust variant with automatic
|
||||||
// conflict resolution see UpdateServiceWithRetry
|
// conflict resolution see UpdateServiceWithRetry
|
||||||
UpdateService(service *servingv1.Service) error
|
UpdateService(service *servingv1.Service) (bool, error)
|
||||||
|
|
||||||
// UpdateServiceWithRetry updates service and retries if there is a version conflict.
|
// UpdateServiceWithRetry updates service and retries if there is a version conflict.
|
||||||
// The updateFunc receives a deep copy of the existing service and can add update it in
|
// The updateFunc receives a deep copy of the existing service and can add update it in
|
||||||
// place.
|
// place. Return if the service creates a new generation or not
|
||||||
UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) error
|
UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) (bool, error)
|
||||||
|
|
||||||
// Apply a service's definition to the cluster. The full service declaration needs to be provided,
|
// Apply a service's definition to the cluster. The full service declaration needs to be provided,
|
||||||
// which is different to UpdateService which can also do a partial update. If the given
|
// which is different to UpdateService which can also do a partial update. If the given
|
||||||
|
|
@ -241,36 +241,37 @@ func (cl *knServingClient) CreateService(service *servingv1.Service) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the given service
|
// Update the given service
|
||||||
func (cl *knServingClient) UpdateService(service *servingv1.Service) error {
|
func (cl *knServingClient) UpdateService(service *servingv1.Service) (bool, error) {
|
||||||
_, err := cl.client.Services(cl.namespace).Update(context.TODO(), service, v1.UpdateOptions{})
|
updated, err := cl.client.Services(cl.namespace).Update(context.TODO(), service, v1.UpdateOptions{})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
return updateServingGvk(service)
|
changed := service.ObjectMeta.Generation != updated.ObjectMeta.Generation
|
||||||
|
return changed, updateServingGvk(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the given service with a retry in case of a conflict
|
// Update the given service with a retry in case of a conflict
|
||||||
func (cl *knServingClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) error {
|
func (cl *knServingClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) (bool, error) {
|
||||||
return updateServiceWithRetry(cl, name, updateFunc, nrRetries)
|
return updateServiceWithRetry(cl, name, updateFunc, nrRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Extracted to be usable with the Mocking client
|
// Extracted to be usable with the Mocking client
|
||||||
func updateServiceWithRetry(cl KnServingClient, name string, updateFunc ServiceUpdateFunc, nrRetries int) error {
|
func updateServiceWithRetry(cl KnServingClient, name string, updateFunc ServiceUpdateFunc, nrRetries int) (bool, error) {
|
||||||
var retries = 0
|
var retries = 0
|
||||||
for {
|
for {
|
||||||
service, err := cl.GetService(name)
|
service, err := cl.GetService(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
if service.GetDeletionTimestamp() != nil {
|
if service.GetDeletionTimestamp() != nil {
|
||||||
return fmt.Errorf("can't update service %s because it has been marked for deletion", name)
|
return false, fmt.Errorf("can't update service %s because it has been marked for deletion", name)
|
||||||
}
|
}
|
||||||
updatedService, err := updateFunc(service.DeepCopy())
|
updatedService, err := updateFunc(service.DeepCopy())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = cl.UpdateService(updatedService)
|
changed, err := cl.UpdateService(updatedService)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
// Retry to update when a resource version conflict exists
|
// Retry to update when a resource version conflict exists
|
||||||
if apierrors.IsConflict(err) && retries < nrRetries {
|
if apierrors.IsConflict(err) && retries < nrRetries {
|
||||||
|
|
@ -279,9 +280,9 @@ func updateServiceWithRetry(cl KnServingClient, name string, updateFunc ServiceU
|
||||||
time.Sleep(time.Second)
|
time.Sleep(time.Second)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
return fmt.Errorf("giving up after %d retries: %w", nrRetries, err)
|
return false, fmt.Errorf("giving up after %d retries: %w", nrRetries, err)
|
||||||
}
|
}
|
||||||
return nil
|
return changed, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -90,17 +90,17 @@ func (c *MockKnServingClient) CreateService(service *servingv1.Service) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the given service
|
// Update the given service
|
||||||
func (sr *ServingRecorder) UpdateService(service interface{}, err error) {
|
func (sr *ServingRecorder) UpdateService(service interface{}, hasChanged bool, err error) {
|
||||||
sr.r.Add("UpdateService", []interface{}{service}, []interface{}{err})
|
sr.r.Add("UpdateService", []interface{}{service}, []interface{}{hasChanged, err})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *MockKnServingClient) UpdateService(service *servingv1.Service) error {
|
func (c *MockKnServingClient) UpdateService(service *servingv1.Service) (bool, error) {
|
||||||
call := c.recorder.r.VerifyCall("UpdateService", service)
|
call := c.recorder.r.VerifyCall("UpdateService", service)
|
||||||
return mock.ErrorOrNil(call.Result[0])
|
return call.Result[0].(bool), mock.ErrorOrNil(call.Result[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delegate to shared retry method
|
// Delegate to shared retry method
|
||||||
func (c *MockKnServingClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, maxRetry int) error {
|
func (c *MockKnServingClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, maxRetry int) (bool, error) {
|
||||||
return updateServiceWithRetry(c, name, updateFunc, maxRetry)
|
return updateServiceWithRetry(c, name, updateFunc, maxRetry)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ func TestMockKnClient(t *testing.T) {
|
||||||
recorder.ListServices(mock.Any(), nil, nil)
|
recorder.ListServices(mock.Any(), nil, nil)
|
||||||
recorder.ListServices(mock.Any(), nil, nil)
|
recorder.ListServices(mock.Any(), nil, nil)
|
||||||
recorder.CreateService(&servingv1.Service{}, nil)
|
recorder.CreateService(&servingv1.Service{}, nil)
|
||||||
recorder.UpdateService(&servingv1.Service{}, nil)
|
recorder.UpdateService(&servingv1.Service{}, false, nil)
|
||||||
recorder.ApplyService(&servingv1.Service{}, true, nil)
|
recorder.ApplyService(&servingv1.Service{}, true, nil)
|
||||||
recorder.DeleteService("hello", time.Duration(10)*time.Second, nil)
|
recorder.DeleteService("hello", time.Duration(10)*time.Second, nil)
|
||||||
recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
|
recorder.WaitForService("hello", time.Duration(10)*time.Second, wait.NoopMessageCallback(), nil, 10*time.Second)
|
||||||
|
|
|
||||||
|
|
@ -157,27 +157,29 @@ func TestCreateService(t *testing.T) {
|
||||||
func TestUpdateService(t *testing.T) {
|
func TestUpdateService(t *testing.T) {
|
||||||
serving, client := setup()
|
serving, client := setup()
|
||||||
serviceUpdate := newService("update-service")
|
serviceUpdate := newService("update-service")
|
||||||
|
serviceUpdate.ObjectMeta.Generation = 2
|
||||||
|
|
||||||
serving.AddReactor("update", "services",
|
serving.AddReactor("update", "services",
|
||||||
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
func(a clienttesting.Action) (bool, runtime.Object, error) {
|
||||||
assert.Equal(t, testNamespace, a.GetNamespace())
|
assert.Equal(t, testNamespace, a.GetNamespace())
|
||||||
name := a.(clienttesting.UpdateAction).GetObject().(metav1.Object).GetName()
|
name := a.(clienttesting.UpdateAction).GetObject().(metav1.Object).GetName()
|
||||||
if name == serviceUpdate.Name {
|
if name == serviceUpdate.Name {
|
||||||
serviceUpdate.Generation = 3
|
serviceReturn := newService("update-service")
|
||||||
return true, serviceUpdate, nil
|
serviceReturn.Generation = 3
|
||||||
|
return true, serviceReturn, nil
|
||||||
}
|
}
|
||||||
return true, nil, fmt.Errorf("error while updating service %s", name)
|
return true, nil, fmt.Errorf("error while updating service %s", name)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("updating a service without error", func(t *testing.T) {
|
t.Run("updating a service without error", func(t *testing.T) {
|
||||||
err := client.UpdateService(serviceUpdate)
|
changed, err := client.UpdateService(serviceUpdate)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
assert.Equal(t, int64(3), serviceUpdate.Generation)
|
assert.Assert(t, changed)
|
||||||
validateGroupVersionKind(t, serviceUpdate)
|
validateGroupVersionKind(t, serviceUpdate)
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("updating a service with error", func(t *testing.T) {
|
t.Run("updating a service with error", func(t *testing.T) {
|
||||||
err := client.UpdateService(newService("unknown"))
|
_, err := client.UpdateService(newService("unknown"))
|
||||||
assert.ErrorContains(t, err, "unknown")
|
assert.ErrorContains(t, err, "unknown")
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -178,17 +178,17 @@ func writeFile(obj runtime.Object, fp, format string) error {
|
||||||
|
|
||||||
// UpdateService updates the service in
|
// UpdateService updates the service in
|
||||||
// the local directory
|
// the local directory
|
||||||
func (cl *knServingGitOpsClient) UpdateService(service *servingv1.Service) error {
|
func (cl *knServingGitOpsClient) UpdateService(service *servingv1.Service) (bool, error) {
|
||||||
// check if file exist
|
// check if file exist
|
||||||
if _, err := cl.GetService(service.ObjectMeta.Name); err != nil {
|
if _, err := cl.GetService(service.ObjectMeta.Name); err != nil {
|
||||||
return err
|
return false, err
|
||||||
}
|
}
|
||||||
// replace file
|
// replace file
|
||||||
return cl.CreateService(service)
|
return true, cl.CreateService(service)
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateServiceWithRetry updates the service in the local directory
|
// UpdateServiceWithRetry updates the service in the local directory
|
||||||
func (cl *knServingGitOpsClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) error {
|
func (cl *knServingGitOpsClient) UpdateServiceWithRetry(name string, updateFunc ServiceUpdateFunc, nrRetries int) (bool, error) {
|
||||||
return updateServiceWithRetry(cl, name, updateFunc, nrRetries)
|
return updateServiceWithRetry(cl, name, updateFunc, nrRetries)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -105,13 +105,15 @@ func TestGitOpsOperations(t *testing.T) {
|
||||||
assert.DeepEqual(t, allServices, result)
|
assert.DeepEqual(t, allServices, result)
|
||||||
})
|
})
|
||||||
t.Run("update service with retry foo", func(t *testing.T) {
|
t.Run("update service with retry foo", func(t *testing.T) {
|
||||||
err := fooclient.UpdateServiceWithRetry("foo", func(svc *servingv1.Service) (*servingv1.Service, error) {
|
changed, err := fooclient.UpdateServiceWithRetry("foo", func(svc *servingv1.Service) (*servingv1.Service, error) {
|
||||||
return svc, nil
|
return svc, nil
|
||||||
}, 1)
|
}, 1)
|
||||||
|
assert.Assert(t, changed)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("update service foo", func(t *testing.T) {
|
t.Run("update service foo", func(t *testing.T) {
|
||||||
err := fooclient.UpdateService(fooUpdateSvc)
|
changed, err := fooclient.UpdateService(fooUpdateSvc)
|
||||||
|
assert.Assert(t, changed)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
})
|
})
|
||||||
t.Run("check updated service foo", func(t *testing.T) {
|
t.Run("check updated service foo", func(t *testing.T) {
|
||||||
|
|
@ -176,14 +178,17 @@ func TestGitOpsSingleFile(t *testing.T) {
|
||||||
assert.DeepEqual(t, testSvc, result)
|
assert.DeepEqual(t, testSvc, result)
|
||||||
})
|
})
|
||||||
t.Run("update service foo", func(t *testing.T) {
|
t.Run("update service foo", func(t *testing.T) {
|
||||||
err := fooclient.UpdateService(updateSvc)
|
changed, err := fooclient.UpdateService(updateSvc)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, changed)
|
||||||
|
|
||||||
err = barclient.UpdateService(updateSvc)
|
changed, err = barclient.UpdateService(updateSvc)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, changed)
|
||||||
|
|
||||||
err = bazclient.UpdateService(updateSvc)
|
changed, err = bazclient.UpdateService(updateSvc)
|
||||||
assert.NilError(t, err)
|
assert.NilError(t, err)
|
||||||
|
assert.Assert(t, changed)
|
||||||
})
|
})
|
||||||
t.Run("list services", func(t *testing.T) {
|
t.Run("list services", func(t *testing.T) {
|
||||||
result, err := fooclient.ListServices()
|
result, err := fooclient.ListServices()
|
||||||
|
|
|
||||||
|
|
@ -166,6 +166,18 @@ func (w *waitForReadyConfig) waitForReadyCondition(watcher watch.Interface, star
|
||||||
return true, false, nil
|
return true, false, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check whether resource is in sync already (meta.generation == status.observedGeneration)
|
||||||
|
inSync, err := generationCheck(event.Object)
|
||||||
|
if err != nil {
|
||||||
|
return false, false, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip events if generations has not yet been consolidated, regardless of type.
|
||||||
|
// Wait for the next event to come in until the generations align
|
||||||
|
if !inSync {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
// Skip event if its not a MODIFIED event, as only MODIFIED events update the condition
|
// Skip event if its not a MODIFIED event, as only MODIFIED events update the condition
|
||||||
// we are looking for.
|
// we are looking for.
|
||||||
// This will filter out all synthetic ADDED events that created bt the API server for
|
// This will filter out all synthetic ADDED events that created bt the API server for
|
||||||
|
|
@ -180,15 +192,6 @@ func (w *waitForReadyConfig) waitForReadyCondition(watcher watch.Interface, star
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip event if generations has not yet been consolidated
|
|
||||||
inSync, err := generationCheck(event.Object)
|
|
||||||
if err != nil {
|
|
||||||
return false, false, err
|
|
||||||
}
|
|
||||||
if !inSync {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
conditions, err := w.conditionsExtractor(event.Object)
|
conditions, err := w.conditionsExtractor(event.Object)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, false, err
|
return false, false, err
|
||||||
|
|
|
||||||
|
|
@ -156,10 +156,10 @@ func pMessages(max int) []string {
|
||||||
func peNormal(name string) ([]watch.Event, int) {
|
func peNormal(name string) ([]watch.Event, int) {
|
||||||
messages := pMessages(2)
|
messages := pMessages(2)
|
||||||
return []watch.Event{
|
return []watch.Event{
|
||||||
{Type: watch.Added, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "", messages[0])},
|
{Type: watch.Added, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "", messages[0], 1, 2)},
|
||||||
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "", messages[0])},
|
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionUnknown, "", messages[0], 2, 2)},
|
||||||
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "", messages[1])},
|
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionUnknown, corev1.ConditionTrue, "", messages[1], 2, 2)},
|
||||||
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", "")},
|
{Type: watch.Modified, Object: CreateTestServiceWithConditions(name, corev1.ConditionTrue, corev1.ConditionTrue, "", "", 2, 2)},
|
||||||
}, len(messages)
|
}, len(messages)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,7 @@ func TestRevision(t *testing.T) {
|
||||||
test.RevisionListWithService(r, "hello")
|
test.RevisionListWithService(r, "hello")
|
||||||
|
|
||||||
t.Log("update hello service and increase revision count to 3")
|
t.Log("update hello service and increase revision count to 3")
|
||||||
test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "8888")
|
test.ServiceUpdate(r, "hello", "--env", "TARGET=kn", "--port", "9000")
|
||||||
|
|
||||||
t.Log("delete three revisions with one revision a nonexistent")
|
t.Log("delete three revisions with one revision a nonexistent")
|
||||||
existRevision1 := test.FindRevisionByGeneration(r, "hello", 1)
|
existRevision1 := test.FindRevisionByGeneration(r, "hello", 1)
|
||||||
|
|
|
||||||
|
|
@ -96,7 +96,7 @@ func serviceCreatePrivateUpdatePublic(r *test.KnRunResultCollector, serviceName
|
||||||
out = r.KnTest().Kn().Run("service", "update", serviceName,
|
out = r.KnTest().Kn().Run("service", "update", serviceName,
|
||||||
"--image", pkgtest.ImagePath("helloworld"), "--no-cluster-local")
|
"--image", pkgtest.ImagePath("helloworld"), "--no-cluster-local")
|
||||||
r.AssertNoError(out)
|
r.AssertNoError(out)
|
||||||
assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "service", serviceName, "updated", "namespace", r.KnTest().Kn().Namespace(), "ready"))
|
assert.Check(r.T(), util.ContainsAllIgnoreCase(out.Stdout, "service", serviceName, "no new revision", "namespace", r.KnTest().Kn().Namespace()))
|
||||||
|
|
||||||
out = r.KnTest().Kn().Run("service", "describe", serviceName, "--verbose")
|
out = r.KnTest().Kn().Run("service", "describe", serviceName, "--verbose")
|
||||||
r.AssertNoError(out)
|
r.AssertNoError(out)
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,7 @@ func TestTrafficSplit(t *testing.T) {
|
||||||
serviceCreateWithOptions(r, serviceName, "--revision-name", rev1)
|
serviceCreateWithOptions(r, serviceName, "--revision-name", rev1)
|
||||||
|
|
||||||
// existing state: traffic block having two targets
|
// existing state: traffic block having two targets
|
||||||
test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2")
|
test.ServiceUpdate(r, serviceName, "--env", "TARGET=v2", "--revision-name", serviceName+"-rev-2")
|
||||||
|
|
||||||
// desired state: tag non-@latest revision with two tags and 50-50% traffic each
|
// desired state: tag non-@latest revision with two tags and 50-50% traffic each
|
||||||
test.ServiceUpdate(r, serviceName,
|
test.ServiceUpdate(r, serviceName,
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue