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 SDK functionality #152

Merged
merged 85 commits into from
Jan 17, 2022

Conversation

deadlycoconuts
Copy link
Contributor

@deadlycoconuts deadlycoconuts commented Jan 12, 2022

Context:

Currently the Turing SDK only supports batch experiments by covering only operations related to ensemblers and ensembling jobs, and we are now expanding its scope to cover online experiments by extending the SDK to cover operations involving other Turing components. Previously we've already implemented the SDK to supporting the listing of routers in PR #148, and this PR includes additional functionalities involving the setting up of routers.

Features:

This PR involves implementing a functionality corresponding to one of the API endpoints involving routers, i.e. creating a new router given a router configuration.

  • New SDK classes have been created for users to interact with (Route, TrafficRuleCondition, TrafficRule, LogConfig, ResourceRequest, Enricher, RouterEnsemblerConfig, etc.) and to build their own RouterConfig instance incrementally using these components

Example:

router_config = RouterConfig(
        environment_name="id-dev",
        name="router-1",
        routes=[
            Route(
                id="model-a",
                endpoint="http://predict-this.io/model-a",
                timeout="100ms"
            ),
            Route(
                id="model-b",
                endpoint="http://predict-this.io/model-b",
                timeout="100ms"
            )
        ],
        rules=None,
        default_route_id="test",
        experiment_engine=ExperimentConfig(
            type="nop",
            config={
                'variables':
                        [
                            {'name': 'order_id', 'field': 'fdsv', 'field_source': 'header'},
                            {'name': 'country_code', 'field': 'dcsd', 'field_source': 'header'},
                            {'name': 'latitude', 'field': 'd', 'field_source': 'header'},
                            {'name': 'longitude', 'field': 'sdSDa', 'field_source': 'header'}
                        ],
                'project_id': 102
            }
        ),
        resource_request=ResourceRequest(
            min_replica=0,
            max_replica=2,
            cpu_request="500m",
            memory_request="512Mi"
        ),
        timeout="100ms",
        log_config=LogConfig(
            result_logger_type=ResultLoggerType.NOP,
            table="abc.dataset.table",
            service_account_secret="not-a-secret"
        ),
        enricher=Enricher(
            image="asia.test.io/model-dev/echo:1.0.2",
            resource_request=ResourceRequest(
                min_replica=0,
                max_replica=2,
                cpu_request="500m",
                memory_request="512Mi"
            ),
            endpoint="/",
            timeout="60ms",
            port=8080,
            env=[
                EnvVar(
                    name="test",
                    value="abc"
                )
            ]
        ),
        ensembler=DockerRouterEnsemblerConfig(
            id=1,
            image="asia.test.io/gods-test/turing-ensembler:0.0.0-build.0",
            resource_request=ResourceRequest(
                min_replica=1,
                max_replica=3,
                cpu_request="500m",
                memory_request="512Mi"
            ),
            endpoint=f"http://localhost:5000/ensembler_endpoint",
            timeout="500ms",
            port=5120,
            env=[],
        )
    )
  • The SDK classes also double as objects that automatically get created (as properties of Router instances) when users receive responses from the Turing API containing Router information

Example:

# retrieving a list of routers using the SDK method list() from PR #148 
routers = turing.Router.list()

# get an instance of one of the Router objects returned
my_router = routers[0]

# access attributes of Router instances (such as RouterConfig and Route) and manipulate them directly
my_router.config.routes[0].timeout = "50ms"
  • These SDK components returned can then be retrieved and reused as individual components for other RouterConfig configurations
  • Tests involving all the newly created components

Modifications

  • sdk/turing/router/* - new Python files containing the new SDK classes for router components
  • sdk/turing/router/router.py - addition of a new Router.create method to create a new Turing router with a given router configuration
  • sdk/turing/router/session.py - addition of a new create_router method used by Router.create to call the API method associated with creating a new Turing router
  • api/api/specs/* - addition of regex expressions that will be enforced by API classes generated by OpenAPI Generator; acts as a central source of truth for validating user input
  • sdk/turing/generated/model/* - autogenerated API classes changed by the OpenAPI generator given the changes made to the OpenAPI specs

def config(self, config):
if config is not None and 'project_id' in config:
config['project_id'] = int(config['project_id'])
self._config = config
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This project_id check is a little awkward; it's there because when project_id gets returned as a response within the config attribute, its value gets parsed as a float by the autogenerated API classes, which when sent back as part of a request, receives a 400 Bad Request message since the API expects an int for the project_id variable.

Copy link
Collaborator

@terryyylim terryyylim left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the extensive test suites @deadlycoconuts , left a few comments for your consideration!

sdk/tests/conftest.py Outdated Show resolved Hide resolved
sdk/turing/router/config/log_config.py Show resolved Hide resolved
sdk/turing/router/config/resource_request.py Show resolved Hide resolved
@deadlycoconuts deadlycoconuts changed the base branch from main to fix_lint January 14, 2022 05:04
@deadlycoconuts deadlycoconuts changed the base branch from fix_lint to main January 14, 2022 05:05
@@ -29,6 +29,7 @@ components:
properties:
name:
type: "string"
pattern: '^[a-zA-Z0-9_]*$'
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The regex expressions look slightly different from those of the UI as the case insensitive flag i doesn't seem to work with OpenAPI generator. As a workaround, I enumerated the different letter cases (i.e. added A-Z) in each of the expressions where the case insensitive flag was used.

@deadlycoconuts deadlycoconuts changed the title Add create router sdk Add create router sdk method Jan 14, 2022
@deadlycoconuts deadlycoconuts changed the title Add create router sdk method Add create router SDK method Jan 14, 2022
@deadlycoconuts deadlycoconuts changed the title Add create router SDK method Add create router SDK functionality Jan 14, 2022
@deadlycoconuts deadlycoconuts changed the base branch from main to fix_lint January 17, 2022 03:10
@deadlycoconuts deadlycoconuts changed the base branch from fix_lint to main January 17, 2022 03:10
Copy link
Contributor

@romanwozniak romanwozniak left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is great, thanks @deadlycoconuts. Could you please also include samples on how to use this SDK under https://github.com/gojek/turing/tree/main/sdk/samples?

@deadlycoconuts
Copy link
Contributor Author

This is great, thanks @deadlycoconuts. Could you please also include samples on how to use this SDK under https://github.com/gojek/turing/tree/main/sdk/samples?

Alright sure, I'll add them in in the next PR :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants