Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add create router version feature #179

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5987cc6
Add create router version endpoint
deadlycoconuts Mar 11, 2022
bcac7db
Edit error message
deadlycoconuts Mar 11, 2022
83e42fa
Update OpenAPI specs and API with new endpoint
deadlycoconuts Mar 11, 2022
c69ecbf
Add tests for CreateRouterVersion
deadlycoconuts Mar 14, 2022
c08c83d
Add UI components for creating router versions without deployment
deadlycoconuts Mar 14, 2022
2c05aff
Refactor UI submit event
deadlycoconuts Mar 14, 2022
6beb97c
Add SDK method to create new router version
deadlycoconuts Mar 15, 2022
551b263
Add tests for create version SDK method
deadlycoconuts Mar 15, 2022
7477a5a
Refactor error handling
deadlycoconuts Mar 15, 2022
09b0482
Rename buttons
deadlycoconuts Mar 15, 2022
1789938
Change button colours to shades of primary colour
deadlycoconuts Mar 15, 2022
b1353ee
Add custom CSS colours
deadlycoconuts Mar 15, 2022
d0430ab
Refactor variables in router view
deadlycoconuts Mar 17, 2022
3fa47bf
Refactor confirmation messages
deadlycoconuts Mar 17, 2022
6716d4e
Update put operation to create router versions to a post operation
deadlycoconuts Mar 21, 2022
abb8932
Add documentation for creating routers with the UI
deadlycoconuts Mar 21, 2022
cabe82e
Add SDK sample to reflect saving of router versions
deadlycoconuts Mar 21, 2022
6f0dd84
Remove redundant words from OpenAPI spec descriptions
deadlycoconuts Mar 21, 2022
c2c79cf
Rename UpdateSummary to RouterUpdateSummary for consistency
deadlycoconuts Mar 21, 2022
d58016d
Rename callback functions for clarity
deadlycoconuts Mar 21, 2022
a94e86e
Refactor VersionComparisonView to receive two onSubmit handlers
deadlycoconuts Mar 21, 2022
ebb1e25
Simplify edit a router sample
deadlycoconuts Mar 21, 2022
39269ce
Refactor create_version to now be a classmethod of RouterVersion
deadlycoconuts Mar 21, 2022
a6a65bb
Refactor CreateRouterVersion endpoint to use RouterVersionConfig
deadlycoconuts Mar 22, 2022
580c9af
Edit UI to use refactored schema for creating router version
deadlycoconuts Mar 22, 2022
5ff58ea
Refactor create_version to now be a classmethod of RouterVersion
deadlycoconuts Mar 22, 2022
ec6aff2
Pin cloudpickle to requirements
deadlycoconuts Mar 22, 2022
9a354fc
Add e2e test for creating router versions
deadlycoconuts Mar 22, 2022
e1d2bd6
Fix e2e test
deadlycoconuts Mar 22, 2022
9fb1c25
Fix e2e test bug
deadlycoconuts Mar 22, 2022
4e2677d
Refactor OpenAPI specs and SDK
deadlycoconuts Mar 22, 2022
24ed856
Simplify router version creation
deadlycoconuts Mar 22, 2022
68f93c9
Refactor CreateOrUpdateRouterRequest
deadlycoconuts Mar 22, 2022
c85444f
Add convenience method to create routers to Router class
deadlycoconuts Mar 22, 2022
4982972
Fix lint comments
deadlycoconuts Mar 22, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
355 changes: 196 additions & 159 deletions api/api/openapi.bundle.yaml

Large diffs are not rendered by default.

123 changes: 80 additions & 43 deletions api/api/specs/routers.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project to retrieve routers from"
description: "id of the project to retrieve routers from"
schema:
<<: *id
required: true
Expand All @@ -45,7 +45,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project to save router"
description: "id of the project to save router"
schema:
<<: *id
required: true
Expand Down Expand Up @@ -74,7 +74,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project to retrieve routers from"
description: "id of the project to retrieve routers from"
schema:
<<: *id
required: true
Expand All @@ -101,7 +101,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project of the router"
description: "id of the project of the router"
schema:
<<: *id
required: true
Expand Down Expand Up @@ -136,7 +136,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project of the router"
description: "id of the project of the router"
schema:
<<: *id
required: true
Expand Down Expand Up @@ -227,7 +227,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project to retrieve routers from"
description: "id of the project to retrieve routers from"
schema:
<<: *id
required: true
Expand All @@ -250,6 +250,40 @@ paths:
description: "Invalid project_id or router_id"
404:
description: "No router versions found"
post:
deadlycoconuts marked this conversation as resolved.
Show resolved Hide resolved
tags: *tags
summary: "Create router version without deploying it"
parameters:
- in: "path"
name: "project_id"
description: "id of the project of the router"
schema:
<<: *id
required: true
- in: "path"
name: "router_id"
description: "id of the router to create a new version for"
schema:
<<: *id
required: true
requestBody:
description: "router configuration to save"
required: true
content:
application/json:
schema:
$ref: "#/components/schemas/RouterVersionConfig"
responses:
200:
description: "OK"
content:
application/json:
schema:
$ref: "#/components/schemas/RouterVersion"
400:
description: "Invalid project_id, router_id or router configuration"
500:
description: "Unable to save configuration"

"/projects/{project_id}/routers/{router_id}/versions/{version}":
get:
Expand All @@ -258,7 +292,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project to retrieve routers from"
description: "id of the project to retrieve routers from"
schema:
<<: *id
required: true
Expand Down Expand Up @@ -292,7 +326,7 @@ paths:
parameters:
- in: "path"
name: "project_id"
description: "project id of the project of the router"
description: "id of the project of the router"
schema:
<<: *id
required: true
Expand Down Expand Up @@ -565,43 +599,46 @@ components:
type: "string"
pattern: '^[a-z0-9-]*$'
config:
$ref: "#/components/schemas/RouterVersionConfig"

RouterVersionConfig:
deadlycoconuts marked this conversation as resolved.
Show resolved Hide resolved
type: "object"
required:
- routes
- default_route_id
- experiment_engine
- timeout
- log_config
properties:
routes:
type: "array"
items:
$ref: "#/components/schemas/Route"
rules:
type: "array"
items:
$ref: "#/components/schemas/TrafficRule"
default_route_id:
type: "string"
experiment_engine:
$ref: "experiment-engines.yaml#/components/schemas/ExperimentConfig"
resource_request:
$ref: "#/components/schemas/ResourceRequest"
timeout:
<<: *timeout
log_config:
type: "object"
required:
- routes
- default_route_id
- experiment_engine
- timeout
- log_config
properties:
routes:
type: "array"
items:
$ref: "#/components/schemas/Route"
rules:
type: "array"
items:
$ref: "#/components/schemas/TrafficRule"
default_route_id:
type: "string"
experiment_engine:
$ref: "experiment-engines.yaml#/components/schemas/ExperimentConfig"
resource_request:
$ref: "#/components/schemas/ResourceRequest"
timeout:
<<: *timeout
log_config:
type: "object"
properties:
result_logger_type:
$ref: "#/components/schemas/ResultLoggerType"
bigquery_config:
$ref: "#/components/schemas/BigQueryConfig"
kafka_config:
$ref: "#/components/schemas/KafkaConfig"
enricher:
$ref: "#/components/schemas/Enricher"
ensembler:
$ref: "#/components/schemas/RouterEnsemblerConfig"
result_logger_type:
$ref: "#/components/schemas/ResultLoggerType"
bigquery_config:
$ref: "#/components/schemas/BigQueryConfig"
kafka_config:
$ref: "#/components/schemas/KafkaConfig"
enricher:
$ref: "#/components/schemas/Enricher"
ensembler:
$ref: "#/components/schemas/RouterEnsemblerConfig"

