diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml deleted file mode 100644 index 44a7bf1..0000000 --- a/.gitlab-ci.yml +++ /dev/null @@ -1,124 +0,0 @@ -stages: - - build - - test - - gen-code - - release - -### Build - -# Build the Fencer Docker image -compile: - stage: build - image: nixos/nix - environment: - # GitLab provides the Cachix signing key to all jobs tagged with - # 'compile' (i.e. only this job) - name: compile - script: - # Build the Docker image and create a list of paths to push to Cachix. - # The secret signing key should not be available to the build process. - - ( unset CACHIX_SIGNING_KEY; - nix-env -iA cachix -f https://cachix.org/api/v1/install; - cachix use fencer; - imagepath=$(nix-build docker.nix); - cp $imagepath fencer.tar.gz; - nix-store -qR --include-outputs $(nix-instantiate docker.nix) > paths - ) - # Push built paths to Cachix - - cachix push fencer < paths - artifacts: - paths: - - fencer.tar.gz - -# Build the Go integration test -compile_integration: - stage: build - image: nixos/nix - script: - - imagepath=$(nix-build test_integration_go/docker.nix) - - cp $imagepath test_integration_go.tar.gz - artifacts: - paths: - - test_integration_go.tar.gz - -### Test - -integration: - stage: test - image: docker:19.03.0 - variables: - DOCKER_DRIVER: overlay2 - DOCKER_TLS_CERTDIR: "/certs" - services: - - docker:19.03.0-dind - before_script: - - docker info - script: - # Create a Docker network for the containers - - docker network create test - - # Run Fencer - - # A pipeline would report that a container named "fencer" already - # exists (possibly from a job for a different pull request) so - # choosing a random container name deals with this - # issue. Furthermore, using a named constant helps with informing - # where this name is used (compared to "fencer" which has an - # overloaded meaning in the CI). - - CNAME="fencer-"$(head /dev/urandom | tr -dc A-Za-z0-9 | head -c 25 ; echo '') - - docker load -i fencer.tar.gz - - docker run - -v $(pwd)/test_integration_go/config:/srv/runtime_data/current - -e RUNTIME_SUBDIRECTORY=ratelimit - --name $CNAME - --network test - --detach - juspay/fencer - - sleep 5 - - # Run the test - - docker load -i test_integration_go.tar.gz - - docker run - -e GRPC_HOST=$CNAME - --network test - test_integration_go - -### Checking checked-in generated code is up to date - -protogen: - stage: gen-code - image: nixos/nix - script: - - nix-env -iA cachix -iA git -f https://cachix.org/api/v1/install - - cachix use fencer - - nix-shell --run ./scripts/protoGen.sh; - - DIFF=$(git diff lib/Fencer/Proto.hs | wc -c) - - if [ "$DIFF" != "0" ]; then exit 1; fi - -### Release - -release_docker: - stage: release - image: docker:19.03.0 - environment: - # GitLab provides the GitHub access token to all jobs tagged with - # 'release_docker' (i.e. only this job) - name: release_docker - variables: - DOCKER_DRIVER: overlay2 - DOCKER_TLS_CERTDIR: "/certs" - services: - - docker:19.03.0-dind - script: - - echo "$GITHUB_ACCESS_TOKEN" - | docker login docker.pkg.github.com --username juspay --password-stdin - - docker load -i fencer.tar.gz - # Tag the image with commit hash and push - - HASH=$(git log -1 --pretty=%h) - - docker tag juspay/fencer "docker.pkg.github.com/juspay/fencer/fencer:$HASH" - - docker push "docker.pkg.github.com/juspay/fencer/fencer:$HASH" - # Tag the same image with "master" and push - - docker tag juspay/fencer docker.pkg.github.com/juspay/fencer/fencer:master - - docker push docker.pkg.github.com/juspay/fencer/fencer:master - only: - - master diff --git a/.hlint.yaml b/.hlint.yaml index f53bd43..63216c3 100644 --- a/.hlint.yaml +++ b/.hlint.yaml @@ -38,7 +38,6 @@ - ignore: { name: 'Use const' } - ignore: { name: 'Move brackets to avoid $' } - ignore: { name: 'Use ?~' } -- ignore: { name: 'Eta reduce' } # Custom hints - warn: diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..5211ff9 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,115 @@ +language: nix +os: linux +dist: bionic + +stages: + - build + - test + - gen-code + - release + +jobs: + include: + + # Build the Fencer Docker image + - stage: build + script: + # Build the Docker image and create a list of paths to push to Cachix. + # The secret signing key should not be available to the build process. + - ( unset CACHIX_SIGNING_KEY; + nix-env -iA cachix -f https://cachix.org/api/v1/install; + cachix use fencer; + imagepath=$(nix-build docker.nix); + cp $imagepath fencer.tar.gz; + nix-store -qR --include-outputs $(nix-instantiate docker.nix) > paths + ) + # Push built paths to Cachix + - cachix push fencer < paths + workspaces: + create: + name: build-docker + paths: + - fencer.tar.gz + env: + # CACHIX_SIGNING_KEY + - secure: "vNNLfNScRuluP7zmlkCv/9uD+haHZ+iNv5FmWbXA757roaUgXBwRHZptM7wkUCUnhWVKiY9TRBJlCg5NAfNtUB1ElDZifLeVnUzaAsF4y7HP/hDYGmg+NnCB4EhBtc8vmATYK323VKzHCGiApKO0EvO7Oc8CRhrk/RFjVA6JoXYn8rM9FXcvT2AAXGzZmbevH5uUSlY61qmCF0YJdQdtjrwzDk1P/NQCKppxOHlJs1j38BF7ax94gKq2sCMXQA3d4V47WxKZgSvG+fBdXeFAwDs+avnTQ9hTFOb08yeCkIfUlx/GzSH6AVZR2tOwg59MVf9rTDIAExe3slNdDnicwWR1iV1ffmeYzztxA/359/YSYbL06ux0Mq8WsC2wg6+QlIo/K7Lc2q9J8Eye3zwfMGPkSNFUQuSkq+dCdN2r3xT3t6qfhdXo90f7GGvSmBwGc63Cao4rPBc7I98q9SLC4OjSXG4ktgqV6zzGG29/Y+sdpq0WN2pcHB2676WF+jyXrmEgm7Fq2SDU2wdxjA3ZviSbw8gUFvF1/tG/O42juYGMjztBg+eLBf+ZcehsFLctu8tRtMn6PouPfd5OwYmG4IsVBLyNa8lK9I/Hl5RGX5X2RWfCbZz98yzvoAU3T+GgDzQ4apODVnquIX0ebQDhM8s+3Av/+pWnqe5fq3iYtbU=" + + # Build the Go integration test + - stage: build + script: + - imagepath=$(nix-build test_integration_go/docker.nix) + - cp $imagepath test_integration_go.tar.gz + workspaces: + create: + name: build-test + paths: + - test_integration_go.tar.gz + + # Run integration tests + - stage: test + services: + - docker + workspaces: + use: + - build-docker + - build-test + env: + # Name of the Docker container running Fencer + - FENCER_SERVER=fencer-server + # Names of Docker images, should correspond to names in .nix files + - FENCER_IMAGE=juspayin/fencer + - FENCER_TEST_IMAGE=test_integration_go + script: + # Create a Docker network for the containers + - docker network create test + # Run Fencer + - docker load -i fencer.tar.gz + - docker run + -v $(pwd)/test_integration_go/config:/srv/runtime_data/current + -e RUNTIME_SUBDIRECTORY=ratelimit + --name $FENCER_SERVER + --network test + --detach + $FENCER_IMAGE + - sleep 5 + # Run the test + - docker load -i test_integration_go.tar.gz + - docker run + -e GRPC_HOST=$FENCER_SERVER + --network test + $FENCER_TEST_IMAGE + + ### Checking checked-in generated code is up to date + - stage: gen-code + script: + - nix-env -iA cachix -iA git -f https://cachix.org/api/v1/install + - cachix use fencer + - nix-shell --run ./scripts/protoGen.sh + - DIFF=$(git diff lib/Fencer/Proto.hs | wc -c) + - if [ "$DIFF" != "0" ]; then exit 1; fi + + ### Release + - stage: release + services: + - docker + env: + # DockerHub repo to push to + - FENCER_REPO=juspayin/fencer + # Name of Docker image, should correspond to the name in docker.nix + - FENCER_IMAGE=juspayin/fencer + # DOCKERHUB_ACCESS_TOKEN + - secure: "KZD2fp9Jlw0e7QJzivpUIesFByf9I2z5VVIzW2KYJFVaYM/zQFHwJTQ5zLViVn69KZ/S8ofiwnEOh8FGMirrtD26fqnYLYYEYd1N5XnNqVSc56Vj90+p9+1ygN+mJX/WvmkLIuozMXNw2PLh37ZWxhaZJBsidI9NTXRY6qqRDZFV16JpQIzrm8gAto5ndidrm11rfh2e3Sgq6eYNUvTSITQ/HI8MM1x9sd+DU/YSrW+9Ww2CWWmgFphOCz+VVC9vbXLRmFga4tOSReYmS1WLQos7pm4GlNAmBPyBh7TL3arLzr4wjc/tqaSNYqV2m8vtmBMfWYlzgK6ccWfXDK92eFsZ5UEKUuw9vt/2qPkZkBOrCAJ5lYRIT+ZbRr64vuikL1RgIKzN7VsEeq7TmwLDkxV1sBQtywSitAVo47KVJBwhlbp2NjPaDt/uxazpQHgv2y7UyhJweHvpfPnwMcBW053PFAXhsdgcMoT7R3hAMerx0u80ll1k9qeRfwVV06gOYd4qoCFNEG3ddKWvXbh4/KGxo1xw+vQ3J3oOwIAdNrHy4FVA3SzjI5hN5MCQ32+7ma8o4vWFfh6KBltw1pLZsI80ZmqdOo2cpRzvUJSbpjCi2xLfkyxEw2SuZOlGpUIIib0yNm+gDinojg3wjsF69EFf+3dLOtduH3kJ1FMKUvY=" + workspaces: + use: + - build-docker + script: + - echo "$DOCKERHUB_ACCESS_TOKEN" | docker login --username juspayin --password-stdin + - docker import fencer.tar.gz $FENCER_IMAGE + # Tag the image with commit hash and push + - HASH=$(git log -1 --pretty=%h) + - docker tag $FENCER_IMAGE $FENCER_REPO:$HASH + - docker push $FENCER_REPO:$HASH + # Tag the same image with "master" and push + - docker tag $FENCER_IMAGE $FENCER_REPO:master + - docker push $FENCER_REPO:master + if: branch = master AND type = push diff --git a/README.md b/README.md index 2f93f81..c229d84 100644 --- a/README.md +++ b/README.md @@ -9,17 +9,14 @@ in touch at . ## Usage -We publish Docker images of Fencer in GitHub package registry: -. You can either use images -tagged with commit hashes, or with `master` for the latest build. At the -moment you have to be logged into the registry before pulling the image – -see [Configuring Docker for use with GitHub Package Registry][github-docker] -for details. +We publish Docker images of Fencer on DockerHub at [juspayin/fencer][]. You +can either use images tagged with commit hashes, or with `master` for the +latest build. -[github-docker]: https://help.github.com/en/github/managing-packages-with-github-package-registry/configuring-docker-for-use-with-github-package-registry +[juspayin/fencer]: https://hub.docker.com/r/juspayin/fencer ``` -docker pull docker.pkg.github.com/juspay/fencer/fencer:master +docker pull juspayin/fencer:master ``` You will need the following directory structure: @@ -41,7 +38,7 @@ docker run -d \ -p 8081:8081 \ -v $(pwd):/srv/runtime_data \ -e RUNTIME_SUBDIRECTORY=ratelimit \ - docker.pkg.github.com/juspay/fencer/fencer:master + juspayin/fencer ``` To modify configuration, create a new directory (e.g. `./config2`) and @@ -58,7 +55,7 @@ docker run -d \ -v $(pwd):/srv/runtime_data \ -e RUNTIME_SUBDIRECTORY=ratelimit \ -e LOG_LEVEL=Info \ - docker.pkg.github.com/juspay/fencer/fencer:master + juspayin/fencer ``` ## Building diff --git a/docker.nix b/docker.nix index 4447c4c..b7c1368 100644 --- a/docker.nix +++ b/docker.nix @@ -4,7 +4,7 @@ let fencer = drv.fencer; in pkgs.dockerTools.buildImage { - name = "juspay/fencer"; + name = "juspayin/fencer"; tag = "latest"; created = "now"; contents = fencer; diff --git a/lib/Fencer/Server.hs b/lib/Fencer/Server.hs index 4160b85..84b17cb 100644 --- a/lib/Fencer/Server.hs +++ b/lib/Fencer/Server.hs @@ -87,22 +87,23 @@ shouldRateLimit logger appState (Grpc.ServerNormalRequest serverCall request) = Logger.field "hits" hits -- Check some conditions and throw errors if necessary. - let cancelCall err = Grpc.serverCallCancel serverCall Grpc.StatusUnknown err + let cancelWithError :: String -> IO () + cancelWithError = Grpc.serverCallCancel serverCall Grpc.StatusUnknown unlessM (atomically (getAppStateRulesLoaded appState)) $ do Logger.info logger $ Logger.msg (Logger.val "Rules not loaded, responding with an error") - cancelCall "no rate limit configuration loaded" + cancelWithError "no rate limit configuration loaded" when (domain == DomainId "") $ do Logger.info logger $ Logger.msg (Logger.val "Empty domain ID, responding with an error") - cancelCall "rate limit domain must not be empty" + cancelWithError "rate limit domain must not be empty" when (null @[] descriptors) $ do Logger.info logger $ Logger.msg (Logger.val "Empty descriptor list, responding with an error") - cancelCall "rate limit descriptor list must not be empty" + cancelWithError "rate limit descriptor list must not be empty" -- Update all counters in one atomic operation, and collect the results. --