diff --git a/.github/workflows/ruby.yml b/.github/workflows/ruby.yml new file mode 100644 index 0000000..ae59509 --- /dev/null +++ b/.github/workflows/ruby.yml @@ -0,0 +1,158 @@ +# Copyright 2010 New Relic, Inc. +# +# 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. +--- +name: Ruby Agent CI + +on: + pull_request: + paths: + - 'src/ruby/**' + - '.github/workflows/ruby.yml' + push: + paths: + - 'ruby/**' + - '.github/workflows/ruby.yml' + branches: + - main + # Do not run when a tag is created. + tags-ignore: + - "**" + release: + types: + - published + workflow_dispatch: + +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +env: + INITCONTAINER_LANGUAGE: ruby + K8S_OPERATOR_IMAGE_TAG: edge + +jobs: + check-modified-files: + name: Check whether any Ruby-related files were modified, skip the test job if not + uses: ./.github/workflows/check-modified-files.yml + secrets: inherit + permissions: + contents: read + with: + agent-language: ruby + + test: + name: Run Ruby init container tests + runs-on: ubuntu-latest + needs: check-modified-files + # run only if files were modified, the workflow was manually invoked, or doing a release + if: needs.check-modified-files.outputs.files-changed == 'true' || github.event_name == 'workflow_dispatch' || github.event_name == 'release' && endsWith(github.ref, '_ruby') + + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + with: + persist-credentials: false + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # 3.3.0 + + - name: Start minikube + uses: medyagh/setup-minikube@317d92317e473a10540357f1f4b2878b80ee7b95 # 0.0.16 + + - name: Deploy cert-manager to minikube + run: | + helm repo add jetstack https://charts.jetstack.io --force-update + helm install cert-manager jetstack/cert-manager --namespace cert-manager --create-namespace --version v1.14.5 --set installCRDs=true + sleep 5 + kubectl wait --for=condition=Ready -n cert-manager --all pods + + - name: Deploy New Relic k8s-agents-operator to minikube + run: | + helm repo add k8s-agents-operator https://newrelic.github.io/k8s-agents-operator + helm upgrade --install k8s-agents-operator k8s-agents-operator/k8s-agents-operator \ + --namespace=default \ + --set=licenseKey=${{ secrets.NEW_RELIC_LICENSE_KEY }} \ + --set=controllerManager.manager.image.tag=${{ env.K8S_OPERATOR_IMAGE_TAG }} + sleep 5 + kubectl wait --for=condition=Ready -n default --all pods + + - name: Build init container + run: | + minikube image build -t e2e/newrelic-${{ env.INITCONTAINER_LANGUAGE }}-init:e2e src/${{ env.INITCONTAINER_LANGUAGE }}/ + + - name: Build test app container + run: | + minikube image build -t e2e/test-app-${{ env.INITCONTAINER_LANGUAGE }}:e2e tests/${{ env.INITCONTAINER_LANGUAGE }}/ + + - name: Run e2e-test + uses: newrelic/newrelic-integration-e2e-action@a97ced80a4841c8c6261d1f9dca6706b1d89acb1 # 1.11.0 + with: + retry_seconds: 60 + retry_attempts: 5 + agent_enabled: false + spec_path: tests/${{ env.INITCONTAINER_LANGUAGE }}/test-specs.yml + account_id: ${{ secrets.NEW_RELIC_ACCOUNT_ID }} + api_key: ${{ secrets.NEW_RELIC_API_KEY }} + license_key: ${{ secrets.NEW_RELIC_LICENSE_KEY }} + + publish: + if: github.event_name == 'release' && endsWith(github.ref, '_ruby') + runs-on: ubuntu-latest + needs: + - test + + steps: + - name: Checkout code + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # 4.1.1 + with: + persist-credentials: false + + - name: Extract Agent Version + id: version + run: | + agent_version=${{ github.ref_name }} # Use tag name + agent_version=${agent_version##v} # Remove v prefix + agent_version=${agent_version%%_${{ env.INITCONTAINER_LANGUAGE }}} # Remove language suffix + echo "agent_version=${agent_version}" | tee -a "$GITHUB_OUTPUT" + + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # 3.3.0 + + - name: Generate Docker metadata (tags and labels) + id: meta + uses: docker/metadata-action@8e5442c4ef9f78752691e2d8f8d19755c6f78e81 # 5.5.1 + with: + images: newrelic/newrelic-${{ env.INITCONTAINER_LANGUAGE }}-init + tags: | + type=raw,value=${{ steps.version.outputs.agent_version }} + type=raw,value=latest + + - name: Login to Docker Hub Container Registry + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # 3.1.0 + with: + username: ${{ github.repository_owner }} + password: ${{ secrets.DOCKER_TOKEN }} + + - name: Build and publish init container image + uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # 5.3.0 + with: + push: true + context: src/${{ env.INITCONTAINER_LANGUAGE }}/ + platforms: linux/amd64,linux/arm64,linux/arm + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} + build-args: | + AGENT_VERSION=${{ steps.version.outputs.agent_version }} diff --git a/tests/ruby/Dockerfile b/tests/ruby/Dockerfile new file mode 100644 index 0000000..785f543 --- /dev/null +++ b/tests/ruby/Dockerfile @@ -0,0 +1,16 @@ +FROM ruby:latest + +WORKDIR /app + +COPY Gemfile ./ + +RUN bundle install + +COPY . . + +EXPOSE 4567 + +#Ensure executable permissions +RUN chmod +x start.sh + +CMD ["./start.sh"] diff --git a/tests/ruby/Gemfile b/tests/ruby/Gemfile new file mode 100644 index 0000000..bc5caff --- /dev/null +++ b/tests/ruby/Gemfile @@ -0,0 +1,8 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'sinatra' +gem 'newrelic_rpm' + +gem "rackup", "~> 2.1" diff --git a/tests/ruby/Gemfile.lock b/tests/ruby/Gemfile.lock new file mode 100644 index 0000000..8b13e7c --- /dev/null +++ b/tests/ruby/Gemfile.lock @@ -0,0 +1,37 @@ +GEM + remote: https://rubygems.org/ + specs: + base64 (0.2.0) + mustermann (3.0.0) + ruby2_keywords (~> 0.0.1) + newrelic_rpm (9.10.0) + rack (3.0.11) + rack-protection (4.0.0) + base64 (>= 0.1.0) + rack (>= 3.0.0, < 4) + rack-session (2.0.0) + rack (>= 3.0.0) + rackup (2.1.0) + rack (>= 3) + webrick (~> 1.8) + ruby2_keywords (0.0.5) + sinatra (4.0.0) + mustermann (~> 3.0) + rack (>= 3.0.0, < 4) + rack-protection (= 4.0.0) + rack-session (>= 2.0.0, < 3) + tilt (~> 2.0) + tilt (2.3.0) + webrick (1.8.1) + +PLATFORMS + ruby + x86_64-darwin-23 + +DEPENDENCIES + newrelic_rpm + rackup (~> 2.1) + sinatra + +BUNDLED WITH + 2.5.6 diff --git a/tests/ruby/app.rb b/tests/ruby/app.rb new file mode 100644 index 0000000..464c628 --- /dev/null +++ b/tests/ruby/app.rb @@ -0,0 +1,13 @@ +# frozen_string_literal: true + +require 'sinatra' +require 'newrelic_rpm' + +set :bind, '0.0.0.0' +set :port, 4567 + +get '/' do + return 'no new relic txn' unless NewRelic::Agent::Tracer.current_transaction + + 'hello, world!' +end diff --git a/tests/ruby/chart/.helmignore b/tests/ruby/chart/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/tests/ruby/chart/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/tests/ruby/chart/Chart.yaml b/tests/ruby/chart/Chart.yaml new file mode 100644 index 0000000..1557c91 --- /dev/null +++ b/tests/ruby/chart/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: test-app-ruby +description: A Helm chart for Kubernetes +type: application +version: 1.0.0 +appVersion: "1.0.0" diff --git a/tests/ruby/chart/templates/deployment.yaml b/tests/ruby/chart/templates/deployment.yaml new file mode 100644 index 0000000..d1294f6 --- /dev/null +++ b/tests/ruby/chart/templates/deployment.yaml @@ -0,0 +1,46 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: test-app-ruby +spec: + selector: + matchLabels: + app: test-app-ruby + replicas: 1 + template: + metadata: + labels: + app: test-app-ruby + annotations: + instrumentation.newrelic.com/inject-ruby: "true" + spec: + containers: + - name: test-app-ruby + image: e2e/test-app-ruby:e2e + imagePullPolicy: Never + ports: + - containerPort: 4567 + env: + - name: NEW_RELIC_APP_NAME + value: k8s-e2e-test-app-ruby + # used by the e2e Github action + - name: NEW_RELIC_LABELS + value: "testKey:{{ .Values.scenarioTag | default "NOTSET" }}" + - name: NEW_RELIC_LOG_LEVEL + value: info + # set the host to staging if using a staging license key + # - name: NEW_RELIC_HOST + # value: staging-collector.newrelic.com +--- +apiVersion: v1 +kind: Service +metadata: + name: test-app-ruby-service +spec: + type: NodePort + ports: + - port: 4567 + targetPort: 4567 + selector: + app: test-app-ruby diff --git a/tests/ruby/chart/templates/instrumentation.yaml b/tests/ruby/chart/templates/instrumentation.yaml new file mode 100644 index 0000000..3e5bd01 --- /dev/null +++ b/tests/ruby/chart/templates/instrumentation.yaml @@ -0,0 +1,11 @@ +--- +apiVersion: newrelic.com/v1alpha1 +kind: Instrumentation +metadata: + labels: + app.kubernetes.io/name: instrumentation + app.kubernetes.io/created-by: newrelic-agent-operator + name: newrelic-instrumentation +spec: + ruby: + image: e2e/newrelic-ruby-init:e2e diff --git a/tests/ruby/chart/values.yaml b/tests/ruby/chart/values.yaml new file mode 100644 index 0000000..44eb261 --- /dev/null +++ b/tests/ruby/chart/values.yaml @@ -0,0 +1 @@ +scenarioTag: "" \ No newline at end of file diff --git a/tests/ruby/config.ru b/tests/ruby/config.ru new file mode 100644 index 0000000..6980847 --- /dev/null +++ b/tests/ruby/config.ru @@ -0,0 +1,3 @@ +require './app.rb' + +run Sinatra::Application \ No newline at end of file diff --git a/tests/ruby/start.sh b/tests/ruby/start.sh new file mode 100644 index 0000000..7ba4b5d --- /dev/null +++ b/tests/ruby/start.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +# Start ruby app and provide time to boot Puma +ruby app.rb & sleep 5 + +# Hit endponint +while true; do + curl http://0.0.0.0:4567 + sleep 3 +done diff --git a/tests/ruby/test-specs.yml b/tests/ruby/test-specs.yml new file mode 100644 index 0000000..d373e4a --- /dev/null +++ b/tests/ruby/test-specs.yml @@ -0,0 +1,15 @@ +description: End-to-end tests for ruby initcontainer +custom_test_key: tags.testKey +scenarios: + - description: This scenario will verify that a transaction is reported by the test app after a curl request + before: + - helm install test-ruby ./chart/ --set=scenarioTag="${SCENARIO_TAG}" -n default + - sleep 5 + - kubectl wait --for=condition=Ready -n default --all pods + - curl --fail-with-body $(minikube service test-app-ruby-service --url -n default)/ + tests: + nrqls: + - query: SELECT latest(duration) AS duration FROM Transaction WHERE appName = 'k8s-e2e-test-app-ruby' + expected_results: + - key: "duration" + lowerBoundedValue: 0.0