Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create init image for lib-injection #2606

Merged
merged 29 commits into from
Feb 28, 2023
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
dba83ca
Create init image for lib-injection
TonyCTHsu Feb 8, 2023
76458d7
Add version and remove DDTRACE_AUTOINJECT
TonyCTHsu Feb 15, 2023
d2f48b4
Add build publish workflow
TonyCTHsu Feb 16, 2023
d559785
Add deployment to gitlab ci
TonyCTHsu Feb 16, 2023
159657b
WIP
TonyCTHsu Feb 16, 2023
009f521
Cleanup workflow
TonyCTHsu Feb 20, 2023
953ad81
Handle failure
TonyCTHsu Feb 20, 2023
eba7706
Change test for lib-injection to not included for gem packaging
TonyCTHsu Feb 20, 2023
17ec104
Refactor workflow
TonyCTHsu Feb 21, 2023
4b648ee
Release workflow
TonyCTHsu Feb 21, 2023
75c3fa9
Dynamic gemfile
TonyCTHsu Feb 21, 2023
d70d5d5
Add system test for lib injection
TonyCTHsu Feb 23, 2023
f56abdf
Change system test commit sha
TonyCTHsu Feb 23, 2023
6eaf3d1
Update commit sha
TonyCTHsu Feb 24, 2023
32d3d42
Add gems.rb app to system test
TonyCTHsu Feb 24, 2023
686073f
Test gems.rb
TonyCTHsu Feb 24, 2023
41721e3
Test explicit
TonyCTHsu Feb 24, 2023
19a3a4b
Handle gems.rb lockfile for trial
TonyCTHsu Feb 24, 2023
322deda
All variant
TonyCTHsu Feb 24, 2023
e6baa62
Fix `gems.rb` check
TonyCTHsu Feb 24, 2023
f656a00
Refactor
TonyCTHsu Feb 27, 2023
90bf0b6
Shell escape
TonyCTHsu Feb 27, 2023
a9bfad6
Change with open3
TonyCTHsu Feb 27, 2023
a0b1a04
Merge branch 'master' into tonycthsu/lib-injection
TonyCTHsu Feb 27, 2023
d6388c5
Update Dockerfile
marcotc Feb 27, 2023
db8301c
Split puts statement for different rescue
TonyCTHsu Feb 27, 2023
c2e7434
Rescue all
TonyCTHsu Feb 27, 2023
befe4f7
Improve scripting by extrace the add cmd
TonyCTHsu Feb 28, 2023
0499917
Improve logging
TonyCTHsu Feb 28, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 59 additions & 0 deletions .github/workflows/lib-injection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
name: "Library Injection"
on:
# Build each branch for testing
push:

jobs:
build-and-publish-test-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker
run: docker login -u publisher -p ${{ secrets.GITHUB_TOKEN }} ghcr.io
- name: Docker Build
uses: docker/build-push-action@v3
with:
push: true
tags: ghcr.io/datadog/dd-trace-rb/dd-lib-ruby-init:${{ github.sha }}
platforms: 'linux/amd64,linux/arm64/v8'
build-args: DDTRACE_RUBY_SHA=${{ github.sha }}
context: ./lib-injection

test:
needs:
- build-and-publish-test-image
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
Copy link
Member

Choose a reason for hiding this comment

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

I'm curious about this -- does the current test action still require write permissions? Is this perhaps a left-over from an example/another action we started from?

strategy:
matrix:
lib-injection-connection: ['network']
lib-injection-use-admission-controller: ['', 'use-admission-controller']
weblog-variant:
- dd-lib-ruby-init-test-rails
- dd-lib-ruby-init-test-rails-explicit
- dd-lib-ruby-init-test-rails-gemsrb
fail-fast: false
env:
TEST_LIBRARY: ruby
WEBLOG_VARIANT: ${{ matrix.weblog-variant }}
LIBRARY_INJECTION_CONNECTION: ${{ matrix.lib-injection-connection }}
LIBRARY_INJECTION_ADMISSION_CONTROLLER: ${{ matrix.lib-injection-use-admission-controller }}
DOCKER_REGISTRY_IMAGES_PATH: ghcr.io/datadog
DOCKER_IMAGE_TAG: ${{ github.sha }}
BUILDX_PLATFORMS: linux/amd64,linux/arm64/v8
steps:
- name: lib-injection test runner
id: lib-injection-test-runner
uses: DataDog/system-tests/lib-injection/runner@1af3241d5b6a928199528a8cbfc5698564f5d260
with:
docker-registry: ghcr.io
docker-registry-username: ${{ github.repository_owner }}
docker-registry-password: ${{ secrets.GITHUB_TOKEN }}
test-script: ./lib-injection/run-manual-lib-injection.sh
33 changes: 33 additions & 0 deletions .github/workflows/release-lib-injection.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@

