CCCTC Docs

CCCTC Docs

  • Help

Service Router

Copyright (c) 2019. California Community Colleges Technology Center
Licensed under the MIT license.
A copy of this license may be found at https://opensource.org/licenses/mit-license.php

The service-router module is part of the API Gateway

The service-router uses Zuul to expose public endpoints as a RESTful API. It proxies or routes public side requests to back end services, such as CCCApply, AWS S3 synchronization, and Canvas data.

API Gateway

The router secures access to all services using OAuth 2.0 (see below for configuration).

Configuration

Spring cloud-config is used to connect remote property files stored in the git repo Service Router Config to configure the running instance.

See cloud-config and the associated bootstrap-* files.

Running service-router

Typically you'll run all three components of the API-Gateway stack locally: service-router, service-conductor and service-workers.

Instructions and pre-requisites for running these services together can be found in the overall API Gateway documentation here: development-environment

Running the Local stack in 'mixed-mode'

The service-router and service-workers can be run in either an IDE or in Docker.

The table below shows the run options supported by default:

Supported by Default?DockerIDE
Yesservice-workers and service-router
Yesservice-workers and service-router
Yesservice-routerservice-workers
No (local override config required)*service-workersservice-router

*The service-workers poll Conductor via the service-router. In a Docker container, the service-workers connect to the service-router via 'http://service-router...' When the service-router is in the IDE, the workers would have to access it via localhost. To work around this, add the configuration below to your 'application_local.yml' file:

  # Conductor URL to poll for work tasks
  conductor:
  # URL to access Conductor (via localhost) when router isn't on Docker network (i.e., running in IDE)
  apiURL: "http://192.168.1.64:10000/conductor/secure/"

Use your machine's IP instead (localhost will not work from within a Docker container).

IntelliJ

The IntelliJ Run Configuration can be configured as:

Main class: org.ccctech.apigateway.servicerouter.ServiceRouterApplication
VM options: -Dspring.profiles.active=dev,_local -Djasypt.encryptor.password=unlockMe -DJASYPT_PASSWORD=unlockMe -DENCRYPT_KEY=unlockMe

Using the "local" profile

Notice above that the profiles specified are "dev,local". The dev profile is defined in cloud config with defaults applicable to local development. The local profile is not in cloud config. Instead, it can be created locally and used to change default values and test out new configurations without having to make changes to cloud config. This is completely optional.

To use: Create a file called application-local.yml in src/main/resources.

Pulling and Running service-router Locally Using the CCCTC Private Registry and Docker

Use the instructions below to run and build service-router using the CCCTC private registry.

Prerequisite: Follow the instructions on adding your user / pass to the registry here to set your credentials for pulling from the CCCTC private registry.

  1. To allow multiple services to communicate with each other, they must all join the same Docker network. Ensure the 'ccctc' network is created locally by running:

    docker network create ccctc
    
  2. Use the following command if you have NOT built the images locally but want to pull already-built images:

    export DOCKER_REGISTRY=registry.ccctechcenter.org/
    
  3. Login to the CCCTC Docker registry using the following command:

    docker login registry.ccctechcenter.org:5000
    

    Note: The docker-compose.yml file uses the following environment variable:

    VariableDescription
    DOCKER_REGISTRYURL to remote private registry, OR "" for local.
  4. Use the following command in the root directory to run service-router locally using the CCCTC base image:

    ./build.sh local restart
    
  5. Start the Docker container from the service-router module root directory with:

    docker-compose up
    
  6. After running the above docker-compose command, you can CTRL-C to stop the service-conductor processes. To ensure proper cleanup, follow that with:

    docker-compose down
    

Running service-workers From a Local Image

Use the following steps after running the CCCTC Docker registry image to switch to a local environment image in order to make changes to the code locally.

  1. Switch to your local environment by unsetting the DOCKER_REGISTRY with:

    unset DOCKER_REGISTRY
    
  2. Recompile and rebuild the Docker image (necessary before starting the container) with Maven:

     mvn clean install
    
  3. Start the Docker container:

       docker-compose up
    
  4. With the above docker-compose command, you can CTRL-C to stop the processes. To ensure proper cleanup, follow that with:

      docker-compose down
    

OAuth 2.0

Services are secured using OAuth 2.0, using Keycloak.

Get Oauth Token - Curl / Bash

# set variables
CLIENT_ID="gateway-client-tester" 
SECRET="2b6c3a6c-364f-4504-a9ee-e461ce27d79e"
OAUTHURL="http://localhost:10000"

# get access token 
ACCESS_TOKEN=$(curl -X POST -d "client_id=$CLIENT_ID&client_secret=$SECRET&grant_type=client_credentials" $OAUTHURL/token/v1/token | jq -r '.access_token')    

Get Oauth Token - Postman

POST to http://localhost:10000/token/v1/token using the credentials above, passing the following in the body as x-www-form-urlencoded key/value pairs:

  • client_id = gateway-client-tester
  • client_secret = 2b6c3a6c-364f-4504-a9ee-e461ce27d79e
  • grant_type = client_credentials

Testing

Listed below are the endpoints exposed that will route requests to the workflow engine (service-conductor) and then the back-end service implementation (service-workers -> microservice).

