From 648d1ee34596ac390b945f15ce6fd4498cccf3be Mon Sep 17 00:00:00 2001 From: Andy Leap <104936100+andrewleap-optimizely@users.noreply.github.com> Date: Mon, 13 Mar 2023 18:19:49 -0400 Subject: [PATCH] [FSSDK-8958] chore: prepare 3.0.1 branch for release (#372) * Fix: Passing docker variables and fixed tag format check. (#363) removing travis and fixing git actions. * change Full Stack to Feature Experimentation (#368) (#369) Co-authored-by: Griffin Cox <104227910+griffincox-optimizely@users.noreply.github.com> * [FSSDK-8958] fix: change build status to actions (#370) * Update README.md * change name of git action * prep for 3.0.1 release (#371) --------- Co-authored-by: Muhammad Noman Co-authored-by: Griffin Cox <104227910+griffincox-optimizely@users.noreply.github.com> --- .github/workflows/agent.yml | 16 +- .travis.yml | 323 ------------------ CHANGELOG.md | 16 +- README.md | 296 +++++++++------- api/openapi-spec/openapi.yaml | 6 +- .../010 - optimizely-agent.md | 48 ++- .../012 - quickstart-for-agent.md | 16 +- .../020 - setup-optimizely-agent.md | 19 +- .../010 - evaluate-rest-apis.md | 12 +- .../020 - admin-api.md | 22 +- .../030 - use-optimizely-agent/index.md | 45 ++- .../010 - authorization.md | 56 +-- .../020 - webhooks-agent.md | 13 +- .../031 - agent-notifications.md | 9 +- .../040 - advanced-configuration.md | 4 +- .../050 - agent-plugins.md | 7 +- .../040 - configure-optimizely-agent/index.md | 78 ++--- .../010 - optimizely-agent.md | 48 ++- .../012 - quickstart-for-agent.md | 18 +- .../020 - setup-optimizely-agent.md | 19 +- .../010 - evaluate-rest-apis.md | 15 +- .../020 - admin-api.md | 22 +- .../030 - use-optimizely-agent/index.md | 34 +- .../010 - authorization.md | 56 +-- .../020 - webhooks-agent.md | 13 +- .../031 - agent-notifications.md | 9 +- .../040 - advanced-configuration.md | 4 +- .../050 - agent-plugins.md | 7 +- .../040 - configure-optimizely-agent/index.md | 78 ++--- docs/readme.md | 33 +- examples/README.md | 21 +- tests/acceptance/README.md | 11 +- 32 files changed, 591 insertions(+), 783 deletions(-) delete mode 100644 .travis.yml diff --git a/.github/workflows/agent.yml b/.github/workflows/agent.yml index 1b954c8c..cba2146a 100644 --- a/.github/workflows/agent.yml +++ b/.github/workflows/agent.yml @@ -1,11 +1,10 @@ -name: Agent CI +name: build on: push: branches: [ master ] tags: - # Making sure this doesn't trigger when tags are pushed - - 'v[0-9]+.[0-9]+.[0-9]+.[0-9]+.[0-9]+.[0-9]' + - 'v*.*.*' pull_request: branches: [ master ] @@ -184,13 +183,18 @@ jobs: echo "$HOME/bin:$HOME/travisci-tools/release_github" >> $GITHUB_PATH - name: run script env: + HOME: 'home/runner' + GITHUB_TOKEN: ${{ secrets.CI_USER_TOKEN }} TRAVIS_OS_NAME: 'linux' + DOCKERHUB_PASS: ${{ secrets.DOCKERHUB_PASS }} + DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} run: | make -e setup build # now we're going to create packages & upload packages ./scripts/ci_create_packages.sh && ./scripts/ci_upload_packages.sh # create the github release (draft) - release_github_v2.sh "$APP_VERSION" + cp $HOME/travisci-tools/release_github/release_github_v2.sh . + ./release_github_v2.sh "$APP_VERSION" # attach generate_secret to the github release ./scripts/ci_build_generate_secret.sh && ./scripts/ci_attach_generate_secret.sh @@ -230,6 +234,7 @@ jobs: - name: set the env run: echo "APP_VERSION=${{ steps.get_version.outputs.VERSION }}" >> $GITHUB_ENV - name: Upload and publish draft + shell: bash env: HOME: 'home/runner' run: | @@ -239,7 +244,10 @@ jobs: - name: run script env: TRAVIS_OS_NAME: ${{ matrix.os_name }} + DOCKERHUB_PASS: ${{ secrets.DOCKERHUB_PASS }} + DOCKERHUB_USER: ${{ secrets.DOCKERHUB_USER }} id: script + shell: bash run: | hub release download $(git describe --abbrev=0 --tags) -i '*-${{ matrix.TARGET }}-*' tar xvfz generate_secret-${{ matrix.TARGET }}-${APP_VERSION}.tar.gz -C /tmp diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 4545bd51..00000000 --- a/.travis.yml +++ /dev/null @@ -1,323 +0,0 @@ -os: linux -dist: xenial -language: shell - -env: - global: - # GO VERSION is set here with GIMME_GO_VERSION see: https://github.com/travis-ci/gimme - # may also want to run `go mod edit -go=1.20` to fix go.mod as well - - GIMME_GO_VERSION=1.20 GIMME_OS=linux GIMME_ARCH=amd64 - -branches: - only: - - master - # https://docs.travis-ci.com/user/customizing-the-build/#safelisting-or-blocklisting-branches - - /^v\d+\.\d+(\.\d+)?(-\S*)?$/ - -stages: - - 'Fmt' - - 'Tests' - - 'Trigger FSC Tests' - - 'Test Build using latest tag (no upload)' - - 'Build, Upload and Publish (draft)' - - 'Test github release assets' - - 'Publish (real)' - - 'Readme-sync-preview' - - 'Readme-sync' - -jobs: - - include: - - - stage: Fmt - script: - - test -z "$(go fmt ./pkg/...)" - - stage: Tests - name: hadolint - os: linux - dist: xenial - script: - - make -e lint - - for f in `find scripts/dockerfiles -type f`; do echo $f; docker run --rm -i hadolint/hadolint:v2.1.0 < $f; done - - - stage: Tests - name: coveralls - os: linux - dist: xenial - script: - - make -e cover COVER_FILE=coverage.txt - after_success: - - go get github.com/mattn/goveralls - - $GOPATH/bin/goveralls -coverprofile=coverage.txt -service=travis-ci - - - stage: Tests - name: sourceclear - os: linux - dist: xenial - addons: - srcclr: true - script: - - go get -v -d ./... - - - stage: Tests - name: windows build.ps1 test - os: windows - language: shell - before_script: skip - script: - - PowerShell -Command Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser - - PowerShell -File "scripts\build.ps1" noninteractive - - PowerShell -File "scripts\check_exe.ps1" - after_success: - - ( [ ${TRAVIS_EVENT_TYPE} = "push" ] && [ ! -z ${TRAVIS_TAG} ] ) && scripts/upload_artifacts.sh - - - stage: Tests - name: acceptance - os: linux - dist: xenial - language: python - python: "3.9" - install: - - pip install -r tests/acceptance/requirements.txt - script: - - MYHOST="http://localhost:8080" make test-acceptance - - - stage: 'Trigger FSC Tests' - if: (branch = master AND type = push) OR type = pull_request OR tag IS present - env: - SDK=agent - SDK_BRANCH=$(if [ -z "$TRAVIS_PULL_REQUEST_BRANCH" ]; then echo ${TRAVIS_BRANCH}; else echo "$TRAVIS_PULL_REQUEST_BRANCH"; fi) - EVENT_TYPE=$TRAVIS_EVENT_TYPE - PULL_REQUEST_SLUG=$TRAVIS_PULL_REQUEST_SLUG - PULL_REQUEST_SHA=$TRAVIS_PULL_REQUEST_SHA - GITHUB_REPOSITORY=$TRAVIS_REPO_SLUG - UPSTREAM_REPO=$TRAVIS_REPO_SLUG - UPSTREAM_SHA=$TRAVIS_COMMIT - PULL_REQUEST_NUMBER=$TRAVIS_PULL_REQUEST - TOKEN=$GITHUB_TOKEN - cache: false - before_install: - ./scripts/pull_travis_ci_tools.sh - install: skip - script: - - "$HOME/travisci-tools/trigger-script-with-status-update.sh" - - - stage: 'Test Build using latest tag (no upload)' - name: linux - os: linux - dist: xenial - script: - - export APP_VERSION=$(git describe --abbrev=0 --tags | tr -d '^v') - - $TRAVIS_BUILD_DIR/scripts/ci_create_packages.sh - - $TRAVIS_BUILD_DIR/scripts/ci_build_generate_secret.sh - - - stage: 'Build, Upload and Publish (draft)' - if: type = push AND tag IS present AND tag =~ /^v[0-9]+\.[0-9]+\.[0-9]+(\-beta)?[0-9]*$/ - name: linux - os: linux - dist: xenial - - # The version of the app is set via git tag (below). This is picked up in the Makefile and compiled into the binary via LDFLAGS. - # It is also picked up in scripts/Makefile.ci to be used in the package name when they are built. - - env: APP_VERSION=${TRAVIS_TAG#v} - - before_install: - - ./scripts/pull_travis_ci_tools.sh - install: - # installs hub to ~/bin - - $HOME/travisci-tools/release_github/install_hub.sh - - export PATH=$HOME/bin:$HOME/travisci-tools/release_github:$PATH - - script: - # now we're going to create packages & upload packages - - $TRAVIS_BUILD_DIR/scripts/ci_create_packages.sh && $TRAVIS_BUILD_DIR/scripts/ci_upload_packages.sh - # create the github release (draft) - - release_github_v2.sh "$TRAVIS_TAG" - # attach generate_secret to the github release - - $TRAVIS_BUILD_DIR/scripts/ci_build_generate_secret.sh && $TRAVIS_BUILD_DIR/scripts/ci_attach_generate_secret.sh - - - stage: 'Test github release assets' - if: type = push AND tag IS present AND tag =~ /^v[0-9]+\.[0-9]+\.[0-9]+(\-beta)?[0-9]*$/ - name: linux - os: linux - env: APP_VERSION=${TRAVIS_TAG#v} - - before_install: - - ./scripts/pull_travis_ci_tools.sh - - install: - # installs hub to ~/bin - - $HOME/travisci-tools/release_github/install_hub.sh - - export PATH=$HOME/bin:$HOME/travisci-tools/slack:$PATH - - before_script: skip - - script: - - hub release download $(git describe --abbrev=0 --tags) -i '*-linux-amd64-*' - - tar xvfz generate_secret-linux-amd64-${APP_VERSION}.tar.gz -C /tmp - - /tmp/generate_secret - - after_failure: - - SLACK_TEXT="${APP_VERSION} $TRAVIS_OS_NAME assets failed verification." send_to_slack.sh - - - stage: 'Test github release assets' - if: type = push AND tag IS present AND tag =~ /^v[0-9]+\.[0-9]+\.[0-9]+(\-beta)?[0-9]*$/ - name: darwin - os: osx - env: APP_VERSION=${TRAVIS_TAG#v} - - before_install: - - ./scripts/pull_travis_ci_tools.sh - - HOMEBREW_NO_AUTO_UPDATE=1 brew install jq - - install: - # installs hub to ~/bin - - $HOME/travisci-tools/release_github/install_hub.sh - - export PATH=$HOME/bin:$HOME/travisci-tools/slack:$PATH - - before_script: skip - - script: - - hub release download $(git describe --abbrev=0 --tags) -i '*-darwin-amd64-*' - - tar xvfz generate_secret-darwin-amd64-${APP_VERSION}.tar.gz -C /tmp - - /tmp/generate_secret - - after_failure: - - SLACK_TEXT="${APP_VERSION} $TRAVIS_OS_NAME assets failed verification." send_to_slack.sh - - - stage: 'Test github release assets' - if: type = push AND tag IS present AND tag =~ /^v[0-9]+\.[0-9]+\.[0-9]+(\-beta)?[0-9]*$/ - name: windows - os: windows - env: APP_VERSION=${TRAVIS_TAG#v} - - before_install: - - ./scripts/pull_travis_ci_tools.sh - - install: - # installs hub to ~/bin - - $HOME/travisci-tools/release_github/install_hub.sh - - export PATH=$HOME/bin:$HOME/travisci-tools/slack:$PATH - - before_script: skip - - script: - - hub release download $(git describe --abbrev=0 --tags) -i '*-windows-amd64-*' - - tar xvfz generate_secret-windows-amd64-${APP_VERSION}.tar.gz -C /tmp - - /tmp/generate_secret.exe - - after_failure: - - SLACK_TEXT="${APP_VERSION} $TRAVIS_OS_NAME assets failed verification." send_to_slack.sh - - - stage: 'Publish (real)' - if: type = push AND tag IS present AND tag =~ /^v[0-9]+\.[0-9]+\.[0-9]+(\-beta)?[0-9]*$/ - name: publish and notify in slack - os: linux - env: APP_VERSION=${TRAVIS_TAG#v} - - before_install: - - ./scripts/pull_travis_ci_tools.sh - - install: - # installs hub to ~/bin - - $HOME/travisci-tools/release_github/install_hub.sh - - export PATH=$HOME/bin:$HOME/travisci-tools/slack:$PATH - - before_script: skip - - script: - - SLACK_TEXT="${APP_VERSION} all assets verified. Publishing https://github.com/optimizely/agent/releases/tag/${TRAVIS_TAG}" send_to_slack.sh - # how to use hub: https://hub.github.com/hub.1.html - - hub release edit --draft=false -m "" ${TRAVIS_TAG} - - - stage: 'Readme-sync-preview' - # publishes changes in your docs pull request (ie, contains changes to /docs/readme-sync directory) to https://rollouts-sandbox-doc-test.readme.io/ for previewing before - # committing to master - before_script: skip - cache: false - # translation: if we're committing to a pull request... - if: false AND type = pull_request - - language: node_js - install: - - - # make dir $HOME/readme-sync2 & clone readme-sync2 repo to it; install dependencies - - - mkdir $HOME/readme-sync2 && pushd $HOME/readme-sync2 && git init && git pull https://$CI_USER_TOKEN@github.com/optimizely/readme-sync2.git && popd - - source ~/.nvm/nvm.sh && cd $HOME/readme-sync2 && nvm install && npm install - - script: - # we need to be in $TRAVIS_BUILD_DIR in order to run the following git diff properly - - cd $TRAVIS_BUILD_DIR - - # print which docs changed in this Pull Request (and which therefore we expect to be updated by readme-sync-2 tool): - - CHANGED_DOCS_FILES=($(git diff --name-only $TRAVIS_COMMIT_RANGE -- docs/readme-sync)) - - echo $CHANGED_DOCS_FILES - - # only if changes were made in the docs/readme-sync repo, trigger this readme-sync stage and sync the docs - # to staging readme project at https://rollouts-sandbox-doc-test.readme.io/docs - - - # build v3.1 docs to v 1.0 of readme staging project - - git diff --quiet $TRAVIS_COMMIT_RANGE -- docs/readme-sync/v3.1 || ( cd $HOME/readme-sync2 && npx ts-node sync/index.ts --apiKey $README_SYNC_API_KEY_PREVIEW --version 1.0 --docs $TRAVIS_BUILD_DIR/docs/readme-sync/v3.1) - # build v4.0 docs to v 1.5 of staging project - - git diff --quiet $TRAVIS_COMMIT_RANGE -- docs/readme-sync/v4.0 || ( cd $HOME/readme-sync2 && npx ts-node sync/index.ts --apiKey $README_SYNC_API_KEY_PREVIEW --version 1.5 --docs $TRAVIS_BUILD_DIR/docs/readme-sync/v4.0) - - - stage: 'Readme-sync' - before_script: skip - cache: false - # translation: if we're merging into a master branch... - if: false AND type = push AND branch = master - - language: node_js - install: - - - # make dir $HOME/readme-sync2 & clone readme-sync2 repo to it; install dependencies - - - mkdir $HOME/readme-sync2 && pushd $HOME/readme-sync2 && git init && git pull https://$CI_USER_TOKEN@github.com/optimizely/readme-sync2.git && popd - - source ~/.nvm/nvm.sh && cd $HOME/readme-sync2 && nvm install && npm install - - script: - # we need to be in $TRAVIS_BUILD_DIR in order to run the following git diff properly - - cd $TRAVIS_BUILD_DIR - - #print which docs changed in this Pull Request (and which therefore we expect to be updated by readme-sync-2 tool): - - CHANGED_DOCS_FILES=($(git diff --name-only $TRAVIS_COMMIT_RANGE -- docs/readme-sync)) - - echo $CHANGED_DOCS_FILES - - #only if changes were made in the docs/readme-sync repo, trigger this readme-sync stage and sync the docs to full stack readme project (https://dash.readme.com/project/full-stack/v4.0/docs/welcome) - # sync v3.1 docs folder to readme project v 3.1 - - git diff --quiet $TRAVIS_COMMIT_RANGE -- docs/readme-sync/v3.1 || ( cd $HOME/readme-sync2 && npx ts-node sync/index.ts --apiKey $README_SYNC_API_KEY --version 3.1 --docs $TRAVIS_BUILD_DIR/docs/readme-sync/v3.1 - # sync v4.0 docs folder to readme project v 4.0 - - git diff --quiet $TRAVIS_COMMIT_RANGE -- docs/readme-sync/v4.0 || ( cd $HOME/readme-sync2 && npx ts-node sync/index.ts --apiKey $README_SYNC_API_KEY --version 4.0 --docs $TRAVIS_BUILD_DIR/docs/readme-sync/v4.0 - ######################################################################################### - # directories/scripts for full SDK-reference-guides, to be implemented after agent docs sync - ######################################################################################### - # this commented out code can be used to implement syncing SDK guides in future: https://optimizely.atlassian.net/browse/OASIS-6807 - ## this preps the input directory for readme-sync script - #- mkdir -p $HOME/readme-sync2/docs/readme-sync/sdk-reference-guides - ## ${TRAVIS_REPO_SLUG#optimizely/} translates to go-sdk docs/readme-sync/sdk-reference-guides/go-sdk - #- ln -s $TRAVIS_BUILD_DIR/docs/readme-sync/sdk-reference-guides/${TRAVIS_REPO_SLUG#optimizely/} $HOME/readme-sync2/docs/readme-sync/sdk-reference-guides/${TRAVIS_REPO_SLUG#optimizely/} - - ## now we need to get all the other *-sdk repos too - ## - ## first we list all possible sdks and inside the for loop, remove the one we are updating - #- export ALL_SDK_REPOS="android-sdk csharp-sdk go-sdk java-sdk javascript-sdk objective-c-sdk python-sdk react-sdk ruby-sdk swift-sdk" - #- mkdir $HOME/sdks && pushd $HOME/sdks && for i in ${ALL_SDK_REPOS//${TRAVIS_REPO_SLUG#optimizely/}}; do git clone https://github.com/optimizely/$i; ( [ -d "$HOME/sdks/$i/docs/readme-sync/sdk-reference-guides/$i" ] && ln -s $HOME/sdks/$i/docs/readme-sync/sdk-reference-guides/$i $HOME/readme-sync2/docs/readme-sync/sdk-reference-guides/$i ) || true; done && popd - ## check our work - #- ls -al $HOME/sdks - #- ls -al $HOME/readme-sync2/docs/readme-sync/sdk-reference-guides - #script: - ## we need to be in $TRAVIS_BUILD_DIR in order to run the following git diff properly - #- cd $TRAVIS_BUILD_DIR - #- git diff --quiet $TRAVIS_COMMIT_RANGE -- docs/readme-sync || ( cd $HOME/readme-sync2 && npx ts-node sync/index.ts --apiKey $README_SYNC_API_KEY --version 4.0 --docs docs/readme-sync/ ) - - - -before_script: - # https://github.com/travis-ci/gimme - - eval "$(gimme)" - - make -e setup build diff --git a/CHANGELOG.md b/CHANGELOG.md index 5379fe22..d021d7f1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). +## [3.0.1] - March 13, 2023 + +- Update README.md and other non-functional code to reflect that this SDK supports both Optimizely Feature Experimentation and Optimizely Full Stack. ([#369](https://github.com/optimizely/agent/pull/369)). + ## [3.0.0] - February 28, 2023 - Upgrade golang version to `1.20` ([#357](https://github.com/optimizely/agent/pull/357)). @@ -29,18 +33,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Introduce `Forced Decisions` property into the `decide` API for overriding and managing user-level flag, experiment and delivery rule decisions. Forced decisions can be used for QA and automated testing purposes ([#324](https://github.com/optimizely/agent/pull/324), [#325](https://github.com/optimizely/agent/pull/325)). - - For details, refer to our API documentation page: https://library.optimizely.com/docs/api/agent/v1/index.html#operation/decide. + - For details, refer to our API documentation page: https://library.optimizely.com/docs/api/agent/v1/index.html#operation/decide. - Upgrade to use [Go SDK v1.8.0](https://github.com/optimizely/go-sdk/releases/tag/v1.8.0). This adds support for Forced Decisions. ## [2.5.0] - Sep 24, 2021 - - Add new fields (sdkKey, environmentKey, attributes, audiences, events, experimentRules, deliveryRules) to `/config` endpoint ([PR #322](https://github.com/optimizely/agent/pull/322)): + - Add new fields (sdkKey, environmentKey, attributes, audiences, events, experimentRules, deliveryRules) to `/config` endpoint ([PR #322](https://github.com/optimizely/agent/pull/322)): ## [2.4.0] - March 3, 2021 ## New Features -- Introduce `/decide` endpoint as a new primary interface for Decide APIs, that is for retrieving feature flag status, configuration and associated experiment decisions for users ([#292](https://github.com/optimizely/agent/pull/292)). +- Introduce `/decide` endpoint as a new primary interface for Decide APIs, that is for retrieving feature flag status, configuration and associated experiment decisions for users ([#292](https://github.com/optimizely/agent/pull/292)). -- For details about this Agent release, refer to our documentation page: https://docs.developers.optimizely.com/full-stack/v4.0/docs/optimizely-agent. +- For details about this Agent release, refer to our documentation page: https://docs.developers.optimizely.com/full-stack/v4.0/docs/optimizely-agent. Upgrade to use [Go SDK v1.6.1](https://github.com/optimizely/go-sdk/tree/v1.6.1). This adds support for OptimizelyDecision. ## [2.3.1] - November 17, 2020 @@ -56,12 +60,12 @@ Upgrade to use [Go SDK v1.6.1](https://github.com/optimizely/go-sdk/tree/v1.6.1) ## [2.1.0] - September 23, 2020 - For `server.allowedHosts` configuration property, add support for matching all subdomains of a host, or all hosts - Adding batching for agent (/v1/batch endpoint), including requests in parallel -- Removed vulnerable version coreos/etcd +- Removed vulnerable version coreos/etcd ## [2.0.0] - August 27, 2020 - Add SDK key validation configuration - Reject request with invalid host (excluding port) -- Block content type other than application/json +- Block content type other than application/json - Introducing support for authenticated datafiles ### Breaking Changes diff --git a/README.md b/README.md index 22078ea4..ae3794d1 100644 --- a/README.md +++ b/README.md @@ -1,28 +1,38 @@ -[![Build Status](https://travis-ci.com/optimizely/agent.svg?token=y3xM1z7bQsqHX2NTEhps&branch=master)](https://travis-ci.com/optimizely/agent) +[![Build Status](https://github.com/optimizely/agent/actions/workflows/agent.yml/badge.svg?branch=master)](https://github.com/optimizely/agent/actions/workflows/agent.yml?query=branch%3Amaster) [![Coverage Status](https://coveralls.io/repos/github/optimizely/agent/badge.svg)](https://coveralls.io/github/optimizely/agent) + # Optimizely Agent -Optimizely Agent is a service which exposes the functionality of the Full Stack and Rollouts SDKs as -a highly available and distributed web application. -Optimizely Full Stack is A/B testing and feature flag management for product development teams. Experiment in any application. Make every feature on your roadmap an opportunity to learn. Learn more at https://www.optimizely.com/platform/full-stack/, or see the [documentation](https://docs.developers.optimizely.com/full-stack/docs). +This repository houses the Optimizely Agent service for use with Optimizely Feature Experimentation and Optimizely Full Stack (legacy). + +Optimizely Feature Experimentation is an A/B testing and feature management tool for product development teams that enables you to experiment at every step. Using Optimizely Feature Experimentation allows for every feature on your roadmap to be an opportunity to discover hidden insights. Learn more at [Optimizely.com](https://www.optimizely.com/products/experiment/feature-experimentation/), or see the [developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/welcome). + +Optimizely Rollouts is [free feature flags](https://www.optimizely.com/free-feature-flagging/) for development teams. You can easily roll out and roll back features in any application without code deploys, mitigating risk for every feature on your roadmap. + +## Get Started + +Refer to the [Agent's developer documentation](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/optimizely-agent) for detailed instructions on getting started with using the SDK. -## Getting Started -To get started with Optimizely Agent, follow the [Quickstart guide](https://docs.developers.optimizely.com/full-stack/docs/) and view example usage in our [examples folder](./examples). +### Requirements -## Prerequisites Optimizely Agent is implemented in [Golang](https://golang.org/). Golang version 1.20+ is required for developing and compiling from source. -Installers and binary archives for most platforms can be downloaded directly from the Go [downloads](https://golang.org/dl/) page. +Installers and binary archives for most platforms can be downloaded directly from the Go [downloads](https://go.dev/dl/) page. + +### Run from source (Linux / OSX) -## Running from source (Linux / OSX) Once Go is installed, the Optimizely Agent can be started via the following `make` command: + ```bash make setup make run ``` + This will start the Optimizely Agent with the default configuration in the foreground. -## Running from source (Windows) -A helper script is available under [scripts/build.ps1](./scripts/build.ps1) to automate compiling Agent in a Windows environment. The script will download and install both Git and Golang and then attempt to compile Agent. Open a Powershell terminal and run +### Run from source (Windows) + +A helper script is available under [scripts/build.ps1](./scripts/build.ps1) to automate compiling Agent in a Windows environment. The script will download and install both Git and Golang and then attempt to compile Agent. Open a Powershell terminal and run + ```bash Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser @@ -31,19 +41,23 @@ Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser .\bin\optimizely.exe ``` -## Running via Docker +### Run via Docker + If you have Docker installed, Optimizely Agent can be started as a container. First pull the Docker image with: + ```bash docker pull optimizely/agent ``` By default this will pull the "latest" tag. You can also specify a specific version of Agent by providing the version as a tag to the docker command: + ```bash docker pull optimizely/agent:X.Y.Z ``` Then run the docker container with: + ```bash docker run -p 8080:8080 --env OPTIMIZELY_LOG_PRETTY=true --env OPTIMIZELY_SERVER_HOST=0.0.0.0 --env OPTIMIZELY_SERVER_ALLOWEDHOSTS=127.0.0.1 optimizely/agent ``` @@ -51,91 +65,97 @@ docker run -p 8080:8080 --env OPTIMIZELY_LOG_PRETTY=true --env OPTIMIZELY_SERVER This will start Agent in the foreground and expose the container API port 8080 to the host. Note that when a new version is released, 2 images are pushed to dockerhub, they are distinguished by their tags: + - :latest (same as :X.Y.Z) - :alpine (same as :X.Y.Z-alpine) The difference between latest and alpine is that latest is built `FROM scratch` while alpine is `FROM alpine`. + - [latest Dockerfile](./scripts/dockerfiles/Dockerfile.static) - [alpine Dockerfile](./scripts/dockerfiles/Dockerfile.alpine) -## Configuration Options +### Configuration Options + Optimizely Agent configuration can be overridden by a yaml configuration file provided at runtime. By default the configuration file will be sourced from the current active directory `e.g. ./config.yaml`. Alternative configuration locations can be specified at runtime via environment variable or command line flag. + ```bash OPTIMIZELY_CONFIG_FILENAME=config.yaml make run ``` + The default configuration can be found [here](config.yaml). Below is a comprehensive list of available configuration properties. -|Property Name|Env Variable|Description| -|---|---|---| -|admin.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|admin.auth.hmacSecrets|OPTIMIZELY_ADMIN_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|admin.auth.jwksUpdateInterval|OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|admin.auth.jwksURL|OPTIMIZELY_ADMIN_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|admin.auth.ttl|OPTIMIZELY_ADMIN_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|admin.port|OPTIMIZELY_ADMIN_PORT|Admin listener port. Default: 8088| -|api.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|api.auth.hmacSecrets|OPTIMIZELY_API_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|api.auth.jwksUpdateInterval|OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|api.auth.jwksURL|OPTIMIZELY_API_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|api.auth.ttl|OPTIMIZELY_API_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization)| -|api.enableNotifications|OPTIMIZELY_API_ENABLENOTIFICATIONS|Enable streaming notification endpoint. Default: false| -|api.enableOverrides|OPTIMIZELY_API_ENABLEOVERRIDES|Enable bucketing overrides endpoint. Default: false| -|api.maxConns|OPTIMIZELY_API_MAXCONNS|Maximum number of concurrent requests| -|api.port|OPTIMIZELY_API_PORT|Api listener port. Default: 8080| -|author|OPTIMIZELY_AUTHOR|Agent author. Default: Optimizely Inc.| -|client.batchSize|OPTIMIZELY_CLIENT_BATCHSIZE|The number of events in a batch. Default: 10| -|client.datafileURLTemplate|OPTIMIZELY_CLIENT_DATAFILEURLTEMPLATE|Template URL for SDK datafile location. Default: https://cdn.optimizely.com/datafiles/%s.json| -|client.eventURL|OPTIMIZELY_CLIENT_EVENTURL|URL for dispatching events. Default: https://logx.optimizely.com/v1/events| -|client.flushInterval|OPTIMIZELY_CLIENT_FLUSHINTERVAL|The maximum time between events being dispatched. Default: 30s| -|client.pollingInterval|OPTIMIZELY_CLIENT_POLLINGINTERVAL|The time between successive polls for updated project configuration. Default: 1m| -|client.queueSize|OPTIMIZELY_CLIENT_QUEUESIZE|The max number of events pending dispatch. Default: 1000| -|client.sdkKeyRegex|OPTIMIZELY_CLIENT_SDKKEYREGEX|Regex to validate SDK keys provided in request header. Default: ^\\w+(:\\w+)?$| -|client.userProfileService|OPTIMIZELY_CLIENT_USERPROFILESERVICE| Property used to enable and set UserProfileServices. Default: ./config.yaml| -|config.filename|OPTIMIZELY_CONFIG_FILENAME|Location of the configuration YAML file. Default: ./config.yaml| -|log.level|OPTIMIZELY_LOG_LEVEL|The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info| -|log.pretty|OPTIMIZELY_LOG_PRETTY|Flag used to set colorized console output as opposed to structured json logs. Default: false| -|name|OPTIMIZELY_NAME|Agent name. Default: optimizely| -|sdkKeys|OPTIMIZELY_SDKKEYS|Comma delimited list of SDK keys used to initialize on startup| -|server.allowedHosts|OPTIMIZELY_SERVER_ALLOWEDHOSTS|List of allowed request host values. Requests whose host value does not match either the configured server.host, or one of these, will be rejected with a 404 response. To match all subdomains, you can use a leading dot (for example `.example.com` matches `my.example.com`, `hello.world.example.com`, etc.). You can use the value `.` to disable allowed host checking, allowing requests with any host. Request host is determined in the following priority order: 1. X-Forwarded-Host header value, 2. Forwarded header host= directive value, 3. Host property of request (see Host under https://golang.org/pkg/net/http/#Request). Note: don't include port in these hosts values - port is stripped from the request host before comparing against these.| -|server.batchRequests.maxConcurrency|OPTIMIZELY_SERVER_BATCHREQUESTS_MAXCONCURRENCY|Number of requests running in parallel. Default: 10| -|server.batchRequests.operationsLimit|OPTIMIZELY_SERVER_BATCHREQUESTS_OPERATIONSLIMIT|Number of allowed operations. ( will flag an error if the number of operations exeeds this parameter) Default: 500| -|server.certfile|OPTIMIZELY_SERVER_CERTFILE|Path to a certificate file, used to run Agent with HTTPS| -|server.disabledCiphers|OPTIMIZELY_SERVER_DISABLEDCIPHERS|List of TLS ciphers to disable when accepting HTTPS connections| -|server.healthCheckPath|OPTIMIZELY_SERVER_HEALTHCHECKPATH|Path for the health status api. Default: /health| -|server.host|OPTIMIZELY_SERVER_HOST|Host of server. Default: 127.0.0.1| -|server.interceptors|N/A|Property used to enable and set [Interceptor](https://docs.developers.optimizely.com/full-stack/docs/agent-plugins#section-interceptor-plugins) plugins| -|server.keyfile|OPTIMIZELY_SERVER_KEYFILE|Path to a key file, used to run Agent with HTTPS| -|server.readTimeout|OPTIMIZELY_SERVER_READTIMEOUT|The maximum duration for reading the entire body. Default: “5s”| -|server.writeTimeout|OPTIMIZELY_SERVER_WRITETIMEOUT|The maximum duration before timing out writes of the response. Default: “10s”| -|version|OPTIMIZELY_VERSION|Agent version. Default: `git describe --tags`| -|webhook.port|OPTIMIZELY_WEBHOOK_PORT|Webhook listener port: Default: 8085| -|webhook.projects.<*projectId*>.sdkKeys|N/A|Comma delimited list of SDK Keys applicable to the respective projectId| -|webhook.projects.<*projectId*>.secret|N/A|Webhook secret used to validate webhook requests originating from the respective projectId| -|webhook.projects.<*projectId*>.skipSignatureCheck|N/A|Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret.| - -More information about configuring Agent can be found in the [Advanced Configuration Notes](https://docs.developers.optimizely.com/full-stack/docs/advanced-configuration). - -## API +| Property Name | Env Variable | Description | +| ------------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| admin.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| admin.auth.hmacSecrets | OPTIMIZELY_ADMIN_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| admin.auth.jwksUpdateInterval | OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| admin.auth.jwksURL | OPTIMIZELY_ADMIN_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| admin.auth.ttl | OPTIMIZELY_ADMIN_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| admin.port | OPTIMIZELY_ADMIN_PORT | Admin listener port. Default: 8088 | +| api.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| api.auth.hmacSecrets | OPTIMIZELY_API_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| api.auth.jwksUpdateInterval | OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| api.auth.jwksURL | OPTIMIZELY_API_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| api.auth.ttl | OPTIMIZELY_API_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorizationn) | +| api.enableNotifications | OPTIMIZELY_API_ENABLENOTIFICATIONS | Enable streaming notification endpoint. Default: false | +| api.enableOverrides | OPTIMIZELY_API_ENABLEOVERRIDES | Enable bucketing overrides endpoint. Default: false | +| api.maxConns | OPTIMIZELY_API_MAXCONNS | Maximum number of concurrent requests | +| api.port | OPTIMIZELY_API_PORT | Api listener port. Default: 8080 | +| author | OPTIMIZELY_AUTHOR | Agent author. Default: Optimizely Inc. | +| client.batchSize | OPTIMIZELY_CLIENT_BATCHSIZE | The number of events in a batch. Default: 10 | +| client.datafileURLTemplate | OPTIMIZELY_CLIENT_DATAFILEURLTEMPLATE | Template URL for SDK datafile location. Default: https://cdn.optimizely.com/datafiles/%s.json | +| client.eventURL | OPTIMIZELY_CLIENT_EVENTURL | URL for dispatching events. Default: https://logx.optimizely.com/v1/events | +| client.flushInterval | OPTIMIZELY_CLIENT_FLUSHINTERVAL | The maximum time between events being dispatched. Default: 30s | +| client.pollingInterval | OPTIMIZELY_CLIENT_POLLINGINTERVAL | The time between successive polls for updated project configuration. Default: 1m | +| client.queueSize | OPTIMIZELY_CLIENT_QUEUESIZE | The max number of events pending dispatch. Default: 1000 | +| client.sdkKeyRegex | OPTIMIZELY_CLIENT_SDKKEYREGEX | Regex to validate SDK keys provided in request header. Default: ^\\w+(:\\w+)?$ | +| client.userProfileService | OPTIMIZELY_CLIENT_USERPROFILESERVICE | Property used to enable and set UserProfileServices. Default: ./config.yaml | +| config.filename | OPTIMIZELY_CONFIG_FILENAME | Location of the configuration YAML file. Default: ./config.yaml | +| log.level | OPTIMIZELY_LOG_LEVEL | The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info | +| log.pretty | OPTIMIZELY_LOG_PRETTY | Flag used to set colorized console output as opposed to structured json logs. Default: false | +| name | OPTIMIZELY_NAME | Agent name. Default: optimizely | +| sdkKeys | OPTIMIZELY_SDKKEYS | Comma delimited list of SDK keys used to initialize on startup | +| server.allowedHosts | OPTIMIZELY_SERVER_ALLOWEDHOSTS | List of allowed request host values. Requests whose host value does not match either the configured server.host, or one of these, will be rejected with a 404 response. To match all subdomains, you can use a leading dot (for example `.example.com` matches `my.example.com`, `hello.world.example.com`, etc.). You can use the value `.` to disable allowed host checking, allowing requests with any host. Request host is determined in the following priority order: 1. X-Forwarded-Host header value, 2. Forwarded header host= directive value, 3. Host property of request (see Host under https://pkg.go.dev/net/http#Request). Note: don't include port in these hosts values - port is stripped from the request host before comparing against these. | +| server.batchRequests.maxConcurrency | OPTIMIZELY_SERVER_BATCHREQUESTS_MAXCONCURRENCY | Number of requests running in parallel. Default: 10 | +| server.batchRequests.operationsLimit | OPTIMIZELY_SERVER_BATCHREQUESTS_OPERATIONSLIMIT | Number of allowed operations. ( will flag an error if the number of operations exeeds this parameter) Default: 500 | +| server.certfile | OPTIMIZELY_SERVER_CERTFILE | Path to a certificate file, used to run Agent with HTTPS | +| server.disabledCiphers | OPTIMIZELY_SERVER_DISABLEDCIPHERS | List of TLS ciphers to disable when accepting HTTPS connections | +| server.healthCheckPath | OPTIMIZELY_SERVER_HEALTHCHECKPATH | Path for the health status api. Default: /health | +| server.host | OPTIMIZELY_SERVER_HOST | Host of server. Default: 127.0.0.1 | +| server.interceptors | N/A | Property used to enable and set [Interceptor](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-plugins#interceptor-plugins) plugins | +| server.keyfile | OPTIMIZELY_SERVER_KEYFILE | Path to a key file, used to run Agent with HTTPS | +| server.readTimeout | OPTIMIZELY_SERVER_READTIMEOUT | The maximum duration for reading the entire body. Default: “5s” | +| server.writeTimeout | OPTIMIZELY_SERVER_WRITETIMEOUT | The maximum duration before timing out writes of the response. Default: “10s” | +| version | OPTIMIZELY_VERSION | Agent version. Default: `git describe --tags` | +| webhook.port | OPTIMIZELY_WEBHOOK_PORT | Webhook listener port: Default: 8085 | +| webhook.projects.<_projectId_>.sdkKeys | N/A | Comma delimited list of SDK Keys applicable to the respective projectId | +| webhook.projects.<_projectId_>.secret | N/A | Webhook secret used to validate webhook requests originating from the respective projectId | +| webhook.projects.<_projectId_>.skipSignatureCheck | N/A | Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret. | + +More information about configuring Agent can be found in the [Advanced Configuration Notes](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/advanced-configuration). + +### API The core API is implemented as a REST service configured on it's own HTTP listener port (default 8080). The full API specification is defined in an OpenAPI 3.0 (aka Swagger) [spec](./api/openapi-spec/openapi.yaml). Each request made into the API must include a `X-Optimizely-SDK-Key` in the request header to identify the context the request should be evaluated. The SDK key maps to a unique Optimizely Project and -[Environment](https://docs.developers.optimizely.com/rollouts/docs/manage-environments) allowing multiple -Environments to be serviced by a single Agent. -For a secure environment, this header should include both the SDK key and the datafile access token -separated by a colon. For example, if SDK key is `my_key` and datafile access token is `my_token` -then set header's value to `my_key:my_token`. +[Environment](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/manage-environments) allowing multiple +Environments to be serviced by a single Agent. +For a secure environment, this header should include both the SDK key and the datafile access token +separated by a colon. For example, if SDK key is `my_key` and datafile access token is `my_token` +then set header's value to `my_key:my_token`. -### Enabling CORS +#### Enabling CORS CORS can be enabled for the core API service by setting the the appropriate cors properties. + ```yaml api: cors: @@ -148,12 +168,12 @@ api: For more advanced options please refer to the [go-chi/cors](https://github.com/go-chi/cors) middleware documentation. -NOTE: To avoid any potential security issues, and reduce risk to your data it's recommended that [authentication](https://docs.developers.optimizely.com/full-stack/docs/authorization) +NOTE: To avoid any potential security issues, and reduce risk to your data it's recommended that [authentication](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization) is enabled alongside CORS. -## Webhooks +### Webhooks -The webhook listener used to receive inbound [Webhook](https://docs.developers.optimizely.com/rollouts/docs/webhooks) +The webhook listener used to receive inbound [Webhook](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/webhooks-agent) requests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates. The webhook listener is configured on its own port (default: 8085) since it can be configured to select traffic from the internet. @@ -171,16 +191,18 @@ of the service, runtime information and operational metrics. By default the admi The `/info` endpoint provides basic information about the Optimizely Agent instance. Example Request: + ```bash curl localhost:8088/info ``` Example Response: + ```json { - "version": "v0.10.0", - "author": "Optimizely Inc.", - "app_name": "optimizely" + "version": "v0.10.0", + "author": "Optimizely Inc.", + "app_name": "optimizely" } ``` @@ -189,14 +211,16 @@ Example Response: The `/health` endpoint is used to determine service availability. Example Request: + ```bash curl localhost:8088/health ``` Example Response: + ```json { - "status": "ok" + "status": "ok" } ``` @@ -207,14 +231,16 @@ This endpoint can used when placing Agent behind a load balancer to indicate whe ### Metrics -The `/metrics` endpoint exposes telemetry data of the running Optimizely Agent. The core runtime metrics are exposed via the go expvar package. Documentation for the various statistics can be found as part of the [mstats](https://golang.org/src/runtime/mstats.go) package. +The `/metrics` endpoint exposes telemetry data of the running Optimizely Agent. The core runtime metrics are exposed via the go expvar package. Documentation for the various statistics can be found as part of the [mstats](https://go.dev/src/runtime/mstats.go) package. Example Request: + ```bash curl localhost:8088/metrics ``` Example Response: + ``` { "cmdline": [ @@ -233,6 +259,7 @@ Example Response: ... } ``` + Custom metrics are also provided for the individual service endpoints and follow the pattern of: ``` @@ -281,59 +308,69 @@ go tool pprof http://localhost:6060/debug/pprof/mutex To view all available profiles can be found at [http://localhost:8088/debug/pprof/](http://localhost:8088/debug/pprof/) in your browser. ## Agent Plugins -Optimizely Agent can be extended through the use of [plugins](https://docs.developers.optimizely.com/full-stack/docs/agent-plugins). Plugins are distinct from the standard Agent packages + +Optimizely Agent can be extended through the use of [plugins](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-plugins). Plugins are distinct from the standard Agent packages to provide a namespaced environment for custom logic. Plugins must be compiled as part of the Agent distribution and are enabled through configuration. ### Interceptor Plugins -* [httplog](./plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). -## UserProfileService Plugins -* [UserProfileService](./plugins/userprofileservice/README.md) - Adds UserProfileService. +- [httplog](./plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). -## Authorization -Optimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. For details, see [Authorization Guide](https://docs.developers.optimizely.com/full-stack/docs/authorization). +### UserProfileService Plugins -## Notifications -Just as you can use Notification Listeners to subscribe to events of interest with Optimizely SDKs, you can use the Notifications endpoint to subscribe to events in Agent. For more information, see the [Notifications Guide](https://docs.developers.optimizely.com/full-stack/docs/agent-notifications). +- [UserProfileService](./plugins/userprofileservice/README.md) - Adds UserProfileService. + +### Authorization + +Optimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. For details, see [Authorization Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/authorization). + +### Notifications + +Just as you can use Notification Listeners to subscribe to events of interest with Optimizely SDKs, you can use the Notifications endpoint to subscribe to events in Agent. For more information, see the [Notifications Guide](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/agent-notifications). + +## Agent Development + +### Package Structure -## Package Structure Following best practice for go project layout as defined [here](https://github.com/golang-standards/project-layout) -* **api** - OpenAPI/Swagger specs, JSON schema files, protocol definition files. -* **bin** - Compiled application binaries. -* **cmd** - Main applications for this project. -* **config** - Application configuration. -* **docs** - User documentation files. -* **pkg** - Library code that can be used by other applications. -* **plugins** - Plugin libraries for extending Agent functionality. -* **scripts** - Scripts to perform various build, install, analysis, etc operations. +- **api** - OpenAPI/Swagger specs, JSON schema files, protocol definition files. +- **bin** - Compiled application binaries. +- **cmd** - Main applications for this project. +- **config** - Application configuration. +- **docs** - User documentation files. +- **pkg** - Library code that can be used by other applications. +- **plugins** - Plugin libraries for extending Agent functionality. +- **scripts** - Scripts to perform various build, install, analysis, etc operations. + +### Make Commands -## Make targets The following `make` targets can be used to build and run the application: -* **build** - builds optimizely and installs binary in bin/optimizely -* **clean** - runs `go clean` and removes the bin/ dir -* **cover** - runs test suite with coverage profiling -* **cover-html** - generates test coverage html report -* **install** - installs all dev and ci dependencies, but does not install golang -* **lint** - runs `golangci-lint` linters defined in `.golangci.yml` file -* **run** - builds and executes the optimizely binary -* **test** - recursively tests all .go files + +- **build** - builds optimizely and installs binary in bin/optimizely +- **clean** - runs `go clean` and removes the bin/ dir +- **cover** - runs test suite with coverage profiling +- **cover-html** - generates test coverage html report +- **setup** - installs all dev and ci dependencies, but does not install golang +- **lint** - runs `golangci-lint` linters defined in `.golangci.yml` file +- **run** - builds and executes the optimizely binary +- **test** - recursively tests all .go files ## Credits This software is used with additional code that is separately downloaded by you. These components are subject to their own license terms which you should review carefully. Gohistogram -(c) 2013 VividCortex -License (MIT): github.com/VividCortex/gohistogram +(c) 2013 VividCortex +License (MIT): https://github.com/VividCortex/gohistogram Chi -(c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc. -License (MIT): github.com/go-chi/chi +(c) 2015-present Peter Kieltyka (https://github.com/pkieltyka), Google Inc. +License (MIT): https://github.com/go-chi/chi -chi-render +chi-render (c) 2016-Present https://github.com/go-chi ‑ authors -License (MIT): github.com/go-chi/render +License (MIT): https://github.com/go-chi/render hostrouter (c) 2016-Present https://github.com/go-chi - authors @@ -341,54 +378,55 @@ License (MIT): https://github.com/go-chi/hostrouter go-chi/cors (c) 2014 Olivier Poitrey -License (MIT): github.com/go-chi/cors +License (MIT): https://github.com/go-chi/cors -go-kit +go-kit (c) 2015 Peter Bourgon -License (MIT): github.com/go-kit/kit +License (MIT): https://github.com/go-kit/kit guuid -(c) 2009,2014 Google Inc. All rights reserved. -License (BSD 3-Clause): github.com/google/uuid +(c) 2009,2014 Google Inc. All rights reserved. +License (BSD 3-Clause): https://github.com/google/uuid -optimizely go sdk +optimizely go sdk (c) 2016-2017, Optimizely, Inc. and contributors -License (Apache 2): github.com/optimizely/go-sdk +License (Apache 2): https://github.com/optimizely/go-sdk -concurrent-map +concurrent-map (c) 2014 streamrail -License (MIT): github.com/orcaman/concurrent-map +License (MIT): https://github.com/orcaman/concurrent-map -zerolog +zerolog (c) 2017 Olivier Poitrey -License (MIT): github.com/rs/zerolog +License (MIT): https://github.com/rs/zerolog -viper +viper (c) 2014 Steve Francia -License (MIT): github.com/spf13/viper +License (MIT): https://github.com/spf13/viper testify (c) 2012-2018 Mat Ryer and Tyler Bunnell -License (MIT): github.com/stretchr/testify +License (MIT): https://github.com/stretchr/testify -net +net (c) 2009 The Go Authors License (BSD 3-Clause): https://github.com/golang/net -sync +sync (c) 2009 The Go Authors License (BSD 3-Clause): https://github.com/golang/sync statik (c) 2014 rakyll -License (Apache 2): github.com/rakyll/statik v0.1.7 +License (Apache 2): https://github.com/rakyll/statik v0.1.7 -sys +sys (c) 2009 The Go Authors License (BSD 3-Clause): https://github.com/golang/sys ## Apache Copyright Notice + Copyright 2019-present, Optimizely, Inc. and contributors 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. +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. diff --git a/api/openapi-spec/openapi.yaml b/api/openapi-spec/openapi.yaml index fec6ac1d..d46a7ec5 100644 --- a/api/openapi-spec/openapi.yaml +++ b/api/openapi-spec/openapi.yaml @@ -1,8 +1,8 @@ openapi: 3.0.0 info: title: Optimizely Agent API - description: Optimizely Agent is a stand-alone, open-source microservice that provides major benefits over using Optimizely SDKs in certain use cases. Its REST API offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Full Stack SDKs. Use this API the control experiments (such as a feature tests). For more info, see https://docs.developers.optimizely.com/full-stack/docs/optimizely-agent. - termsOfService: http://optimizely.com/terms/ + description: Optimizely Agent is a stand-alone, open-source microservice that provides major benefits over using Optimizely SDKs in certain use cases. Its REST API offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Feature Experimentation SDKs. Use this API the control experiments (such as a feature tests). For more info, see https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/optimizely-agent + termsOfService: https://www.optimizely.com/legal/terms/ license: name: Apache 2.0 url: https://www.apache.org/licenses/LICENSE-2.0.html @@ -148,7 +148,7 @@ paths: post: summary: Activate selected features and experiments for the given user. operationId: activate - description: Returns Optimizely's decision about which features and experiments a given user is exposed to. Optionally sends an impression event to the Optimizely analytics backend for any decision made for an experiment. This endpoint consolidates key functionality from the Full Stack SDKs into one convenient call. + description: Returns Optimizely's decision about which features and experiments a given user is exposed to. Optionally sends an impression event to the Optimizely analytics backend for any decision made for an experiment. This endpoint consolidates key functionality from the Feature Experimentation SDKs into one convenient call. responses: '200': description: Valid response diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/010 - optimizely-agent.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/010 - optimizely-agent.md index 5bdadc3c..01404589 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/010 - optimizely-agent.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/010 - optimizely-agent.md @@ -3,76 +3,88 @@ title: "Optimizely Agent" excerpt: "" slug: "optimizely-agent" hidden: false -metadata: - title: "Optimizely Agent microservice - Optimizely Full Stack" +metadata: + title: "Optimizely Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-02-21T20:35:58.387Z" updatedAt: "2020-07-14T20:51:52.458Z" --- -Optimizely Agent is a standalone, open-source, and highly available microservice that provides major benefits over using Optimizely SDKs in certain use cases. The [Agent REST API](https://library.optimizely.com/docs/api/agent/v1/index.html) offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Full Stack SDKs. + +Optimizely Agent is a standalone, open-source, and highly available microservice that provides major benefits over using Optimizely SDKs in certain use cases. The [Agent REST API](https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/reference/getconfig) offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Feature Experimentation SDKs. A typical production installation of Optimizely Agent is to run two or more services behind a load balancer or proxy. The service itself can be run via a Docker container or installed from source. See [Setup Optimizely Agent](doc:setup-optimizely-agent) for instructions on how to run Optimizely Agent. ### Example Implementation + ![example implementation](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-example-implementation.png) + # Should I Use Optimizely Agent? Here are some of the top reasons to consider using Optimizely Agent: ## 1. Service Oriented Architecture (SOA) -If you already separate some of your logic into services that might need to access the Optimizely decision APIs, we recommend using Optimizely Agent. -The images below compare implementation styles in a service-oriented architecture, first *without* using Optimizely Agent, which shows six SDK embedded instances: +If you already separate some of your logic into services that might need to access the Optimizely decision APIs, we recommend using Optimizely Agent. + +The images below compare implementation styles in a service-oriented architecture, first _without_ using Optimizely Agent, which shows six SDK embedded instances: !["A diagram showing the use of SDKs installed on each service in a service oriented architecture \n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-service-oriented-architecture.png) -Now *with* Agent, instead of installing the SDK six times, you create just one Optimizely instance: an HTTP API that every service can access as needed. +Now _with_ Agent, instead of installing the SDK six times, you create just one Optimizely instance: an HTTP API that every service can access as needed. !["A diagram showing the use of Optimizely Agent in a single service \n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-single-service.png) ## 2. Standardize Access Across Teams -If you want to deploy Optimizely Full Stack once, then roll out the single implementation across a large number of teams, we recommend using Optimizely Agent. + +If you want to deploy Optimizely Feature Experimentation once, then roll out the single implementation across a large number of teams, we recommend using Optimizely Agent. By standardizing your teams' access to the Optimizely service, you can better enforce processes and implement governance around feature management and experimentation as a practice. !["A diagram showing the central and standardized access to the Optimizely Agent service across an arbitrary number of teams.\n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-standardized-access.png) ## 3. Networking Centralization -You don’t want many SDK instances connecting to Optimizely's cloud service from every node in your application. Optimizely Agent centralizes your network connection. Only one cluster of agent instances connects to Optimizely for tasks like update [datafiles](doc:get-the-datafile) and dispatch [events](doc:track-events). + +You don’t want many SDK instances connecting to Optimizely's cloud service from every node in your application. Optimizely Agent centralizes your network connection. Only one cluster of agent instances connects to Optimizely for tasks like update [datafiles](doc:get-the-datafile) and dispatch [events](doc:track-events). ## 4. Languages -You’re using a language that isn’t supported by a native SDK (i.e. Elixir, Scala, Perl). While its possible to create your own service using an Optimizely SDK of your choice, you could also customize the open-source Optimizely Agent to your needs without building the service layer on your own. +You’re using a language that isn’t supported by a native SDK (i.e. Elixir, Scala, Perl). While its possible to create your own service using an Optimizely SDK of your choice, you could also customize the open-source Optimizely Agent to your needs without building the service layer on your own. + +# Reasons to _not_ use Optimizely Agent -# Reasons to *not* use Optimizely Agent -If your use case wouldn't benefit greatly from Optimizely Agent, you should consider the below reasons to *not* use Optimizely Agent and review Optimizely's many [open-source SDKs](doc:sdk-reference-guides) instead. +If your use case wouldn't benefit greatly from Optimizely Agent, you should consider the below reasons to _not_ use Optimizely Agent and review Optimizely's many [open-source SDKs](doc:sdk-reference-guides) instead. ## 1. Latency -If time to provide bucketing decisions is a primary concern for you, you may want to use an embedded Full Stack SDK rather than Optimizely Agent. +If time to provide bucketing decisions is a primary concern for you, you may want to use an embedded Feature Experimentation SDK rather than Optimizely Agent. | Implementation Option | Decision Latency | -|-----------------------|------------------| +| --------------------- | ---------------- | | Embedded SDK | microseconds | | Optimizely Agent | milliseconds | ## 2. Monolith -If your app is constructed as a monolith, embedded SDKs might be easier to install and might be a more natural fit for your application and development practices. + +If your app is constructed as a monolith, embedded SDKs might be easier to install and might be a more natural fit for your application and development practices. ## 3. Velocity -If you’re looking for the fastest way to get a single team up and running with deploying feature management and experimentation, embedding an SDK is the best option for you at first. You can always start using Optimizely Agent later, and it can even be used alongside Optimizely Full Stack SDKs running in another part of your stack. + +If you’re looking for the fastest way to get a single team up and running with deploying feature management and experimentation, embedding an SDK is the best option for you at first. You can always start using Optimizely Agent later, and it can even be used alongside Optimizely Feature Experimentation SDKs running in another part of your stack. # Best Practices -While every implementation is different, you can review this section of best practices for tips on these commonly discussed topics. +While every implementation is different, you can review this section of best practices for tips on these commonly discussed topics. ## How many Agent instances should I deploy? + Agent can scale to large decision / event tracking volumes with relatively low CPU / memory specs. For example, at Optimizely, we scaled our deployment to 740 clients with a cluster of 12 agent instances, which in total use 6 vCPUs and 12GB RAM. You will likely need to focus more on network bandwidth than compute power. ## Using a load balancer + Any standard load balancer should let you route traffic across your agent cluster. At Optimizely, we used an AWS Elastic Load Balancer (ELB) for our internal deployment. This allows us to transparently scale our agent cluster as internal demands increase. ## Synchronizing datafiles across Agent instances + Agent offers eventual rather than strong consistency across datafiles. -In detail, today, each agent instance maintains a dedicated, separate cache. Each agent instance persists an SDK instance for each SDK key your team uses. Agent instances automatically keep datafiles up to date for each SDK key instance so that you will have eventual consistency across the cluster. The rate of the datafile update can be [set as the configuration](doc:configure-optimizely-agent) value ```OPTIMIZELY_CLIENT_POLLINGINTERVAL``` (the default is 1 minute). -Because SDKs are generally stateless today, they shouldn’t need to share data. We plan to add a common backing data store, so we invite you to share your feedback. +In detail, today, each agent instance maintains a dedicated, separate cache. Each agent instance persists an SDK instance for each SDK key your team uses. Agent instances automatically keep datafiles up to date for each SDK key instance so that you will have eventual consistency across the cluster. The rate of the datafile update can be [set as the configuration](doc:configure-optimizely-agent) value `OPTIMIZELY_CLIENT_POLLINGINTERVAL` (the default is 1 minute). +Because SDKs are generally stateless today, they shouldn’t need to share data. We plan to add a common backing data store, so we invite you to share your feedback. If you require strong consistency across datafiles, then we recommend an active / passive deployment where all requests are made to a single vertically scaled host, with a passive, standby cluster available for high availability. diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/012 - quickstart-for-agent.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/012 - quickstart-for-agent.md index fe3de499..e60adaa7 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/012 - quickstart-for-agent.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/012 - quickstart-for-agent.md @@ -3,8 +3,8 @@ title: "Quickstart for Agent" excerpt: "" slug: "quickstart-for-agent" hidden: false -metadata: - title: "Quickstart for Agent - Optimizely Full Stack" +metadata: + title: "Quickstart for Agent - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2020-08-17T20:51:52.458Z" --- @@ -15,11 +15,10 @@ This brief quickstart describes how to run Agent, using two examples: - To get started using example Node microservices, see the following video link. - - ## Running locally via Node -| Resource | Description | -| ------------------------------------------------------------ | ------------------------------------------------------------ | + +| Resource | Description | +| -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [Implementing feature flags across microservices with Optimizely Agent](https://www.youtube.com/watch?v=kwNVdSXMGX8&t=20s) | 4-minute video on implementing Optimizely Agent with example microservices | ## Running locally via Docker @@ -38,8 +37,9 @@ Then start the service in the foreground with the following command: ```bash docker run -p 8080:8080 --env OPTIMIZELY_LOG_PRETTY=true optimizely/agent ``` + Note that we're enabling "pretty" logs which provide colorized and human readable formatting. -The default log output format is structured JSON. +The default log output format is structured JSON. ## Evaluating REST APIs @@ -85,4 +85,4 @@ resp = s.post(url = 'http://localhost:8080/v1/activate', params=params, json=pay print(resp.json()) ``` -The activate API is a POST to signal to the caller that there are side-effects. Namely, activation results in a "decision" event sent to Optimizely analytics for the purpose of analyzing Feature Test results. A "decision" will NOT be sent if the feature is simply part of a rollout. +The activate API is a POST to signal to the caller that there are side-effects. Namely, activation results in a "decision" event sent to Optimizely analytics for the purpose of analyzing Feature Test results. A "decision" will NOT be sent if the feature is simply part of a rollout. diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/020 - setup-optimizely-agent.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/020 - setup-optimizely-agent.md index c051a3c9..bcc2fdb7 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/020 - setup-optimizely-agent.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/020 - setup-optimizely-agent.md @@ -3,23 +3,26 @@ title: "Install Optimizely Agent" excerpt: "" slug: "setup-optimizely-agent" hidden: false -metadata: - title: "Install Agent - Optimizely Full Stack" +metadata: + title: "Install Agent - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:27.363Z" updatedAt: "2020-03-31T23:54:17.841Z" --- + ## Running Agent from source (Linux / OSX) To develop and compile Optimizely Agent from source: -1. Install [Golang](https://golang.org/dl/) version 1.20+ . -2. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent). +1. Install [Golang](https://golang.org/dl/) version 1.20+ . +2. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent). 3. From the repo directory, open a terminal and start Optimizely Agent: ```bash make setup ``` + Then + ```bash make run ``` @@ -31,7 +34,7 @@ This starts the Optimizely Agent with the default configuration in the foregroun You can use a [helper script](https://github.com/optimizely/agent/blob/master/scripts/build.ps1) to install prerequisites (Golang, Git) and compile agent in a Windows environment. Take these steps: 1. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent) -2. From the repo directory, open a Powershell terminal and run +2. From the repo directory, open a Powershell terminal and run ```bash Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser @@ -50,6 +53,7 @@ If you have Docker installed, you can start Optimizely Agent as a container. Tak ```bash docker pull optimizely/agent ``` + By default this will pull the "latest" tag. You can also specify a specific version of Agent by providing the version as a tag to the docker command: ```bash @@ -61,15 +65,18 @@ docker pull optimizely/agent:X.Y.Z ```bash docker run -p 8080:8080 optimizely/agent ``` + This will start Agent in the foreground and expose the container API port 8080 to the host. 3. (Optional) You can alter the configuration by passing in environment variables to the preceding command, without having to create a config.yaml file. See [configure optimizely agent](doc:configure-optimizely-agent) for more options. Versioning: When a new version is released, 2 images are pushed to dockerhub. They are distinguished by their tags: + - :latest (same as :X.Y.Z) - :alpine (same as :X.Y.Z-alpine) The difference between latest and alpine is that latest is built `FROM scratch` while alpine is `FROM alpine`. + - [latest Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.static) -- [alpine Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.alpine) \ No newline at end of file +- [alpine Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.alpine) diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md index 0bf59ca2..8ab88a9f 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md @@ -3,16 +3,17 @@ title: "Evaluate REST APIs" excerpt: "" slug: "evaluate-rest-apis" hidden: false -metadata: - title: "Evaluate REST APIs - Optimizely Full Stack" +metadata: + title: "Evaluate REST APIs - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:53.019Z" updatedAt: "2020-04-13T23:02:34.056Z" --- + Below is an example demonstrating the APIs capabilities. For brevity, we've chosen to illustrate the API usage with Python. Note that the API documentation is defined via an OpenAPI (Swagger) spec and can be viewed [here](https://library.optimizely.com/docs/api/agent/v1/index.html). ## Start an http session -Each request made into Optimizely Agent is in the context of an Optimizely SDK Key. SDK Keys map API requests to a specific Optimizely Project and Environment. We can setup a global request header by using the `requests.Session` object. +Each request made into Optimizely Agent is in the context of an Optimizely SDK Key. SDK Keys map API requests to a specific Optimizely Project and Environment. We can setup a global request header by using the `requests.Session` object. ```python import requests @@ -20,9 +21,11 @@ import requests s = requests.Session() s.headers.update({'X-Optimizely-SDK-Key': 'YOUR-SDK-KEY'}) ``` + The following examples will assume this session is being maintained. ## Get current environment configuration + The `/v1/config` endpoint returns a manifest of the current working environment. ```python @@ -34,11 +37,11 @@ for key in env['featuresMap']: ``` ## Run flag rules + The `POST /v1/decide?keys={flagKey}` endpoint activates the feature for a given user. In Optimizely, activation is in the context of a given user to make the relative bucketing decision. In this case we'll provide a `userId` via the request body. The `userId` will be used to determine how the feature will be evaluated. Features can either be part of a Feature Test in which variations of feature variables are being measured against one another or a feature rollout, which progressively make the feature available to the selected audience. From an API standpoint the presence of a Feature Test or Rollout is abstracted away from the response and only the resulting variation or enabled feature is returned. - ```python # single feature activate params = { "featureKey": "my-feature" } @@ -56,4 +59,5 @@ params = { resp2 = s.post(url = 'http://localhost:8080/v1/activate', params=params, json=payload) print(json.dumps(resp.json(), indent=4, sort_keys=True)) ``` + The activate API is a POST to signal to the caller that there are side-effects. Namely, activation results in a "decision" event sent to Optimizely analytics for the purpose of analyzing Feature Test results. A "decision" will NOT be sent if the feature is simply part of a rollout. diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md index 9aefdfba..c150d327 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md @@ -3,11 +3,12 @@ title: "Admin API" excerpt: "" slug: "admin-api" hidden: false -metadata: - title: "Admin APIs - Optimizely Full Stack" +metadata: + title: "Admin APIs - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:28.054Z" updatedAt: "2020-02-21T23:09:19.274Z" --- + The Admin API provides system information about the running process. This can be used to check the availability of the service, runtime information and operational metrics. By default the admin listener is configured on port 8088. ## Info @@ -15,16 +16,18 @@ The Admin API provides system information about the running process. This can be The `/info` endpoint provides basic information about the Optimizely Agent instance. Example Request: + ```bash curl localhost:8088/info ``` Example Response: + ```json { - "version": "v0.10.0", - "author": "Optimizely Inc.", - "app_name": "optimizely" + "version": "v0.10.0", + "author": "Optimizely Inc.", + "app_name": "optimizely" } ``` @@ -33,14 +36,16 @@ Example Response: The `/health` endpoint is used to determine service availability. Example Request: + ```bash curl localhost:8088/health ``` Example Response: + ```json { - "status": "ok" + "status": "ok" } ``` @@ -54,11 +59,13 @@ This endpoint can used when placing Agent behind a load balancer to indicate whe The `/metrics` endpoint exposes telemetry data of the running Optimizely Agent. The core runtime metrics are exposed via the go expvar package. Documentation for the various statistics can be found as part of the [mstats](https://golang.org/src/runtime/mstats.go) package. Example Request: + ```bash curl localhost:8088/metrics ``` Example Response: + ```json { "cmdline": [ @@ -77,6 +84,7 @@ Example Response: ... } ``` + Custom metrics are also provided for the individual service endpoints and follow the pattern of: ```bash @@ -86,4 +94,4 @@ Custom metrics are also provided for the individual service endpoints and follow "timers..responseTimeHist.p90": 0, "timers..responseTimeHist.p95": 0, "timers..responseTimeHist.p99": 0, -``` \ No newline at end of file +``` diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/index.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/index.md index 604508f8..9d1a1e36 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/index.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/030 - use-optimizely-agent/index.md @@ -3,8 +3,8 @@ title: "Use Optimizely Agent" excerpt: "" slug: "use-optimizely-agent" hidden: false -metadata: - title: "How to use Optimizely Agent - Optimizely Full Stack" +metadata: + title: "How to use Optimizely Agent - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:28.054Z" updatedAt: "2020-04-08T21:26:30.308Z" --- @@ -13,16 +13,15 @@ Optimizely Agent provides [APIs](https://library.optimizely.com/docs/api/agent/v ### Manage features - Optimizely Agent simplifies the core feature management of our [SDK APIs](doc:sdk-reference-guides). It consolidates the following endpoints: +Optimizely Agent simplifies the core feature management of our [SDK APIs](doc:sdk-reference-guides). It consolidates the following endpoints: - [isFeatureEnabled](doc:is-feature-enabled-go) - [getFeatureVariableBoolean](doc:get-feature-variable-go#section-boolean) - [getFeatureVariableDouble](doc:get-feature-variable-go#section-double) - [getFeatureVariableInteger](doc:get-feature-variable-go#section-integer) -- [getFeatureVariableString](doc:get-feature-variable-go#section-string) +- [getFeatureVariableString](doc:get-feature-variable-go#section-string) - [getEnabledFeatures](doc:get-enabled-features-go) - ... into one, convenient endpoint: `POST /v1/activate?featureKey={featureKey}` @@ -30,34 +29,31 @@ Optimizely Agent provides [APIs](https://library.optimizely.com/docs/api/agent/v This [endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/activate) returns: - the decision for this feature for this user -- any corresponding feature variable values. +- any corresponding feature variable values. -For example: +For example: ```json { - "featureKey": "feature-key-1", - "enabled": true, - "variables": { - "my-var-1": "cust-val-1", - "my-var-2": "cust-va1-2" - } + "featureKey": "feature-key-1", + "enabled": true, + "variables": { + "my-var-1": "cust-val-1", + "my-var-2": "cust-va1-2" + } } ``` -The response is determined by the [feature tests](doc:run-feature-tests) and [feature rollouts](doc:use-feature-flags) defined for the supplied feature key, following the same rules as any Full Stack SDK. +The response is determined by the [feature tests](doc:run-feature-tests) and [feature rollouts](doc:use-feature-flags) defined for the supplied feature key, following the same rules as any Feature Experimentation SDK. Note: If the user is assigned to a feature test, this API will dispatch an impression. ### Authentication - -To authenticate, [pass your SDK key](https://docs.developers.optimizely.com/full-stack/docs/evaluate-rest-apis#section-start-an-http-session) as a header named ```X-Optimizely-SDK-Key``` in your API calls to Optimizely Agent. You can find your SDK key in app.optimizely.com under Settings > Environments > SDK Key. Remember you have a different SDK key for each environment. - +To authenticate, [pass your SDK key](https://docs.developers.optimizely.com/full-stack/v4.0/docs/quickstart-for-agent#start-an-http-session) as a header named `X-Optimizely-SDK-Key` in your API calls to Optimizely Agent. You can find your SDK key in app.optimizely.com under Settings > Environments > SDK Key. Remember you have a different SDK key for each environment. ### Running A/B tests - To activate an A/B test, use: `POST /v1/activate?experimentKey={experimentKey}` @@ -67,33 +63,34 @@ This dispatches an impression and return the user’s assigned variation: `POST /v1/activate?experimentKey={experimentKey}` This dispatches an impression and return the user’s assigned variation: + ```json { "experimentKey": "experiment-key-1", "variationKey": "variation-key-1" } ``` + ### Get All Decisions + To get all Feature decisions for a visitor in a single request use: `POST /v1/activate?type=feature` -To receive only the enabled features for a visitor use: +To receive only the enabled features for a visitor use: `POST /v1/activate?type=feature&enabled=true` To get all Experiment decisions for a visitor in a single request use: `POST /v1/activate?type=experiment` - - ### Tracking conversions -To track events, use the same [tracking endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/trackEvent) you use in the [SDKs' track API](doc:track-javascript): +To track events, use the same [tracking endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/trackEvent) you use in the [SDKs' track API](doc:track-javascript): `POST /v1/track?eventKey={eventKey}` There is no response body for successful conversion event requests. -### API reference +### API reference - For more details on Optimizely Agent’s APIs, see the [complete API Reference](https://library.optimizely.com/docs/api/agent/v1/index.html). \ No newline at end of file +For more details on Optimizely Agent’s APIs, see the [complete API Reference](https://library.optimizely.com/docs/api/agent/v1/index.html). diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md index df731365..4987402b 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md @@ -3,42 +3,47 @@ title: "Authorization" excerpt: "" slug: "authorization" hidden: false -metadata: - title: "Agent Authorization - Optimizely Full Stack" +metadata: + title: "Agent Authorization - Optimizely Feature Experimentation" createdAt: "2020-03-11T20:58:11.777Z" updatedAt: "2020-03-31T19:44:52.119Z" --- + Optimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. There are three modes of operation: ## 1. Issuer & Validator -Access tokens are issued by Agent itself, using a [Client Credentials grant](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/). Access tokens are signed and validated using the HS256 algorithm with a signing secret provided in configuration. Clients request access tokens by sending a `POST` request to `/oauth/token` on the port of the desired interface (by default, `8080` for the API interface, and `8088` for the Admin interface), including a client ID and secret in the request. +Access tokens are issued by Agent itself, using a [Client Credentials grant](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/). Access tokens are signed and validated using the HS256 algorithm with a signing secret provided in configuration. Clients request access tokens by sending a `POST` request to `/oauth/token` on the port of the desired interface (by default, `8080` for the API interface, and `8088` for the Admin interface), including a client ID and secret in the request. Issuer & Validator mode is useful if you want to implement authorization, and you are not already running an authorization server that can issue JWTs. ## 2. Validator-only + Agent validates access tokens that were issued elsewhere. Access tokens are validated with public keys fetched from a [JWKS](https://tools.ietf.org/html/rfc7517) URL provided in configuration. Validator-only mode is useful if you want to plug directly into an existing JWT-based workflow already being used in your system or organization. ## 3. No authorization (default) + The interface is publicly available. # Configuration + - The API and Admin interfaces are each independently configured to run in one of the above-mentioned modes of operation. - Authorization configuration is located under the `auth` key - Each mode of operation has its own set of configuration properties, described below. ## Issuer & Validator + The configuration properties pertaining to Issuer & Validator mode are listed below: -|Property Name|Environment Variable|Description| -|---|---|---| -|ttl|TTL|Time-to-live of access tokens issued| -|hmacSecrets|HMACSECRETS|Array of secrets used to sign & validate access tokens, using the HMAC SHA256 algorithm. Values must be base64-format strings. The first value in the array is used to sign issued access tokens. Access tokens signed with any value in the array are considered valid.| -|clients|N/A|Array of objects, used for token issuance, consisting of `id`, `secretHash`, and `sdkKeys`. Clients provide ID and secret in their requests to `/oauth/token`. Agent validates the request credentials by checking for an exact match of ID, checking that the BCrypt hash of the request secret matches the `secretHash` from configuration, and that the SDK key provided in the `X-Optimizely-Sdk-Key` request header exists in the `sdkKeys` from configuration. `secretHash` values must be base64-format strings.| +| Property Name | Environment Variable | Description | +| ------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ttl | TTL | Time-to-live of access tokens issued | +| hmacSecrets | HMACSECRETS | Array of secrets used to sign & validate access tokens, using the HMAC SHA256 algorithm. Values must be base64-format strings. The first value in the array is used to sign issued access tokens. Access tokens signed with any value in the array are considered valid. | +| clients | N/A | Array of objects, used for token issuance, consisting of `id`, `secretHash`, and `sdkKeys`. Clients provide ID and secret in their requests to `/oauth/token`. Agent validates the request credentials by checking for an exact match of ID, checking that the BCrypt hash of the request secret matches the `secretHash` from configuration, and that the SDK key provided in the `X-Optimizely-Sdk-Key` request header exists in the `sdkKeys` from configuration. `secretHash` values must be base64-format strings. | To make setup easier, Agent provides a command-line tool that can generate base64-encoded 32-byte random values, and their associated base64-encoded BCrypt hashes: @@ -48,25 +53,32 @@ To make setup easier, Agent provides a command-line tool that can generate base6 Client Secret: i3SrdrCy/wEGqggv9OI4FgIsdHHNpOacrmIMJ6SFIkE= Client Secret's hash: JDJhJDEyJERGNzhjRXVTNTdOQUZ3cndxTkZ6Li5XQURlazU2R21YeFZjb1pWSkN5eGZ1SXM4VXRLb0ZD ``` + Use the hash value to configure Agent, and pass the secret value as `client_secret` when making access token requests to `/oauth/token`. For details of the access token issuance endpoint, see the OpenAPI spec file. ## Validator-only + The configuration properties pertaining to Validator-only mode are listed below: -|Property Name|Environment Variable|Description| -|---|---|---| -|jwksURL|JWKSURL|URL from which public keys should be fetched for token validation| -|jwksUpdateInterval|JWKSUPDATEINTERVAL|Interval on which public keys should be re-fetched (example: `30m` for 30 minutes)| +| Property Name | Environment Variable | Description | +| ------------------ | -------------------- | ---------------------------------------------------------------------------------- | +| jwksURL | JWKSURL | URL from which public keys should be fetched for token validation | +| jwksUpdateInterval | JWKSUPDATEINTERVAL | Interval on which public keys should be re-fetched (example: `30m` for 30 minutes) | ## No authorization (default) + The API & Admin interfaces run with no authorization when no `auth` configuration is given. ## Configuration examples + Optimizely Agent uses the [Viper](https://github.com/spf13/viper) library for configuration, which allows setting values via environment variables, flags, and YAML configuration files. + ### Issuer & Validator + _*WARNING*_: For security, we advise that you configure `hmacSecrets` with either an environment variable or a flag, and NOT through a config file. In the below example, the Admin interface is configured in Issuer & Validator mode, with `hmacSecrets` provided via environment variable, and other values provided via YAML config file. + ```shell // Comma-separated value, to set multiple hmacSecrets. // Access tokens are signed with the first value. @@ -82,35 +94,39 @@ admin: clients: # Either of these two id/secret pairs can be exchanged for access tokens - id: agentConsumer1 - secretHash: XgZTeTvWaZ6fLiey6EBSOxJ2QFdd6dIiUcZGDIIJ+IY + secretHash: XgZTeTvWaZ6fLiey6EBSOxJ2QFdd6dIiUcZGDIIJ+IY sdkKeys: # These credentials can be exchanged for tokens granting access to these two SDK keys - abcd1234 - efgh5678 - id: agentConsumer2 - secretHash: ssz0EEViKIinkFXxzqncKxz+6VygEc2d2rKf+la5rXM + secretHash: ssz0EEViKIinkFXxzqncKxz+6VygEc2d2rKf+la5rXM sdkKeys: # These credentials can be exchanged for tokens granting access only to this one SDK key - ijkl9012 ``` ### Validator-only + ```yaml # In this example, the API interface is configured in Validator-only mode api: - auth: - # Signing keys will be fetched from this url and used when validating access tokens - jwksURL: https://YOUR_DOMAIN/.well-known/jwks.json - # Siging keys will be periodically fetched on this interval - jwksUpdateInterval: 30m + auth: + # Signing keys will be fetched from this url and used when validating access tokens + jwksURL: https://YOUR_DOMAIN/.well-known/jwks.json + # Siging keys will be periodically fetched on this interval + jwksUpdateInterval: 30m ``` # Secret Rotation (Issuer & Validator mode) + To support secret rotation, both `hmacSecrets` and `clients` support setting multiple values. In `hmacSecrets`, the first value will be used to sign issued tokens, but tokens signed with any of the values will be considered valid. # Example (Python) + Example requests demonstrating the Issuer & Validator mode: + ```python #!/usr/bin/python @@ -185,4 +201,4 @@ s.headers.update({'Authorization': 'Bearer {}'.format(resp_dict['access_token']) resp = s.get('http://localhost:8080/v1/config') print('config response after passing access token: ') print(json.dumps(resp.json(), indent=4, sort_keys=True)) -``` \ No newline at end of file +``` diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md index cbd14cb3..6f06ca6d 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md @@ -3,12 +3,13 @@ title: "Webhooks" excerpt: "" slug: "webhooks-agent" hidden: false -metadata: - title: "Agent microservice webhooks - Optimizely Full Stack" +metadata: + title: "Agent microservice webhooks - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:26.981Z" updatedAt: "2020-05-05T17:03:48.045Z" --- -Optimizely Agent implements a webhook listener used to receive inbound [Webhook](doc:configure-webhooks) requests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates. + +Optimizely Agent implements a webhook listener used to receive inbound [Webhook](doc:configure-webhooks) requests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates. The webhook listener is configured on its own port (default: 8085) since it can be configured to select traffic from the internet. To accept webhook requests Agent must be configured by mapping an Optimizely Project Id to a set of SDK keys along @@ -20,8 +21,8 @@ with the associated secret used for validating the inbound request. An example w ## trigger an immediate download of the datafile from the CDN ## webhook: - ## http listener port - port: "8089" + ## http listener port + port: "8089" # ## a map of Optimizely Projects to one or more SDK keys # projects: # ## : Optimizely project id as an integer @@ -38,4 +39,4 @@ webhook: ## Next -[Create Webhooks](https://docs.developers.optimizely.com/full-stack/docs/webhooks-agent) +[Create Webhooks](https://docs.developers.optimizely.com/full-stack/v4.0/docs/webhooks-agent) diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md index f986333b..95cb7b54 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md @@ -1,17 +1,17 @@ --- -title: Agent Notifications +title: Agent Notifications excerpt: "" slug: "agent-notifications" hidden: false -metadata: - title: "Agent notifications - Optimizely Full Stack" +metadata: + title: "Agent notifications - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2020-07-14T20:51:52.458Z" --- Agent provides an endpoint that sends notifications to subscribers via [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). This is Agent's equivalent of Notification Listeners found in Optimizely SDKs. -For details on the notification types, what causes them to be triggered, and the data they provide, see the [Notification Listeners documentation](https://docs.developers.optimizely.com/full-stack/docs/set-up-notification-listener-go). +For details on the notification types, what causes them to be triggered, and the data they provide, see the [Notification Listeners documentation](https://docs.developers.optimizely.com/full-stack/v4.0/docs/set-up-notification-listener-go). ## Configuration @@ -41,7 +41,6 @@ curl -N -H "Accept:text/event-stream" -H "X-Optimizely-Sdk-Key:"\ This connection will remain open, and any notifications triggered by other requests received by Agent are pushed as events to this stream. Try sending requests to `/v1/activate` or `/v1/track` to see notifications being triggered. - ### Filtering To subscribe only to a particular category of notifications, add a `filter` query parameter. For example, to subscribe only to Decision notifications: diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md index 24e30804..776e4012 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md @@ -3,8 +3,8 @@ title: "Advanced configuration" excerpt: "" slug: "advanced-config-agent" hidden: false -metadata: - title: "advanced config - Agent microservice - Optimizely Full Stack" +metadata: + title: "advanced config - Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2020-07-14T20:51:52.458Z" --- diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md index db908946..6d4c708e 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md @@ -4,7 +4,7 @@ excerpt: "" slug: "agent-plugins" hidden: false metadata: - title: "Agent plugins - Optimizely Full Stack" + title: "Agent plugins - Optimizely Feature Experimentation" createdAt: "2020-09-21T20:30:00.000Z" updatedAt: "2020-09-21T20:30:00.000Z" --- @@ -19,9 +19,10 @@ Interceptors can be added to Agent to customize the request and/or response by i This interface defines a `Handler()` method that returns a standard net/http middleware handler based on [http.Handler](https://golang.org/pkg/net/http/#Handler). The interceptor struct can also include a set of fields that can be configured via `config.yaml`. -* [httplog](https://github.com/optimizely/agent/tree/master/plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). +- [httplog](https://github.com/optimizely/agent/tree/master/plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). ### Example Interceptor definition + ```go package example @@ -66,6 +67,7 @@ func init() { ``` To make the interceptor available to Agent, add the plugin as an anonymous import into [all.go](./interceptors/all/all.go). + ```go package all @@ -76,6 +78,7 @@ import ( ``` Enable the example interceptor by adding to `server.interceptors` within your `config.yaml`. Note that the yaml fields should match the struct definition of your plugin. + ```yaml server: interceptors: diff --git a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md index ab849349..007cc0ad 100644 --- a/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md +++ b/docs/readme-sync/v3.1/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md @@ -3,12 +3,13 @@ title: "Configure Optimizely Agent" excerpt: "" slug: "configure-optimizely-agent" hidden: false -metadata: - title: "Configure Agent microservice - Optimizely Full Stack" +metadata: + title: "Configure Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:27.173Z" updatedAt: "2020-04-08T21:42:08.698Z" --- -By default Optimizely Agent uses the configuration file in the current active directory, e.g., `./config.yaml`. You can override the [default configuration](https://github.com/optimizely/agent/blob/master/config.yaml) by providing a yaml configuration file at runtime. + +By default Optimizely Agent uses the configuration file in the current active directory, e.g., `./config.yaml`. You can override the [default configuration](https://github.com/optimizely/agent/blob/master/config.yaml) by providing a yaml configuration file at runtime. You can specify alternative configuration locations at runtime via an environment variable or command line flag: @@ -16,41 +17,40 @@ You can specify alternative configuration locations at runtime via an environmen OPTIMIZELY_CONFIG_FILENAME=config.yaml make run ``` - Below is a comprehensive list of available configuration properties. -|Property Name|Env Variable|Description| -|---|---|---| -|admin.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.jwksURL|OPTIMIZELY_ADMIN_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.jwksUpdateInterval|OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization)| -|admin.auth.hmacSecrets|OPTIMIZELY_ADMIN_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.ttl|OPTIMIZELY_ADMIN_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization)| -|admin.port|OPTIMIZELY_ADMIN_PORT|Admin listener port. Default: 8088| -|api.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.hmacSecrets|OPTIMIZELY_API_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.jwksURL|OPTIMIZELY_API_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.jwksUpdateInterval|OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization)| -|api.auth.ttl|OPTIMIZELY_API_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization)| -|api.port|OPTIMIZELY_API_PORT|Api listener port. Default: 8080| -|api.maxConns|OPTIMIZLEY_API_MAXCONNS|Maximum number of concurrent requests| -|author|OPTIMIZELY_AUTHOR|Agent author. Default: Optimizely Inc.| -|certfile|OPTIMIZELY_CERTFILE|Path to a certificate file, used to run Agent with HTTPS| -|client.batchSize|OPTIMIZELY_CLIENT_BATCHSIZE|The number of events in a batch. Default: 10| -|config.filename|OPTIMIZELY_CONFIG_FILENAME|Location of the configuration YAML file. Default: ./config.yaml| -|client.flushInterval|OPTIMIZELY_CLIENT_FLUSHINTERVAL|The maximum time between events being dispatched. Default: 30s| -|client.pollingInterval|OPTIMIZELY_CLIENT_POLLINGINTERVAL|The time between successive polls for updated project configuration. Default: 1m| -|client.queueSize|OPTIMIZELY_CLIENT_QUEUESIZE|The max number of events pending dispatch. Default: 1000| -|disabledCiphers|OPTIMIZELY_DISABLEDCIPHERS|List of TLS ciphers to disable when accepting HTTPS connections| -|keyfile|OPTIMIZELY_KEYFILE|Path to a key file, used to run Agent with HTTPS| -|log.level|OPTIMIZELY_LOG_LEVEL|The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info| -|log.pretty|OPTIMIZELY_LOG_PRETTY|Flag used to set colorized console output as opposed to structured json logs. Default: false| -|name|OPTIMIZELY_NAME|Agent name. Default: optimizely| -|version|OPTIMIZELY_VERSION|Agent version. Default: `git describe --tags`| -|sdkKeys|OPTIMIZELY_SDKKEYS|Comma delimited list of SDK keys used to initialize on startup| -|server.readTimeout|OPTIMIZELY_SERVER_READTIMEOUT|The maximum duration for reading the entire body. Default: “5s”| -|server.writeTimeout|OPTIMIZELY_SERVER_WRITETIMEOUT|The maximum duration before timing out writes of the response. Default: “10s”| -|webhook.port|OPTIMIZELY_WEBHOOK_PORT|Webhook listener port: Default: 8085| -|webhook.projects.<*projectId*>.sdkKeys|N/A|Comma delimited list of SDK keys applicable to the respective projectId| -|webhook.projects.<*projectId*>.secret|N/A|Webhook secret used to validate webhook requests originating from the respective projectId| -|webhook.projects.<*projectId*>.skipSignatureCheck|N/A|Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret.| +| Property Name | Env Variable | Description | +| ------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| admin.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.jwksURL | OPTIMIZELY_ADMIN_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.jwksUpdateInterval | OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization) | +| admin.auth.hmacSecrets | OPTIMIZELY_ADMIN_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.ttl | OPTIMIZELY_ADMIN_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization) | +| admin.port | OPTIMIZELY_ADMIN_PORT | Admin listener port. Default: 8088 | +| api.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.hmacSecrets | OPTIMIZELY_API_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.jwksURL | OPTIMIZELY_API_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.jwksUpdateInterval | OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization) | +| api.auth.ttl | OPTIMIZELY_API_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization) | +| api.port | OPTIMIZELY_API_PORT | Api listener port. Default: 8080 | +| api.maxConns | OPTIMIZLEY_API_MAXCONNS | Maximum number of concurrent requests | +| author | OPTIMIZELY_AUTHOR | Agent author. Default: Optimizely Inc. | +| certfile | OPTIMIZELY_CERTFILE | Path to a certificate file, used to run Agent with HTTPS | +| client.batchSize | OPTIMIZELY_CLIENT_BATCHSIZE | The number of events in a batch. Default: 10 | +| config.filename | OPTIMIZELY_CONFIG_FILENAME | Location of the configuration YAML file. Default: ./config.yaml | +| client.flushInterval | OPTIMIZELY_CLIENT_FLUSHINTERVAL | The maximum time between events being dispatched. Default: 30s | +| client.pollingInterval | OPTIMIZELY_CLIENT_POLLINGINTERVAL | The time between successive polls for updated project configuration. Default: 1m | +| client.queueSize | OPTIMIZELY_CLIENT_QUEUESIZE | The max number of events pending dispatch. Default: 1000 | +| disabledCiphers | OPTIMIZELY_DISABLEDCIPHERS | List of TLS ciphers to disable when accepting HTTPS connections | +| keyfile | OPTIMIZELY_KEYFILE | Path to a key file, used to run Agent with HTTPS | +| log.level | OPTIMIZELY_LOG_LEVEL | The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info | +| log.pretty | OPTIMIZELY_LOG_PRETTY | Flag used to set colorized console output as opposed to structured json logs. Default: false | +| name | OPTIMIZELY_NAME | Agent name. Default: optimizely | +| version | OPTIMIZELY_VERSION | Agent version. Default: `git describe --tags` | +| sdkKeys | OPTIMIZELY_SDKKEYS | Comma delimited list of SDK keys used to initialize on startup | +| server.readTimeout | OPTIMIZELY_SERVER_READTIMEOUT | The maximum duration for reading the entire body. Default: “5s” | +| server.writeTimeout | OPTIMIZELY_SERVER_WRITETIMEOUT | The maximum duration before timing out writes of the response. Default: “10s” | +| webhook.port | OPTIMIZELY_WEBHOOK_PORT | Webhook listener port: Default: 8085 | +| webhook.projects.<_projectId_>.sdkKeys | N/A | Comma delimited list of SDK keys applicable to the respective projectId | +| webhook.projects.<_projectId_>.secret | N/A | Webhook secret used to validate webhook requests originating from the respective projectId | +| webhook.projects.<_projectId_>.skipSignatureCheck | N/A | Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret. | diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/010 - optimizely-agent.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/010 - optimizely-agent.md index 13779717..67fe1be1 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/010 - optimizely-agent.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/010 - optimizely-agent.md @@ -3,76 +3,88 @@ title: "Optimizely Agent" excerpt: "" slug: "optimizely-agent" hidden: false -metadata: - title: "Optimizely Agent microservice - Optimizely Full Stack" +metadata: + title: "Optimizely Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-02-21T20:35:58.387Z" updatedAt: "2021-03-15T23:02:34.056Z" --- -Optimizely Agent is a standalone, open-source, and highly available microservice that provides major benefits over using Optimizely SDKs in certain use cases. The [Agent REST API](https://library.optimizely.com/docs/api/agent/v1/index.html) offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Full Stack SDKs. + +Optimizely Agent is a standalone, open-source, and highly available microservice that provides major benefits over using Optimizely SDKs in certain use cases. The [Agent REST API](https://library.optimizely.com/docs/api/agent/v1/index.html) offers consolidated and simplified endpoints for accessing all the functionality of Optimizely Feature Experimentation SDKs. A typical production installation of Optimizely Agent is to run two or more services behind a load balancer or proxy. The service itself can be run via a Docker container or installed from source. See [Setup Optimizely Agent](doc:setup-optimizely-agent) for instructions on how to run Optimizely Agent. ### Example Implementation + ![example implementation](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-example-implementation.png) + # Should I Use Optimizely Agent? Here are some of the top reasons to consider using Optimizely Agent: ## 1. Service Oriented Architecture (SOA) -If you already separate some of your logic into services that might need to access the Optimizely decision APIs, we recommend using Optimizely Agent. -The images below compare implementation styles in a service-oriented architecture, first *without* using Optimizely Agent, which shows six SDK embedded instances: +If you already separate some of your logic into services that might need to access the Optimizely decision APIs, we recommend using Optimizely Agent. + +The images below compare implementation styles in a service-oriented architecture, first _without_ using Optimizely Agent, which shows six SDK embedded instances: !["A diagram showing the use of SDKs installed on each service in a service oriented architecture \n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-service-oriented-architecture.png) -Now *with* Agent, instead of installing the SDK six times, you create just one Optimizely instance: an HTTP API that every service can access as needed. +Now _with_ Agent, instead of installing the SDK six times, you create just one Optimizely instance: an HTTP API that every service can access as needed. !["A diagram showing the use of Optimizely Agent in a single service \n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-single-service.png) ## 2. Standardize Access Across Teams -If you want to deploy Optimizely Full Stack once, then roll out the single implementation across a large number of teams, we recommend using Optimizely Agent. + +If you want to deploy Optimizely Feature Experimentation once, then roll out the single implementation across a large number of teams, we recommend using Optimizely Agent. By standardizing your teams' access to the Optimizely service, you can better enforce processes and implement governance around feature management and experimentation as a practice. !["A diagram showing the central and standardized access to the Optimizely Agent service across an arbitrary number of teams.\n(Click to Enlarge)"](https://raw.githubusercontent.com/optimizely/agent/master/docs/images/agent-standardized-access.png) ## 3. Networking Centralization -You don’t want many SDK instances connecting to Optimizely's cloud service from every node in your application. Optimizely Agent centralizes your network connection. Only one cluster of agent instances connects to Optimizely for tasks like update [datafiles](doc:get-the-datafile) and dispatch [events](doc:track-events). + +You don’t want many SDK instances connecting to Optimizely's cloud service from every node in your application. Optimizely Agent centralizes your network connection. Only one cluster of agent instances connects to Optimizely for tasks like update [datafiles](doc:get-the-datafile) and dispatch [events](doc:track-events). ## 4. Languages -You’re using a language that isn’t supported by a native SDK (i.e. Elixir, Scala, Perl). While its possible to create your own service using an Optimizely SDK of your choice, you could also customize the open-source Optimizely Agent to your needs without building the service layer on your own. +You’re using a language that isn’t supported by a native SDK (i.e. Elixir, Scala, Perl). While its possible to create your own service using an Optimizely SDK of your choice, you could also customize the open-source Optimizely Agent to your needs without building the service layer on your own. + +# Reasons to _not_ use Optimizely Agent -# Reasons to *not* use Optimizely Agent -If your use case wouldn't benefit greatly from Optimizely Agent, you should consider the below reasons to *not* use Optimizely Agent and review Optimizely's many [open-source SDKs](doc:sdk-reference-guides) instead. +If your use case wouldn't benefit greatly from Optimizely Agent, you should consider the below reasons to _not_ use Optimizely Agent and review Optimizely's many [open-source SDKs](doc:sdk-reference-guides) instead. ## 1. Latency -If time to provide bucketing decisions is a primary concern for you, you may want to use an embedded Full Stack SDK rather than Optimizely Agent. +If time to provide bucketing decisions is a primary concern for you, you may want to use an embedded Feature Experimentation SDK rather than Optimizely Agent. | Implementation Option | Decision Latency | -|-----------------------|------------------| +| --------------------- | ---------------- | | Embedded SDK | microseconds | | Optimizely Agent | milliseconds | ## 2. Monolith -If your app is constructed as a monolith, embedded SDKs might be easier to install and might be a more natural fit for your application and development practices. + +If your app is constructed as a monolith, embedded SDKs might be easier to install and might be a more natural fit for your application and development practices. ## 3. Velocity -If you’re looking for the fastest way to get a single team up and running with deploying feature management and experimentation, embedding an SDK is the best option for you at first. You can always start using Optimizely Agent later, and it can even be used alongside Optimizely Full Stack SDKs running in another part of your stack. + +If you’re looking for the fastest way to get a single team up and running with deploying feature management and experimentation, embedding an SDK is the best option for you at first. You can always start using Optimizely Agent later, and it can even be used alongside Optimizely Feature Experimentation SDKs running in another part of your stack. # Best Practices -While every implementation is different, you can review this section of best practices for tips on these commonly discussed topics. +While every implementation is different, you can review this section of best practices for tips on these commonly discussed topics. ## How many Agent instances should I deploy? + Agent can scale to large decision / event tracking volumes with relatively low CPU / memory specs. For example, at Optimizely, we scaled our deployment to 740 clients with a cluster of 12 agent instances, which in total use 6 vCPUs and 12GB RAM. You will likely need to focus more on network bandwidth than compute power. ## Using a load balancer + Any standard load balancer should let you route traffic across your agent cluster. At Optimizely, we used an AWS Elastic Load Balancer (ELB) for our internal deployment. This allows us to transparently scale our agent cluster as internal demands increase. ## Synchronizing datafiles across Agent instances + Agent offers eventual rather than strong consistency across datafiles. -In detail, today, each agent instance maintains a dedicated, separate cache. Each agent instance persists an SDK instance for each SDK key your team uses. Agent instances automatically keep datafiles up to date for each SDK key instance so that you will have eventual consistency across the cluster. The rate of the datafile update can be [set as the configuration](doc:configure-optimizely-agent) value ```OPTIMIZELY_CLIENT_POLLINGINTERVAL``` (the default is 1 minute). -Because SDKs are generally stateless today, they shouldn’t need to share data. We plan to add a common backing data store, so we invite you to share your feedback. +In detail, today, each agent instance maintains a dedicated, separate cache. Each agent instance persists an SDK instance for each SDK key your team uses. Agent instances automatically keep datafiles up to date for each SDK key instance so that you will have eventual consistency across the cluster. The rate of the datafile update can be [set as the configuration](doc:configure-optimizely-agent) value `OPTIMIZELY_CLIENT_POLLINGINTERVAL` (the default is 1 minute). +Because SDKs are generally stateless today, they shouldn’t need to share data. We plan to add a common backing data store, so we invite you to share your feedback. If you require strong consistency across datafiles, then we recommend an active / passive deployment where all requests are made to a single vertically scaled host, with a passive, standby cluster available for high availability. diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/012 - quickstart-for-agent.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/012 - quickstart-for-agent.md index 071f052b..8d33a907 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/012 - quickstart-for-agent.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/012 - quickstart-for-agent.md @@ -3,8 +3,8 @@ title: "Quickstart for Agent" excerpt: "" slug: "quickstart-for-agent" hidden: false -metadata: - title: "Quickstart for Agent - Optimizely Full Stack" +metadata: + title: "Quickstart for Agent - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2021-03-15T23:02:34.056Z" --- @@ -15,11 +15,10 @@ This brief quickstart describes how to run Agent, using two examples: - To get started using example Node microservices, see the following video link. - - ## Running locally via Node -| Resource | Description | -| ------------------------------------------------------------ | ------------------------------------------------------------ | + +| Resource | Description | +| -------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------- | | [Implementing feature flags across microservices with Optimizely Agent](https://www.youtube.com/watch?v=kwNVdSXMGX8&t=20s) | 4-minute video on implementing Optimizely Agent with example microservices | ## Running locally via Docker @@ -38,8 +37,9 @@ Then start the service in the foreground with the following command: ```bash docker run -p 8080:8080 --env OPTIMIZELY_LOG_PRETTY=true optimizely/agent ``` + Note that we're enabling "pretty" logs which provide colorized and human readable formatting. -The default log output format is structured JSON. +The default log output format is structured JSON. ## Evaluating REST APIs @@ -73,7 +73,7 @@ for key in env['featuresMap']: ### Run a feature flag rule -The `/decide?keys={keys}` endpoint decides whether to enable a feature flag or flags for a given user. You can decide multiple flags with this syntax: `/v1/decide?keys=flagA&keys=flagB`. We'll provide a `userId` via the request body. The API evaluates the `userId` to determine which flag rule and flag variation the user buckets into. Rule types include A/B tests, in which flag variations are measured against one another, or a flag delivery, which progressively make the flag available to the selected audience. +The `/decide?keys={keys}` endpoint decides whether to enable a feature flag or flags for a given user. You can decide multiple flags with this syntax: `/v1/decide?keys=flagA&keys=flagB`. We'll provide a `userId` via the request body. The API evaluates the `userId` to determine which flag rule and flag variation the user buckets into. Rule types include A/B tests, in which flag variations are measured against one another, or a flag delivery, which progressively make the flag available to the selected audience. This endpoint returns an array of `OptimizelyDecision` objects, which contains information about the flag and rule the user bucketed into. @@ -91,4 +91,4 @@ resp = s.post(url = 'http://localhost:8080/v1/decide', params=params, json=paylo print(resp.json()) ``` -The decide API is a POST to signal to the caller that there are side-effects. Namely, this endpoint results in a "decision" event sent to Optimizely analytics for the purpose of analyzing A/B test results. By default a "decision" is not sent if the feature flag is simply part of a delivery. +The decide API is a POST to signal to the caller that there are side-effects. Namely, this endpoint results in a "decision" event sent to Optimizely analytics for the purpose of analyzing A/B test results. By default a "decision" is not sent if the feature flag is simply part of a delivery. diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/020 - setup-optimizely-agent.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/020 - setup-optimizely-agent.md index 96f2c0b9..a382874b 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/020 - setup-optimizely-agent.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/020 - setup-optimizely-agent.md @@ -3,23 +3,26 @@ title: "Install Optimizely Agent" excerpt: "" slug: "setup-optimizely-agent" hidden: false -metadata: - title: "Install Agent - Optimizely Full Stack" +metadata: + title: "Install Agent - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:27.363Z" updatedAt: "2021-03-15T23:02:34.056Z" --- + ## Running Agent from source (Linux / OSX) To develop and compile Optimizely Agent from source: -1. Install [Golang](https://golang.org/dl/) version 1.20+ . -2. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent). +1. Install [Golang](https://golang.org/dl/) version 1.20+ . +2. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent). 3. From the repo directory, open a terminal and start Optimizely Agent: ```bash make setup ``` + Then + ```bash make run ``` @@ -31,7 +34,7 @@ This starts the Optimizely Agent with the default configuration in the foregroun You can use a [helper script](https://github.com/optimizely/agent/blob/master/scripts/build.ps1) to install prerequisites (Golang, Git) and compile agent in a Windows environment. Take these steps: 1. Clone the [Optimizely Agent repo](https://github.com/optimizely/agent) -2. From the repo directory, open a Powershell terminal and run +2. From the repo directory, open a Powershell terminal and run ```bash Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope CurrentUser @@ -50,6 +53,7 @@ If you have Docker installed, you can start Optimizely Agent as a container. Tak ```bash docker pull optimizely/agent ``` + By default this will pull the "latest" tag. You can also specify a specific version of Agent by providing the version as a tag to the docker command: ```bash @@ -61,15 +65,18 @@ docker pull optimizely/agent:X.Y.Z ```bash docker run -p 8080:8080 optimizely/agent ``` + This will start Agent in the foreground and expose the container API port 8080 to the host. 3. (Optional) You can alter the configuration by passing in environment variables to the preceding command, without having to create a config.yaml file. See [configure optimizely agent](doc:configure-optimizely-agent) for more options. Versioning: When a new version is released, 2 images are pushed to dockerhub. They are distinguished by their tags: + - :latest (same as :X.Y.Z) - :alpine (same as :X.Y.Z-alpine) The difference between latest and alpine is that latest is built `FROM scratch` while alpine is `FROM alpine`. + - [latest Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.static) -- [alpine Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.alpine) \ No newline at end of file +- [alpine Dockerfile](https://github.com/optimizely/agent/blob/master/scripts/dockerfiles/Dockerfile.alpine) diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md index 85715af7..02a14888 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/010 - evaluate-rest-apis.md @@ -3,16 +3,17 @@ title: "Evaluate REST APIs" excerpt: "" slug: "evaluate-rest-apis" hidden: false -metadata: - title: "Evaluate REST APIs - Optimizely Full Stack" +metadata: + title: "Evaluate REST APIs - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:53.019Z" updatedAt: "2021-03-15T23:02:34.056Z" --- + Below is an example demonstrating the APIs capabilities. For brevity, we've chosen to illustrate the API usage with Python. Note that the API documentation is defined via an OpenAPI (Swagger) spec and can be viewed [here](https://library.optimizely.com/docs/api/agent/v1/index.html). ## Start an http session -Each request made into Optimizely Agent is in the context of an Optimizely SDK Key. SDK Keys map API requests to a specific Optimizely Project and Environment. We can setup a global request header by using the `requests.Session` object. +Each request made into Optimizely Agent is in the context of an Optimizely SDK Key. SDK Keys map API requests to a specific Optimizely Project and Environment. We can setup a global request header by using the `requests.Session` object. ```python import requests @@ -20,9 +21,11 @@ import requests s = requests.Session() s.headers.update({'X-Optimizely-SDK-Key': 'YOUR-SDK-KEY'}) ``` + The following examples will assume this session is being maintained. ## Get current environment configuration + The `/v1/config` endpoint returns a manifest of the current working environment. ```python @@ -36,13 +39,14 @@ for key in env['featuresMap']: ## Run a feature flag rule The Decide [endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/decide) buckets a user into a feature flag variation (choosing between multiple enabled variations or one disabled variation) as part of a flag rule. Flag rules let you: + - experiment using A/B tests -- roll out feature flags progressively to a selected audience using targeted feature flag deliveries. +- roll out feature flags progressively to a selected audience using targeted feature flag deliveries. To run a flag rule, use ```python -# decide 1 flag. +# decide 1 flag. params = { "keys": "my-feature-flag" } payload = { "userId": "test-user", @@ -64,4 +68,5 @@ params = {"keys":"flag_1", "keys":"flag_2"} resp2 = s.post(url = 'http://localhost:8080/v1/decide', params=params, json=payload) print(json.dumps(resp.json(), indent=4, sort_keys=True)) ``` + The decide API is a POST to signal to the caller that there are side-effects. Namely, the decision results in a "decision" event sent to Optimizely analytics for the purpose of analyzing A/B test results. A decision event will NOT be sent by default if the flag is simply part of a delivery. diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md index ed571c5a..d76e7de6 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/020 - admin-api.md @@ -3,11 +3,12 @@ title: "Admin API" excerpt: "" slug: "admin-api" hidden: false -metadata: - title: "Admin APIs - Optimizely Full Stack" +metadata: + title: "Admin APIs - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:28.054Z" updatedAt: "2021-03-15T23:02:34.056Z" --- + The Admin API provides system information about the running process. This can be used to check the availability of the service, runtime information and operational metrics. By default the admin listener is configured on port 8088. ## Info @@ -15,16 +16,18 @@ The Admin API provides system information about the running process. This can be The `/info` endpoint provides basic information about the Optimizely Agent instance. Example Request: + ```bash curl localhost:8088/info ``` Example Response: + ```json { - "version": "v0.10.0", - "author": "Optimizely Inc.", - "app_name": "optimizely" + "version": "v0.10.0", + "author": "Optimizely Inc.", + "app_name": "optimizely" } ``` @@ -33,14 +36,16 @@ Example Response: The `/health` endpoint is used to determine service availability. Example Request: + ```bash curl localhost:8088/health ``` Example Response: + ```json { - "status": "ok" + "status": "ok" } ``` @@ -54,11 +59,13 @@ This endpoint can used when placing Agent behind a load balancer to indicate whe The `/metrics` endpoint exposes telemetry data of the running Optimizely Agent. The core runtime metrics are exposed via the go expvar package. Documentation for the various statistics can be found as part of the [mstats](https://golang.org/src/runtime/mstats.go) package. Example Request: + ```bash curl localhost:8088/metrics ``` Example Response: + ```json { "cmdline": [ @@ -77,6 +84,7 @@ Example Response: ... } ``` + Custom metrics are also provided for the individual service endpoints and follow the pattern of: ```bash @@ -86,4 +94,4 @@ Custom metrics are also provided for the individual service endpoints and follow "timers..responseTimeHist.p90": 0, "timers..responseTimeHist.p95": 0, "timers..responseTimeHist.p99": 0, -``` \ No newline at end of file +``` diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/index.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/index.md index 45e96b17..f707a633 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/index.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/030 - use-optimizely-agent/index.md @@ -3,17 +3,16 @@ title: "Use Optimizely Agent" excerpt: "" slug: "use-optimizely-agent" hidden: false -metadata: - title: "How to use Optimizely Agent - Optimizely Full Stack" +metadata: + title: "How to use Optimizely Agent - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:28.054Z" updatedAt: "2021-03-15T23:02:34.056Z" --- -Optimizely Agent provides [APIs](https://library.optimizely.com/docs/api/agent/v1/index.html) that enable running feature flag rules, such as A/B tests and targeted flag deliveries. Agent provides equivalent functionality to all our SDKs. At its core is the [Optimizely Go SDK](doc:go-sdk). +Optimizely Agent provides [APIs](https://library.optimizely.com/docs/api/agent/v1/index.html) that enable running feature flag rules, such as A/B tests and targeted flag deliveries. Agent provides equivalent functionality to all our SDKs. At its core is the [Optimizely Go SDK](doc:go-sdk). ### Running feature flag rules - The Decide [endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/decide) buckets a user into a feature flag variation as part of a flag rule. It chooses between multiple enabled or one disabled variation for a flag. Flag rules include A/B tests and targeted feature flag deliveries. To run a flag rule, use: `POST /v1/decide?keys={flagKey}` @@ -35,16 +34,12 @@ curl --location --request POST 'http://localhost:8080/v1/decide?keys=YOUR_FLAG_1 }' ``` - - - - This returns an array of OptimizelyDecision objects that contains all the information you need to run your flag rule, such as: -- the decision to bucket this user into an enabled or disabled feature flag variation. -- any corresponding feature flag variable values. +- the decision to bucket this user into an enabled or disabled feature flag variation. +- any corresponding feature flag variable values. -For example: +For example: ```json { @@ -67,23 +62,22 @@ For example: } ``` -The response is determined by the [A/B tests](https://docs.developers.optimizely.com/full-stack/v4.0/docs/run-a-b-tests) and [deliveries](https://docs.developers.optimizely.com/full-stack/v4.0/docs/run-flag-deliveries) defined for the supplied feature key, following the same rules as any Full Stack SDK. +The response is determined by the [A/B tests](https://docs.developers.optimizely.com/full-stack/v4.0/docs/run-a-b-tests) and [deliveries](https://docs.developers.optimizely.com/full-stack/v4.0/docs/run-flag-deliveries) defined for the supplied feature key, following the same rules as any Feature Experimentation SDK. Note: If the user is bucketed into an A/B test, this endpoint dispatches a decision event. ### Authentication - -To authenticate, [pass your SDK key](https://docs.developers.optimizely.com/full-stack/docs/evaluate-rest-apis#section-start-an-http-session) as a header named ```X-Optimizely-SDK-Key``` in your API calls to Optimizely Agent. You can find your SDK key in app.optimizely.com under Settings > Environments > SDK Key. Remember you have a different SDK key for each environment. +To authenticate, [pass your SDK key](https://docs.developers.optimizely.com/full-stack/v4.0/docs/quickstart-for-agent#start-an-http-session) as a header named `X-Optimizely-SDK-Key` in your API calls to Optimizely Agent. You can find your SDK key in app.optimizely.com under Settings > Environments > SDK Key. Remember you have a different SDK key for each environment. ### Get All Decisions + - To get all feature flag decisions for a visitor in a single request, omit the feature flag parameter: `POST /v1/decide` - To get decisions for multiple keys, specify multiple keys parameters, for example: `keys=flag_key_1&keys=flag_key_2` - -- To receive only the enabled feature flags for a visitor use a decide option in the `application/json` request body: +- To receive only the enabled feature flags for a visitor use a decide option in the `application/json` request body: ```curl --header 'Content-Type: application/json' \ @@ -98,16 +92,14 @@ To authenticate, [pass your SDK key](https://docs.developers.optimizely.com/ful }' ``` - - ### Tracking conversions -To track events, use the same [tracking endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/trackEvent) you use in the [SDKs' track API](doc:track-javascript): +To track events, use the same [tracking endpoint](https://library.optimizely.com/docs/api/agent/v1/index.html#operation/trackEvent) you use in the [SDKs' track API](doc:track-javascript): `POST /v1/track?eventKey={eventKey}` There is no response body for successful conversion event requests. -### API reference +### API reference - For more details on Optimizely Agent’s APIs, see the [complete API Reference](https://library.optimizely.com/docs/api/agent/v1/index.html). +For more details on Optimizely Agent’s APIs, see the [complete API Reference](https://library.optimizely.com/docs/api/agent/v1/index.html). diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md index b3429cd5..9d86d3b8 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/010 - authorization.md @@ -3,42 +3,47 @@ title: "Authorization" excerpt: "" slug: "authorization" hidden: false -metadata: - title: "Agent Authorization - Optimizely Full Stack" +metadata: + title: "Agent Authorization - Optimizely Feature Experimentation" createdAt: "2020-03-11T20:58:11.777Z" updatedAt: "2021-03-15T23:02:34.056Z" --- + Optimizely Agent supports authorization workflows based on OAuth and JWT standards, allowing you to protect access to its API and Admin interfaces. There are three modes of operation: ## 1. Issuer & Validator -Access tokens are issued by Agent itself, using a [Client Credentials grant](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/). Access tokens are signed and validated using the HS256 algorithm with a signing secret provided in configuration. Clients request access tokens by sending a `POST` request to `/oauth/token` on the port of the desired interface (by default, `8080` for the API interface, and `8088` for the Admin interface), including a client ID and secret in the request. +Access tokens are issued by Agent itself, using a [Client Credentials grant](https://www.oauth.com/oauth2-servers/access-tokens/client-credentials/). Access tokens are signed and validated using the HS256 algorithm with a signing secret provided in configuration. Clients request access tokens by sending a `POST` request to `/oauth/token` on the port of the desired interface (by default, `8080` for the API interface, and `8088` for the Admin interface), including a client ID and secret in the request. Issuer & Validator mode is useful if you want to implement authorization, and you are not already running an authorization server that can issue JWTs. ## 2. Validator-only + Agent validates access tokens that were issued elsewhere. Access tokens are validated with public keys fetched from a [JWKS](https://tools.ietf.org/html/rfc7517) URL provided in configuration. Validator-only mode is useful if you want to plug directly into an existing JWT-based workflow already being used in your system or organization. ## 3. No authorization (default) + The interface is publicly available. # Configuration + - The API and Admin interfaces are each independently configured to run in one of the above-mentioned modes of operation. - Authorization configuration is located under the `auth` key - Each mode of operation has its own set of configuration properties, described below. ## Issuer & Validator + The configuration properties pertaining to Issuer & Validator mode are listed below: -|Property Name|Environment Variable|Description| -|---|---|---| -|ttl|TTL|Time-to-live of access tokens issued| -|hmacSecrets|HMACSECRETS|Array of secrets used to sign & validate access tokens, using the HMAC SHA256 algorithm. Values must be base64-format strings. The first value in the array is used to sign issued access tokens. Access tokens signed with any value in the array are considered valid.| -|clients|N/A|Array of objects, used for token issuance, consisting of `id`, `secretHash`, and `sdkKeys`. Clients provide ID and secret in their requests to `/oauth/token`. Agent validates the request credentials by checking for an exact match of ID, checking that the BCrypt hash of the request secret matches the `secretHash` from configuration, and that the SDK key provided in the `X-Optimizely-Sdk-Key` request header exists in the `sdkKeys` from configuration. `secretHash` values must be base64-format strings.| +| Property Name | Environment Variable | Description | +| ------------- | -------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| ttl | TTL | Time-to-live of access tokens issued | +| hmacSecrets | HMACSECRETS | Array of secrets used to sign & validate access tokens, using the HMAC SHA256 algorithm. Values must be base64-format strings. The first value in the array is used to sign issued access tokens. Access tokens signed with any value in the array are considered valid. | +| clients | N/A | Array of objects, used for token issuance, consisting of `id`, `secretHash`, and `sdkKeys`. Clients provide ID and secret in their requests to `/oauth/token`. Agent validates the request credentials by checking for an exact match of ID, checking that the BCrypt hash of the request secret matches the `secretHash` from configuration, and that the SDK key provided in the `X-Optimizely-Sdk-Key` request header exists in the `sdkKeys` from configuration. `secretHash` values must be base64-format strings. | To make setup easier, Agent provides a command-line tool that can generate base64-encoded 32-byte random values, and their associated base64-encoded BCrypt hashes: @@ -48,25 +53,32 @@ To make setup easier, Agent provides a command-line tool that can generate base6 Client Secret: i3SrdrCy/wEGqggv9OI4FgIsdHHNpOacrmIMJ6SFIkE= Client Secret's hash: JDJhJDEyJERGNzhjRXVTNTdOQUZ3cndxTkZ6Li5XQURlazU2R21YeFZjb1pWSkN5eGZ1SXM4VXRLb0ZD ``` + Use the hash value to configure Agent, and pass the secret value as `client_secret` when making access token requests to `/oauth/token`. For details of the access token issuance endpoint, see the OpenAPI spec file. ## Validator-only + The configuration properties pertaining to Validator-only mode are listed below: -|Property Name|Environment Variable|Description| -|---|---|---| -|jwksURL|JWKSURL|URL from which public keys should be fetched for token validation| -|jwksUpdateInterval|JWKSUPDATEINTERVAL|Interval on which public keys should be re-fetched (example: `30m` for 30 minutes)| +| Property Name | Environment Variable | Description | +| ------------------ | -------------------- | ---------------------------------------------------------------------------------- | +| jwksURL | JWKSURL | URL from which public keys should be fetched for token validation | +| jwksUpdateInterval | JWKSUPDATEINTERVAL | Interval on which public keys should be re-fetched (example: `30m` for 30 minutes) | ## No authorization (default) + The API & Admin interfaces run with no authorization when no `auth` configuration is given. ## Configuration examples + Optimizely Agent uses the [Viper](https://github.com/spf13/viper) library for configuration, which allows setting values via environment variables, flags, and YAML configuration files. + ### Issuer & Validator + _*WARNING*_: For security, we advise that you configure `hmacSecrets` with either an environment variable or a flag, and NOT through a config file. In the below example, the Admin interface is configured in Issuer & Validator mode, with `hmacSecrets` provided via environment variable, and other values provided via YAML config file. + ```shell // Comma-separated value, to set multiple hmacSecrets. // Access tokens are signed with the first value. @@ -82,35 +94,39 @@ admin: clients: # Either of these two id/secret pairs can be exchanged for access tokens - id: agentConsumer1 - secretHash: XgZTeTvWaZ6fLiey6EBSOxJ2QFdd6dIiUcZGDIIJ+IY + secretHash: XgZTeTvWaZ6fLiey6EBSOxJ2QFdd6dIiUcZGDIIJ+IY sdkKeys: # These credentials can be exchanged for tokens granting access to these two SDK keys - abcd1234 - efgh5678 - id: agentConsumer2 - secretHash: ssz0EEViKIinkFXxzqncKxz+6VygEc2d2rKf+la5rXM + secretHash: ssz0EEViKIinkFXxzqncKxz+6VygEc2d2rKf+la5rXM sdkKeys: # These credentials can be exchanged for tokens granting access only to this one SDK key - ijkl9012 ``` ### Validator-only + ```yaml # In this example, the API interface is configured in Validator-only mode api: - auth: - # Signing keys will be fetched from this url and used when validating access tokens - jwksURL: https://YOUR_DOMAIN/.well-known/jwks.json - # Siging keys will be periodically fetched on this interval - jwksUpdateInterval: 30m + auth: + # Signing keys will be fetched from this url and used when validating access tokens + jwksURL: https://YOUR_DOMAIN/.well-known/jwks.json + # Siging keys will be periodically fetched on this interval + jwksUpdateInterval: 30m ``` # Secret Rotation (Issuer & Validator mode) + To support secret rotation, both `hmacSecrets` and `clients` support setting multiple values. In `hmacSecrets`, the first value will be used to sign issued tokens, but tokens signed with any of the values will be considered valid. # Example (Python) + Example requests demonstrating the Issuer & Validator mode: + ```python #!/usr/bin/python @@ -185,4 +201,4 @@ s.headers.update({'Authorization': 'Bearer {}'.format(resp_dict['access_token']) resp = s.get('http://localhost:8080/v1/config') print('config response after passing access token: ') print(json.dumps(resp.json(), indent=4, sort_keys=True)) -``` \ No newline at end of file +``` diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md index 18b063fe..d3752b1d 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/020 - webhooks-agent.md @@ -3,12 +3,13 @@ title: "Webhooks" excerpt: "" slug: "webhooks-agent" hidden: false -metadata: - title: "Agent microservice webhooks - Optimizely Full Stack" +metadata: + title: "Agent microservice webhooks - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:26.981Z" updatedAt: "2021-03-15T23:02:34.056Z" --- -Optimizely Agent implements a webhook listener used to receive inbound [Webhook](doc:configure-webhooks) requests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates. + +Optimizely Agent implements a webhook listener used to receive inbound [Webhook](doc:configure-webhooks) requests from optimizely.com. These webhooks enable PUSH style notifications triggering immediate project configuration updates. The webhook listener is configured on its own port (default: 8085) since it can be configured to select traffic from the internet. To accept webhook requests Agent must be configured by mapping an Optimizely Project Id to a set of SDK keys along @@ -20,8 +21,8 @@ with the associated secret used for validating the inbound request. An example w ## trigger an immediate download of the datafile from the CDN ## webhook: - ## http listener port - port: "8089" + ## http listener port + port: "8089" # ## a map of Optimizely Projects to one or more SDK keys # projects: # ## : Optimizely project id as an integer @@ -38,4 +39,4 @@ webhook: ## Next -[Create Webhooks](https://docs.developers.optimizely.com/full-stack/docs/webhooks-agent) +[Create Webhooks](https://docs.developers.optimizely.com/full-stack/v4.0/docs/webhooks-agent) diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md index f993df86..40f898ce 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/031 - agent-notifications.md @@ -1,17 +1,17 @@ --- -title: Agent Notifications +title: Agent Notifications excerpt: "" slug: "agent-notifications" hidden: false -metadata: - title: "Agent notifications - Optimizely Full Stack" +metadata: + title: "Agent notifications - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2021-03-15T23:02:34.056Z" --- Agent provides an endpoint that sends notifications to subscribers via [Server-Sent Events](https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events). This is Agent's equivalent of Notification Listeners found in Optimizely SDKs. -For details on the notification types, what causes them to be triggered, and the data they provide, see the [Notification Listeners documentation](https://docs.developers.optimizely.com/full-stack/docs/set-up-notification-listener-go). +For details on the notification types, what causes them to be triggered, and the data they provide, see the [Notification Listeners documentation](https://docs.developers.optimizely.com/full-stack/v4.0/docs/set-up-notification-listener-go). ## Configuration @@ -41,7 +41,6 @@ curl -N -H "Accept:text/event-stream" -H "X-Optimizely-Sdk-Key:"\ This connection will remain open, and any notifications triggered by other requests received by Agent are pushed as events to this stream. Try sending requests to `/v1/activate` or `/v1/track` to see notifications being triggered. - ### Filtering To subscribe only to a particular category of notifications, add a `filter` query parameter. For example, to subscribe only to Decision notifications: diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md index 7c3f9864..8c2e98d5 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/040 - advanced-configuration.md @@ -3,8 +3,8 @@ title: "Advanced configuration" excerpt: "" slug: "advanced-config-agent" hidden: false -metadata: - title: "advanced config - Agent microservice - Optimizely Full Stack" +metadata: + title: "advanced config - Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-05-21T20:35:58.387Z" updatedAt: "2021-03-15T23:02:34.056Z" --- diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md index 08e0c15d..9a6d2ea6 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/050 - agent-plugins.md @@ -4,7 +4,7 @@ excerpt: "" slug: "agent-plugins" hidden: false metadata: - title: "Agent plugins - Optimizely Full Stack" + title: "Agent plugins - Optimizely Feature Experimentation" createdAt: "2020-09-21T20:30:00.000Z" updatedAt: "2021-03-15T23:02:34.056Z" --- @@ -19,9 +19,10 @@ Interceptors can be added to Agent to customize the request and/or response by i This interface defines a `Handler()` method that returns a standard net/http middleware handler based on [http.Handler](https://golang.org/pkg/net/http/#Handler). The interceptor struct can also include a set of fields that can be configured via `config.yaml`. -* [httplog](https://github.com/optimizely/agent/tree/master/plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). +- [httplog](https://github.com/optimizely/agent/tree/master/plugins/interceptors/httplog) - Adds HTTP request logging based on [go-chi/httplog](https://github.com/go-chi/httplog). ### Example Interceptor definition + ```go package example @@ -66,6 +67,7 @@ func init() { ``` To make the interceptor available to Agent, add the plugin as an anonymous import into [all.go](./interceptors/all/all.go). + ```go package all @@ -76,6 +78,7 @@ import ( ``` Enable the example interceptor by adding to `server.interceptors` within your `config.yaml`. Note that the yaml fields should match the struct definition of your plugin. + ```yaml server: interceptors: diff --git a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md index 18a8a868..9729b095 100644 --- a/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md +++ b/docs/readme-sync/v4.0/deploy-as-a-microservice/040 - configure-optimizely-agent/index.md @@ -3,12 +3,13 @@ title: "Configure Optimizely Agent" excerpt: "" slug: "configure-optimizely-agent" hidden: false -metadata: - title: "Configure Agent microservice - Optimizely Full Stack" +metadata: + title: "Configure Agent microservice - Optimizely Feature Experimentation" createdAt: "2020-02-21T17:44:27.173Z" updatedAt: "2021-03-15T23:02:34.056Z" --- -By default Optimizely Agent uses the configuration file in the current active directory, e.g., `./config.yaml`. You can override the [default configuration](https://github.com/optimizely/agent/blob/master/config.yaml) by providing a yaml configuration file at runtime. + +By default Optimizely Agent uses the configuration file in the current active directory, e.g., `./config.yaml`. You can override the [default configuration](https://github.com/optimizely/agent/blob/master/config.yaml) by providing a yaml configuration file at runtime. You can specify alternative configuration locations at runtime via an environment variable or command line flag: @@ -16,41 +17,40 @@ You can specify alternative configuration locations at runtime via an environmen OPTIMIZELY_CONFIG_FILENAME=config.yaml make run ``` - Below is a comprehensive list of available configuration properties. -|Property Name|Env Variable|Description| -|---|---|---| -|admin.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.jwksURL|OPTIMIZELY_ADMIN_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.jwksUpdateInterval|OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization)| -|admin.auth.hmacSecrets|OPTIMIZELY_ADMIN_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization)| -|admin.auth.ttl|OPTIMIZELY_ADMIN_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization)| -|admin.port|OPTIMIZELY_ADMIN_PORT|Admin listener port. Default: 8088| -|api.auth.clients|N/A|Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.hmacSecrets|OPTIMIZELY_API_AUTH_HMACSECRETS|Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.jwksURL|OPTIMIZELY_API_AUTH_JWKSURL|JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization)| -|api.auth.jwksUpdateInterval|OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL|JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization)| -|api.auth.ttl|OPTIMIZELY_API_AUTH_TTL|Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization)| -|api.port|OPTIMIZELY_API_PORT|Api listener port. Default: 8080| -|api.maxConns|OPTIMIZLEY_API_MAXCONNS|Maximum number of concurrent requests| -|author|OPTIMIZELY_AUTHOR|Agent author. Default: Optimizely Inc.| -|certfile|OPTIMIZELY_CERTFILE|Path to a certificate file, used to run Agent with HTTPS| -|client.batchSize|OPTIMIZELY_CLIENT_BATCHSIZE|The number of events in a batch. Default: 10| -|config.filename|OPTIMIZELY_CONFIG_FILENAME|Location of the configuration YAML file. Default: ./config.yaml| -|client.flushInterval|OPTIMIZELY_CLIENT_FLUSHINTERVAL|The maximum time between events being dispatched. Default: 30s| -|client.pollingInterval|OPTIMIZELY_CLIENT_POLLINGINTERVAL|The time between successive polls for updated project configuration. Default: 1m| -|client.queueSize|OPTIMIZELY_CLIENT_QUEUESIZE|The max number of events pending dispatch. Default: 1000| -|disabledCiphers|OPTIMIZELY_DISABLEDCIPHERS|List of TLS ciphers to disable when accepting HTTPS connections| -|keyfile|OPTIMIZELY_KEYFILE|Path to a key file, used to run Agent with HTTPS| -|log.level|OPTIMIZELY_LOG_LEVEL|The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info| -|log.pretty|OPTIMIZELY_LOG_PRETTY|Flag used to set colorized console output as opposed to structured json logs. Default: false| -|name|OPTIMIZELY_NAME|Agent name. Default: optimizely| -|version|OPTIMIZELY_VERSION|Agent version. Default: `git describe --tags`| -|sdkKeys|OPTIMIZELY_SDKKEYS|Comma delimited list of SDK keys used to initialize on startup| -|server.readTimeout|OPTIMIZELY_SERVER_READTIMEOUT|The maximum duration for reading the entire body. Default: “5s”| -|server.writeTimeout|OPTIMIZELY_SERVER_WRITETIMEOUT|The maximum duration before timing out writes of the response. Default: “10s”| -|webhook.port|OPTIMIZELY_WEBHOOK_PORT|Webhook listener port: Default: 8085| -|webhook.projects.<*projectId*>.sdkKeys|N/A|Comma delimited list of SDK keys applicable to the respective projectId| -|webhook.projects.<*projectId*>.secret|N/A|Webhook secret used to validate webhook requests originating from the respective projectId| -|webhook.projects.<*projectId*>.skipSignatureCheck|N/A|Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret.| +| Property Name | Env Variable | Description | +| ------------------------------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------- | +| admin.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.jwksURL | OPTIMIZELY_ADMIN_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.jwksUpdateInterval | OPTIMIZELY_ADMIN_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization) | +| admin.auth.hmacSecrets | OPTIMIZELY_ADMIN_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization) | +| admin.auth.ttl | OPTIMIZELY_ADMIN_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization) | +| admin.port | OPTIMIZELY_ADMIN_PORT | Admin listener port. Default: 8088 | +| api.auth.clients | N/A | Credentials for requesting access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.hmacSecrets | OPTIMIZELY_API_AUTH_HMACSECRETS | Signing secret for issued access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.jwksURL | OPTIMIZELY_API_AUTH_JWKSURL | JWKS URL for validating access tokens. See: [Authorization Guide](doc:authorization) | +| api.auth.jwksUpdateInterval | OPTIMIZELY_API_AUTH_JWKSUPDATEINTERVAL | JWKS Update Interval for caching the keys in the background. See: [Authorization Guide](doc:authorization) | +| api.auth.ttl | OPTIMIZELY_API_AUTH_TTL | Time-to-live of issued access tokens. See: [Authorization Guide](doc:authorization) | +| api.port | OPTIMIZELY_API_PORT | Api listener port. Default: 8080 | +| api.maxConns | OPTIMIZLEY_API_MAXCONNS | Maximum number of concurrent requests | +| author | OPTIMIZELY_AUTHOR | Agent author. Default: Optimizely Inc. | +| certfile | OPTIMIZELY_CERTFILE | Path to a certificate file, used to run Agent with HTTPS | +| client.batchSize | OPTIMIZELY_CLIENT_BATCHSIZE | The number of events in a batch. Default: 10 | +| config.filename | OPTIMIZELY_CONFIG_FILENAME | Location of the configuration YAML file. Default: ./config.yaml | +| client.flushInterval | OPTIMIZELY_CLIENT_FLUSHINTERVAL | The maximum time between events being dispatched. Default: 30s | +| client.pollingInterval | OPTIMIZELY_CLIENT_POLLINGINTERVAL | The time between successive polls for updated project configuration. Default: 1m | +| client.queueSize | OPTIMIZELY_CLIENT_QUEUESIZE | The max number of events pending dispatch. Default: 1000 | +| disabledCiphers | OPTIMIZELY_DISABLEDCIPHERS | List of TLS ciphers to disable when accepting HTTPS connections | +| keyfile | OPTIMIZELY_KEYFILE | Path to a key file, used to run Agent with HTTPS | +| log.level | OPTIMIZELY_LOG_LEVEL | The log [level](https://github.com/rs/zerolog#leveled-logging) for the agent. Default: info | +| log.pretty | OPTIMIZELY_LOG_PRETTY | Flag used to set colorized console output as opposed to structured json logs. Default: false | +| name | OPTIMIZELY_NAME | Agent name. Default: optimizely | +| version | OPTIMIZELY_VERSION | Agent version. Default: `git describe --tags` | +| sdkKeys | OPTIMIZELY_SDKKEYS | Comma delimited list of SDK keys used to initialize on startup | +| server.readTimeout | OPTIMIZELY_SERVER_READTIMEOUT | The maximum duration for reading the entire body. Default: “5s” | +| server.writeTimeout | OPTIMIZELY_SERVER_WRITETIMEOUT | The maximum duration before timing out writes of the response. Default: “10s” | +| webhook.port | OPTIMIZELY_WEBHOOK_PORT | Webhook listener port: Default: 8085 | +| webhook.projects.<_projectId_>.sdkKeys | N/A | Comma delimited list of SDK keys applicable to the respective projectId | +| webhook.projects.<_projectId_>.secret | N/A | Webhook secret used to validate webhook requests originating from the respective projectId | +| webhook.projects.<_projectId_>.skipSignatureCheck | N/A | Boolean to indicate whether the signature should be validated. TODO remove in favor of empty secret. | diff --git a/docs/readme.md b/docs/readme.md index 04155680..80d3a7ca 100644 --- a/docs/readme.md +++ b/docs/readme.md @@ -1,25 +1,21 @@ ## Internal docs authoring notes - - -When you edit the docs in /docs/readme-sync/ and merge to the master branch, you trigger a Travis build stage (readme-sync) that syncs the Markdown doc files to FullStack public docs at https://docs.developers.optimizely.com/full-stack/docs/optimizely-agent. +When you edit the docs in /docs/readme-sync/ and merge to the master branch, you trigger a Travis build stage (readme-sync) that syncs the Markdown doc files to Feature Experimentation public docs at https://docs.developers.optimizely.com/experimentation/v4.0.0-full-stack/docs/optimizely-agent. ### Previewing -Before you commit to master, there's a travis stage that syncs your branch's changes to a ReadMe sandbox so you can preview the published output, https://docs.developers.optimizely.com/full-stack/docs/ (you need to be logged into ReadMe to see this sandbox, since it's not public). +Before you commit to master, there's a travis stage that syncs your branch's changes to a ReadMe sandbox so you can preview the published output, https://docs.developers.optimizely.com/full-stack/v4.0/docs (you need to be logged into ReadMe to see this sandbox, since it's not public). ### Directory and filename requirements -See https://github.com/flowcommerce/readme-sync. - - +See https://github.com/flowcommerce/readme-sync. ### Authoring requirements & limitations You can author the docs in Github-flavored Markdown, with the following minor restrictions and caveats: - **links** - You can use relative links, but you have to leave out the .md extension. Like this: [relative link to a doc](./readme-sync/deploy-as-a-microservice). (Future improvement: should be easy to modify readme-sync code to strip out .md extensions if we want working relative links in the markdown stored in github) -- **images** - You can't use relative links. Currently, we use hyperlinks to images stored on the master branch [like this](). +- **images** - You can't use relative links. Currently, we use hyperlinks to images stored on the master branch [like this](). - **manual edits to updatedAt:** the frontmatter in each markdown page includes an updatedAt field, which you must manually edit when you commit a page, so that the public docs display the correct info at the bottom of the page ("Updated x days ago"). - **no semantic code snippets / language highlighting** ReadMe gets confused if you use a code block snippet that indicates the language. It erratically interprets #code comments as heading markdown syntax. So if you have a bunch of headings, then avoid: @@ -30,25 +26,12 @@ You can author the docs in Github-flavored Markdown, with the following minor re and only use: ``` -# some code in some unspecified language here +# some code in some unspecified language here ``` -- **no authoring in dash.readme** - If someone doesn't know better, they could edit the Agent docs in dash.readme... but those edits will be overwritten the next time triggers the readme-sync Travis stage. There's no mechanism in dash.readme to warn them not to edit. Likewise, any suggested edits in ReadMe need to be manually merged to the Github docs rather than merged using ReadMe's mechanism. - - +- **no authoring in dash.readme** - If someone doesn't know better, they could edit the Agent docs in dash.readme... but those edits will be overwritten the next time triggers the readme-sync Travis stage. There's no mechanism in dash.readme to warn them not to edit. Likewise, any suggested edits in ReadMe need to be manually merged to the Github docs rather than merged using ReadMe's mechanism. ### Future improvements - - -- **build conflict resolution** - If 2 Travis builds tried to sync to readme at the same time, one could overwrite the other. Build duration is ~5 minutes. (One way to get to eventual consistency might be to run a nightly Travis build that syncs to Readme.) -- **no automatic updates to readme-sync** - The engine for this sync is an externally developed tool that uses the ReadMe API called readme-sync. We clone readme-sync not from the public repo, but from a mirrored repo (https://travis-ci.com/github/optimizely/readme-sync2) that was set up in early 2020. So over time we'll miss out on updates to readme-sync https://github.com/flowcommerce/readme-sync. - - - - - - - - - +- **build conflict resolution** - If 2 Travis builds tried to sync to readme at the same time, one could overwrite the other. Build duration is ~5 minutes. (One way to get to eventual consistency might be to run a nightly Travis build that syncs to Readme.) +- **no automatic updates to readme-sync** - The engine for this sync is an externally developed tool that uses the ReadMe API called readme-sync. We clone readme-sync not from the public repo, but from a mirrored repo (https://travis-ci.com/github/optimizely/readme-sync2) that was set up in early 2020. So over time we'll miss out on updates to readme-sync https://github.com/flowcommerce/readme-sync. diff --git a/examples/README.md b/examples/README.md index 9a3bb4cd..d05c2345 100644 --- a/examples/README.md +++ b/examples/README.md @@ -2,29 +2,33 @@ This folder provides a set of sample scripts to illustrate some of the main API features. Most of the examples below require an SDK key `` as one of the arguments. The SDK key can be found in the settings of your Optimizely -Full Stack or Rollouts account. +Feature Experimentation or Rollouts account. ### Installation The included examples were written in python and assumes python 3.7+. If using a python3 venv [virtual environment](https://packaging.python.org/guides/installing-using-pip-and-virtual-environments/) you can install all of the dependencies in the requirements.txt: + ```bash pip install -r requirements.txt ``` + ### Decide The `/decide` endpoint returns the requested flag decisions for a user. The flag decision includes flag enabled/disabled status and flag variation. Example usage: + ```bash python basic.py ``` -The `/decide` endpoint also supports batching requests by supplying multiple flag keys in +The `/decide` endpoint also supports batching requests by supplying multiple flag keys in single `/decide` call. Please refer to [advanced.py](./advanced.py) for an example on how to fetch multiple decisions. This is useful to reduce the number of outbound API calls made from your service to Optimizely Agent. Example usage: + ```bash python advanced.py ``` @@ -33,9 +37,10 @@ python advanced.py The `/track` endpoint is used to send conversion events to the Optimizely analytics backend. The example in [track.py](./track.py) provides an example of calling the /track api with a set of event tags -in the payload. +in the payload. Example usage: + ```bash python track.py ``` @@ -47,6 +52,7 @@ This endpoint is disabled by default and should not be used in a production envi for development and QA testing. An example of how to set an override can be found in `override.py`. Example usage: + ```bash python override.py ``` @@ -59,28 +65,31 @@ how to request an authorization token and use it in subsequent API requests. Ple for a complete overview of the authentication modes supported by Agent. Example usage: + ```bash python auth.py clientid1 0bfLVX9U3Lpr6Qe4X3DSSIWNqEkEQ4bkX1WZ5Km6spM= ``` ### Activate -##### Activate is currently still widely used, but it will be gradually superseeded by Decide. +##### Activate is currently still widely used, but it will be gradually superseeded by Decide. The `/activate` endpoint returns a decision of the requested experiment or feature for a given user context. For single decisions please refer to [basic_activate.py](./basic_activate.py) which demonstrates how to iterate through the configuration for a given SDK project and make individual activation requests. Example usage: + ```bash python basic_activate.py ``` -The `/activate` endpoint also supports batching requests by supplying multiple experiment or feature keys in +The `/activate` endpoint also supports batching requests by supplying multiple experiment or feature keys in single `/activate` call. Please refer to [advanced_activate.py](./advanced_activate.py) for an example on how to fetch multiple decisions. This is useful to reduce the number of outbound API calls made from your service to Optimizely Agent. Example usage: + ```bash python advanced_activate.py -``` \ No newline at end of file +``` diff --git a/tests/acceptance/README.md b/tests/acceptance/README.md index 64799032..d2f2b927 100644 --- a/tests/acceptance/README.md +++ b/tests/acceptance/README.md @@ -1,20 +1,19 @@ ### API acceptance tests for Optimizely Agent Acceptance tests run against a real Optimizely project, using REST API calls. -The project lives on app.optimzely.com and is maintained by the Full Stack team at Optimizely. +The project lives on app.optimzely.com and is maintained by the Feature Experimentation team at Optimizely. -First, do everything from the agent's root directory. +First, do everything from the agent's root directory. Python version 3.7 or greater is required. -It is recommended to set up a python virtual environment. +It is recommended to set up a python virtual environment. Activate virtual environment. -Install requirements `pip install -r tests/acceptance/requirements.txt` - +Install requirements `pip install -r tests/acceptance/requirements.txt` Run tests `MYHOST="http://localhost:8080" make test-acceptance` You can point `MYHOST` to any URL where agent service is located. -Tests contain a few tests that don't support user profile service. Those tests are intended to be used +Tests contain a few tests that don't support user profile service. Those tests are intended to be used by Optimizely at a different place and are therefore excluded from the main test run.