name: "Release Library Injection"
on:
push:
tags:
- 'v*.*.*'

jobs:
build-and-publish-release-image:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set version
id: version
run: echo "version=${GITHUB_REF#refs/*/}" >> $GITHUB_OUTPUT
- name: Get version
run: echo "The selected version is ${{ steps.version.outputs.version }}"
- name: Set up QEMU
uses: docker/setup-qemu-action@v2
- name: Set up Docker Buildx
id: buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker
run: docker login -u publisher -p ${{ secrets.GITHUB_TOKEN }} ghcr.io
- name: Docker Build
uses: docker/build-push-action@v3
with:
push: true
tags: ghcr.io/datadog/dd-trace-rb/dd-lib-ruby-init:${{ steps.version.outputs.version }}
platforms: 'linux/amd64,linux/arm64/v8'
build-args: DDTRACE_RUBY_VERSION=${{ steps.version.outputs.version }}
context: ./lib-injection

37 changes: 37 additions & 0 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,40 @@ deploy_to_reliability_env:
UPSTREAM_COMMIT_SHA: $CI_COMMIT_SHA
FORCE_TRIGGER: $FORCE_TRIGGER

deploy_to_docker_registries:
stage: deploy
rules:
- if: '$POPULATE_CACHE'
when: never
- if: '$CI_COMMIT_TAG =~ /^v.*/'
when: delayed
start_in: 1 day
- when: manual
allow_failure: true
trigger:
project: DataDog/public-images
branch: main
strategy: depend
variables:
IMG_SOURCES: ghcr.io/datadog/dd-trace-rb/dd-lib-ruby-init:$CI_COMMIT_TAG
IMG_DESTINATIONS: dd-lib-ruby-init:$CI_COMMIT_TAG
IMG_SIGNING: "false"

deploy_latest_tag_to_docker_registries:
stage: deploy
rules:
- if: '$POPULATE_CACHE'
when: never
- if: '$CI_COMMIT_TAG =~ /^v.*/'
when: delayed
start_in: 1 day
- when: manual
allow_failure: true
trigger:
project: DataDog/public-images
branch: main
strategy: depend
variables:
IMG_SOURCES: ghcr.io/datadog/dd-trace-rb/dd-lib-ruby-init:$CI_COMMIT_TAG
IMG_DESTINATIONS: dd-lib-ruby-init:latest
IMG_SIGNING: "false"
24 changes: 24 additions & 0 deletions lib-injection/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# This image provides the files needed to install the dd-trace-rb
# and auto instrument Ruby applications in containerized environments.
FROM busybox

# Set high UID to prevent possible conflict with existing users: http://www.linfo.org/uid.html
ARG UID=10000
Copy link
Member

Choose a reason for hiding this comment

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

Why is the user id set to 10000? Any reason for this specific value?

Copy link
Member

Choose a reason for hiding this comment

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


ARG DDTRACE_RUBY_VERSION
ENV DDTRACE_RUBY_VERSION=$DDTRACE_RUBY_VERSION

ARG DDTRACE_RUBY_SHA
ENV DDTRACE_RUBY_SHA=$DDTRACE_RUBY_SHA

RUN addgroup -g 10000 -S datadog && \
adduser -u ${UID} -S datadog -G datadog

USER ${UID}
WORKDIR /datadog-init
ADD auto_inject.rb /datadog-init/auto_inject.rb

RUN sed -i "s~<DD_TRACE_SHA_TO_BE_REPLACED>~${DDTRACE_RUBY_SHA}~g" /datadog-init/auto_inject.rb
RUN sed -i "s~<DD_TRACE_VERSION_TO_BE_REPLACED>~${DDTRACE_RUBY_VERSION}~g" /datadog-init/auto_inject.rb

ADD copy-lib.sh /datadog-init/copy-lib.sh
84 changes: 84 additions & 0 deletions lib-injection/auto_inject.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
return if ENV['skip_autoinject']
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

begin
require 'open3'