Route:
type: "object"
Expand Down
1 change: 1 addition & 0 deletions api/e2e/test/00_all_e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ func TestEndToEnd(t *testing.T) {
t.Parallel()
t.Run("CreateRouter_KnativeServices", TestCreateRouter)
t.Run("UpdateRouter_InvalidConfig", TestUpdateRouterInvalidConfig)
t.Run("CreateRouterVersion", TestCreateRouterVersion)
t.Run("UndeployRouter", TestUndeployRouter)
t.Run("DeployRouterVersion_InvalidConfig", TestDeployRouterInvalidConfig)
t.Run("DeployRouter", TestDeployValidConfig)
Expand Down
148 changes: 148 additions & 0 deletions api/e2e/test/03_create_router_version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
//go:build e2e
// +build e2e

package e2e

import (
"bytes"
"context"
"fmt"
"io/ioutil"
"net/http"
"path/filepath"
"testing"

"github.com/tidwall/gjson"

"github.com/gojek/turing/api/turing/models"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

/*
Pre:
testCreateRouter run successfully.
Steps:
Create a router version with a valid router config
b. GET router version 3 > shows status "undeployed"
c. GET router > config still shows version 1
d. Test cluster state that all deployments exist
e. Make a request to the router, validate the response.
*/
func TestCreateRouterVersion(t *testing.T) {
// Read existing router that MUST have already exists from previous create router e2e test
// Router name is assumed to follow this format: e2e-experiment-{{.TestID}}
routerName := "e2e-experiment-" + globalTestContext.TestID
t.Log(fmt.Sprintf("Retrieving router with name '%s' created from previous test step", routerName))
existingRouter, err := getRouterByName(
globalTestContext.httpClient, globalTestContext.APIBasePath, globalTestContext.ProjectID, routerName)
require.NoError(t, err)

// Read router config test data
data := makeRouterPayload(filepath.Join("testdata", "create_router_version.json.tmpl"), globalTestContext)

// Update router
url := fmt.Sprintf(
"%s/projects/%d/routers/%d/versions",
globalTestContext.APIBasePath,
globalTestContext.ProjectID,
existingRouter.ID,
)
t.Log("Creating router version: POST " + url)
req, err := http.NewRequest("POST", url, bytes.NewReader(data))
require.NoError(t, err)
req.Header.Set("Content-Type", "application/json")
resp, err := globalTestContext.httpClient.Do(req)
require.NoError(t, err)
assert.Equal(t, http.StatusOK, resp.StatusCode, readBody(t, resp))

// Get router version 3
t.Log("Testing GET router version")
routerVersion, err := getRouterVersion(
globalTestContext.httpClient,
globalTestContext.APIBasePath,
globalTestContext.ProjectID,
int(existingRouter.ID),
3,
)
require.NoError(t, err)
assert.Equal(t, models.RouterVersionStatusUndeployed, routerVersion.Status)

t.Log("Ensure existing router did not update the version to the new version i.e. the version still unchanged at 1")
router, err := getRouter(
globalTestContext.httpClient,
globalTestContext.APIBasePath,
globalTestContext.ProjectID,
int(existingRouter.ID),
)
require.NoError(t, err)
require.NotNil(t, router.CurrRouterVersion)
assert.Equal(t, 1, int(router.CurrRouterVersion.Version))

downstream, err := getRouterDownstream(globalTestContext.clusterClients,
globalTestContext.ProjectName,
fmt.Sprintf("%s-turing-router", router.Name))
assert.NoError(t, err)
assert.Equal(t, downstream, fmt.Sprintf("%s-turing-router-%d.%s.%s",
router.Name, 1, globalTestContext.ProjectName, globalTestContext.KServiceDomain))

// Check that previous enricher, router, ensembler deployments exist
t.Log("Checking cluster state")
assert.True(t, isDeploymentExists(
globalTestContext.clusterClients,
globalTestContext.ProjectName,
fmt.Sprintf("%s-turing-router-%d-0-deployment", router.Name, 1)))
assert.True(t, isDeploymentExists(
globalTestContext.clusterClients,
globalTestContext.ProjectName,
fmt.Sprintf("%s-turing-enricher-%d-0-deployment", router.Name, 1)))
assert.True(t, isDeploymentExists(
globalTestContext.clusterClients,
globalTestContext.ProjectName,
fmt.Sprintf("%s-turing-ensembler-%d-0-deployment", router.Name, 1)))

// Make request to router
t.Log("Testing router endpoint")
router, err = getRouter(
globalTestContext.httpClient,
globalTestContext.APIBasePath,
globalTestContext.ProjectID,
int(router.ID),
)
require.NoError(t, err)
assert.Equal(t,
fmt.Sprintf(
"http://%s-turing-router.%s.%s/v1/predict",
router.Name,
globalTestContext.ProjectName,
globalTestContext.KServiceDomain,
),
router.Endpoint,
)
req, err = http.NewRequestWithContext(
context.Background(),
http.MethodPost,
router.Endpoint,
ioutil.NopCloser(bytes.NewReader([]byte(`{}`))),
)
require.NoError(t, err)
resp, err = globalTestContext.httpClient.Do(req)
require.NoError(t, err)
responseBytes, err := ioutil.ReadAll(resp.Body)
defer resp.Body.Close()
require.NoError(t, err)
actualResponse := gjson.GetBytes(responseBytes, "json.response").String()
expectedResponse := `{
"experiment": {},
"route_responses": [
{
"data": {
"version": "control"
},
"is_default": true,
"route": "control"
}
]
}`
assert.JSONEq(t, expectedResponse, actualResponse)
}
Loading