The above OAuth configurations have been tested using the following curl commands:

NOTE: Ensure the property conductor.apiURL points to the service-conductor server URL. Running in IntelliJ with the above -Dspring.profiles.active=dev,local will set a working default.

Postman

Postman tests are checked into the api-gateway git repo. During the build process of any API-Gateway component, Jenkins utilizes these to test the deployment.

You can run those tests locally from the command line with:

# define local machine IP in var
export localip=$(ifconfig | grep "inet " | grep -Fv 127.0.0.1 | awk '{print $2}')

# run test image, resolving local ip
docker run --rm --add-host="localip:$localip" -t registry.ccctechcenter.org:5000/ccctechcenter/api-gateway-test

The above command maps your local IP to "my-dev-host", which is the hostname used in the local environment.

Canvas Data Warehouse

zuul:
  routes:
    canvasDW:
      path: /canvasDW/*/dataSync
curl -s -H "Content-Type: application/json" \
    -H "Authorization: bearer $ACCESS_TOKEN" \
    -X GET "$ROUTER/canvasDW/001/dataSync/" | python -m json.tool

This endpoint will start the following sequence of actions:

  1. The service-router starts a new workflow in service-conductor.
  2. An 'intake' service-worker polls service-conductor for an appropriate workflow denoting work to be processed.
  3. The service-worker calls the configured service and passes it the inbound payload from the client.
  4. The microservice processes the request and returns its response.
  5. The service-worker gets the reply from the service and sets its output to an attribute on the workflow.
  6. The service-router polls Conductor in a loop for the workflow completion.
  7. Upon completion, the service-router sends the workflow output to the API Gateway client that initiated the call.

College Adaptor

zuul:
  routes:
    college-adaptor:
      path: /adaptor/**
curl -s -H "Content-Type: application/json" \
    -H "Authorization: bearer $ACCESS_TOKEN" \
    -X GET "$ROUTER/adaptor/001/terms?mis=001" | python -m json.tool

or

curl -s -H "Content-Type: application/json" \
    -H "Authorization: bearer $ACCESS_TOKEN" \
    -X GET "$ROUTER/adaptor/001/sections?sisTermId=2017FA&sisCourseId=ENGL-100&mis=001" | python -m json.tool

This endpoint will start the following sequence of actions:

  1. The service-router starts a new workflow in service-conductor.
  2. An 'intake' service-worker polls service-conductor for an appropriate workflow denoting work to be processed.
  3. The service-worker calls the configured service and passes it the inbound payload from the client.
  4. The adaptor behaves exactly as it does now in production (except with OAuth turned off).
  5. The service-worker gets the reply from the adaptor and sets its output to an attribute on the workflow.
  6. The service-router polls Conductor in a loop for the workflow completion.
  7. Upon completion, the service-router sends the workflow output to the API Gateway client that initiated the call.

Movies Dummy Service

This simple service was used in prototyping Zuul and various aspects of service-conductor exception handling. It's for the prototype phase only.

zuul:
  routes:
    movies:
      path: /movies/**
curl -s -H "Content-Type: application/json" \
    -H "Authorization: bearer $ACCESS_TOKEN" \
    -X GET "$ROUTER/movies/ghostbusters" | python -m json.tool

This endpoint will start the following sequence of actions:

  1. The service-router starts a new workflow in service-conductor.
  2. An 'intake' service-worker polls service-conductor for an appropriate workflow denoting work to be processed.
  3. The service-worker calls the configured service and passes it the inbound payload from the client.
  4. The microservice processes the request and returns its response.
  5. The service-worker gets the reply from the service and sets its output to an attribute on the workflow.
  6. The service-router polls Conductor in a loop for the workflow completion.
  7. Upon completion, the service-router sends the workflow output to the API Gateway client that initiated the call.

AWS Deployment:

  • service-router - primary service. This will automatically deploy to the appropriate environment, on any code push
  • router-rancher-lb - provides internal load balancing for service-router, within the rancher network. Must be deployed manually for a new environment. Choose "build with parameters" on a Jenkins job for this service, and select "deploy_rancher_lb"

Resources

Netflix's Edge Gateway Using Zuul : https://www.infoq.com/presentations/netflix-gateway-zuul

Zuul 2 : The Netflix Journey to Asynchronous, Non-Blocking Systems : https://medium.com/netflix-techblog/zuul-2-the-netflix-journey-to-asynchronous-non-blocking-systems-45947377fb5c

Limitations

see wiki

Sentry IO

Sentry IO is error tracking software that has been integrated in the project. The integration relies on the existence of an environment variable SENTRY_DSN (the data source name). The data source name is a URL that provides endpoint information to the sentry IO subsystem. When the environment variable is not present, the Sentry IO subsystem is completely disabled.

  • Configuration
  • Running service-router
    • Running the Local stack in 'mixed-mode'
    • IntelliJ
    • Pulling and Running service-router Locally Using the CCCTC Private Registry and Docker
  • OAuth 2.0
  • Testing
    • Postman
  • AWS Deployment:
  • Resources
  • Limitations
  • Sentry IO