_, status = Open3.capture2e({'skip_autoinject' => 'true'}, 'bundle show ddtrace')

if status.success?
puts '[DATADOG LIB INJECTION] ddtrace already installed... skipping auto-injection'
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
return
end

require 'bundler'
require 'shellwords'

if Bundler.frozen_bundle?
puts "[DATADOG LIB INJECTION] Cannot inject with frozen Bundler"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
return
end

version = "<DD_TRACE_VERSION_TO_BE_REPLACED>"
sha = "<DD_TRACE_SHA_TO_BE_REPLACED>"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

# Stronger restrict
condition = if !version.empty?
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
# For public release
"--version #{version.gsub(/^v/, '').shellescape}"
elsif !sha.empty?
# For internal testing
"--github datadog/dd-trace-rb --ref #{sha.shellescape}"
end

unless condition
puts "[DATADOG LIB INJECTION] NO VERSION"
return
end

puts "[DATADOG LIB INJECTION] ddtrace is not installed... Perform lib injection for dd-trace-rb."
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

gemfile = Bundler::SharedHelpers.default_gemfile
lockfile = Bundler::SharedHelpers.default_lockfile

if gemfile.basename.to_s == 'gems.rb'
datadog_gemfile = gemfile.dirname + "datadog-Gemfile"
datadog_lockfile = lockfile.dirname + "datadog-Gemfile.lock"
else
datadog_gemfile = gemfile.dirname + ("datadog-#{gemfile.basename}")
datadog_lockfile = lockfile.dirname + ("datadog-#{lockfile.basename}")
end
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

require 'fileutils'

begin
# Copies for trial
Copy link
Member

Choose a reason for hiding this comment

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

Consider explaining here in a bit more detail why we're doing this

FileUtils.cp gemfile, datadog_gemfile
FileUtils.cp lockfile, datadog_lockfile

output, status = Open3.capture2e(
{ 'skip_autoinject' => 'true', 'BUNDLE_GEMFILE' => datadog_gemfile.to_s },
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
"bundle add ddtrace #{condition} --require ddtrace/auto_instrument"
)

if status.success?
puts '[DATADOG LIB INJECTION] ddtrace added to bundle...'

FileUtils.cp datadog_gemfile, gemfile
FileUtils.cp datadog_lockfile, lockfile
else
puts "[DATADOG LIB INJECTION] #{output}"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
end
rescue => e
puts "[DATADOG LIB INJECTION] trial error: #{e}"
Copy link
Member

Choose a reason for hiding this comment

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

Trial error? What does it mean?

Copy link
Contributor Author

@TonyCTHsu TonyCTHsu Feb 28, 2023

Choose a reason for hiding this comment

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

The ruby script here is conducting a trial for adding ddtrace into the bundle. The trial could be success or not and then cleanup the filesystem. I added this to be safe if there is an exception thrown during the trial but I don't see it coming.

Copy link
Member

Choose a reason for hiding this comment

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

I think customers may have the same question, and I suggest that the answer is part of the error message, not just a comment here :)

ensure
# Remove the copies
FileUtils.rm datadog_gemfile
FileUtils.rm datadog_lockfile
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
end
rescue Bundler::BundlerError => e
puts "[DATADOG LIB INJECTION] BundlerError: #{e}"
rescue LoadError => e
puts "[DATADOG LIB INJECTION] LoadError: #{e}"
rescue Exception => e
puts "[DATADOG LIB INJECTION] Exception: #{e}"
end
Copy link
Member

Choose a reason for hiding this comment

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

I had left an earlier comment on this PR, that perhaps you missed but -- I think we're missing some specs for this. We do have some coverage via the system tests, but consider testing some or all of the behaviors here using RSpec as well, to give us more confidence when changing this script.

5 changes: 5 additions & 0 deletions lib-injection/copy-lib.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#!/bin/sh

# This script is used by the admission controller to install the library from the
# init container into the application container.
cp auto_inject.rb "$1/auto_inject.rb"
2 changes: 1 addition & 1 deletion spec/ddtrace/release_gem_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@
/x

directories_excluded = %r{
^(sig|spec|docs|\.circleci|\.github|benchmarks|gemfiles|integration|tasks|yard|vendor/rbs)/
^(sig|spec|docs|\.circleci|\.github|lib-injection|benchmarks|gemfiles|integration|tasks|yard|vendor/rbs)/
}x

expect(files)
Expand Down