Skip to content

Commit

Permalink
feature(service): Implements traffic splitting and tagging targets
Browse files Browse the repository at this point in the history
 - Add e2e tests
 - Use '=' for traffic and tag assignment instead of ':'
 - Use --tag and --untag flags for tagging traffic targets
 - Use --traffic flag for setting traffic portions
 - Allow --traffic portion to either take revisionName or tagName
 - Uses @latest identifier for referencing latest revision of service
 - Dont throw error if requested revision=tag pair is same
 - Support having multiple tags for a revision
	 - creates a new target in traffic block if revision present in traffic block with new tag requested
	 - creates N new targets in traffic block if revision absent in traffic block with Nxnew tags requested
 - Ensure updating tag of @latest requires --untag flag
	 - streamline updating tag for latestReadyRevision
	 - adds respective tests
	 - adds tests for ensuring given traffic sum to 100 on CLI and fail fast
 - Add note about preference of order in case where tagOfOneRevision == revisionOfAnother,
   first tags are checked and assigned traffic if any, as tags are supposed to be
   unique in traffic block and should be referenced in such scenario.
 - Remove the examples from flag description, moves it to service update command example section
 - Pass only traffic block to compute trffic, makes it better to consume.
 - Cover more error cases for invalid value format for assignments, covers a=b=c, a=, =b, or variants of them
 - Separate and improves the error messages
 - Add unit tests for traffic computing
 - Add sanity checks in dedicated function verifyInputSanity
 	  - traffic perents should sum to 100
          - individual percent should be in 0-100
          - repetition of @latest or tagName or revisionRef is disallowed
 - Verify traffic percents sum to 100 on client side and fail fast
 - Add e2e tests for traffic splitting
	 - create and update service, assign tags and set traffic to make an existing state
	 - run the scenario on existing state of service
	 - form the desired state traffic block
	 - extract the traffic block and form the traffic block struct actual state
	 - assert.DeepEqual actual and desired traffic blocks
 - Use logic to generate service name in the same way as namespace, use different service name per test case
 - Run e2e test for traffic splitting in parallel
 - Use timeout duration of 30m for e2e tests, use timeout parameter for go_test_e2e library function
 - Use tagName in flag description of --untag, avoiding conflict with --tag flag
 - Update CHANGELOG
  • Loading branch information
navidshaikh committed Aug 15, 2019
1 parent c4e8d5a commit e7b4d8b
Show file tree
Hide file tree
Showing 11 changed files with 1,173 additions and 17 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,11 @@
| Add --revision-name flag
| https://github.com/knative/client/pull/282[#282]

| 🎁
| Support traffic splitting and tagging targets
| https://github.com/knative/client/pull/345[#345]


|===

## v0.2.0 (2019-07-10)
Expand Down
26 changes: 20 additions & 6 deletions docs/cmd/kn_service_update.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,25 @@ kn service update NAME [flags]

```
# Updates a service 'mysvc' with new environment variables
kn service update mysvc --env KEY1=VALUE1 --env KEY2=VALUE2
# Updates a service 'svc' with new environment variables
kn service update svc --env KEY1=VALUE1 --env KEY2=VALUE2
# Update a service 'mysvc' with new port
kn service update mysvc --port 80
# Update a service 'svc' with new port
kn service update svc --port 80
# Updates a service 'mysvc' with new requests and limits parameters
kn service update mysvc --requests-cpu 500m --limits-memory 1024Mi
# Updates a service 'svc' with new requests and limits parameters
kn service update svc --requests-cpu 500m --limits-memory 1024Mi
# Assign tag 'latest' and 'stable' to revisions 'echo-v2' and 'echo-v1' respectively
kn service update svc --tag echo-v2=latest --tag echo-v1=stable
OR
kn service update svc --tag echo-v2=latest,echo-v1=stable
# Update tag from 'testing' to 'staging' for latest ready revision of service
kn service update svc --untag testing --tag @latest=staging
# Add tag 'test' to echo-v3 revision with 10% traffic and rest to latest ready revision of service
kn service update svc --tag echo-v3=test --traffic test=10,@latest=90
```

### Options
Expand All @@ -43,6 +54,9 @@ kn service update NAME [flags]
--requests-cpu string The requested CPU (e.g., 250m).
--requests-memory string The requested memory (e.g., 64Mi).
--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}}")
--tag strings Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. This flag can be specified multiple times.
--traffic strings Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.
--untag strings Untag revision (format: --untag tagName). This flag can be spcified multiple times.
--wait-timeout int Seconds to wait before giving up on waiting for service to be ready. (default 60)
```

Expand Down
56 changes: 56 additions & 0 deletions pkg/kn/commands/flags/traffic.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// Copyright © 2019 The Knative Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package flags

import (
"github.com/spf13/cobra"
)

type Traffic struct {
RevisionsPercentages []string
RevisionsTags []string
UntagRevisions []string
}

func (t *Traffic) Add(cmd *cobra.Command) {
cmd.Flags().StringSliceVar(&t.RevisionsPercentages,
"traffic",
nil,
"Set traffic distribution (format: --traffic revisionRef=percent) where revisionRef can be a revision or a tag or '@latest' string "+
"representing latest ready revision. This flag can be given multiple times with percent summing up to 100%.")

cmd.Flags().StringSliceVar(&t.RevisionsTags,
"tag",
nil,
"Set tag (format: --tag revisionRef=tagName) where revisionRef can be a revision or '@latest' string representing latest ready revision. "+
"This flag can be specified multiple times.")

cmd.Flags().StringSliceVar(&t.UntagRevisions,
"untag",
nil,
"Untag revision (format: --untag tagName). This flag can be spcified multiple times.")
}

func (t *Traffic) PercentagesChanged(cmd *cobra.Command) bool {
return cmd.Flags().Changed("traffic")
}

func (t *Traffic) TagsChanged(cmd *cobra.Command) bool {
return cmd.Flags().Changed("tag") || cmd.Flags().Changed("untag")
}

func (t *Traffic) Changed(cmd *cobra.Command) bool {
return t.PercentagesChanged(cmd) || t.TagsChanged(cmd)
}
37 changes: 30 additions & 7 deletions pkg/kn/commands/service/service_update.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import (
"errors"
"fmt"

"github.com/knative/client/pkg/kn/commands/flags"
"github.com/knative/client/pkg/kn/traffic"
"github.com/spf13/cobra"
api_errors "k8s.io/apimachinery/pkg/api/errors"

Expand All @@ -27,19 +29,30 @@ import (
func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
var editFlags ConfigurationEditFlags
var waitFlags commands.WaitFlags

var trafficFlags flags.Traffic
serviceUpdateCommand := &cobra.Command{
Use: "update NAME [flags]",
Short: "Update a service.",
Example: `
# Updates a service 'mysvc' with new environment variables
kn service update mysvc --env KEY1=VALUE1 --env KEY2=VALUE2
# Updates a service 'svc' with new environment variables
kn service update svc --env KEY1=VALUE1 --env KEY2=VALUE2
# Update a service 'svc' with new port
kn service update svc --port 80
# Updates a service 'svc' with new requests and limits parameters
kn service update svc --requests-cpu 500m --limits-memory 1024Mi
# Update a service 'mysvc' with new port
kn service update mysvc --port 80
# Assign tag 'latest' and 'stable' to revisions 'echo-v2' and 'echo-v1' respectively
kn service update svc --tag echo-v2=latest --tag echo-v1=stable
OR
kn service update svc --tag echo-v2=latest,echo-v1=stable
# Updates a service 'mysvc' with new requests and limits parameters
kn service update mysvc --requests-cpu 500m --limits-memory 1024Mi`,
# Update tag from 'testing' to 'staging' for latest ready revision of service
kn service update svc --untag testing --tag @latest=staging
# Add tag 'test' to echo-v3 revision with 10% traffic and rest to latest ready revision of service
kn service update svc --tag echo-v3=test --traffic test=10,@latest=90`,
RunE: func(cmd *cobra.Command, args []string) (err error) {
if len(args) != 1 {
return errors.New("requires the service name.")
Expand Down Expand Up @@ -69,6 +82,15 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
return err
}

if trafficFlags.Changed(cmd) {
traffic, err := traffic.Compute(cmd, service.Spec.Traffic, &trafficFlags)
if err != nil {
return err
}

service.Spec.Traffic = traffic
}

err = client.UpdateService(service)
if err != nil {
// Retry to update when a resource version conflict exists
Expand Down Expand Up @@ -99,6 +121,7 @@ func NewServiceUpdateCommand(p *commands.KnParams) *cobra.Command {
commands.AddNamespaceFlags(serviceUpdateCommand.Flags(), false)
editFlags.AddUpdateFlags(serviceUpdateCommand)
waitFlags.AddConditionWaitFlags(serviceUpdateCommand, 60, "Update", "service")
trafficFlags.Add(serviceUpdateCommand)
return serviceUpdateCommand
}

Expand Down
Loading

0 comments on commit e7b4d8b

Please sign in to comment.