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

Add gitlab pipeline for host injection #2941

Merged
merged 43 commits into from
Jul 24, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
2b29cb5
Add gitlab pipeline for host injection
TonyCTHsu Jun 29, 2023
02237e7
Multi-ruby job sketch
randomanderson Jun 30, 2023
d14c680
fix dependencies
randomanderson Jun 30, 2023
59a584e
add runner tags
randomanderson Jun 30, 2023
54520f4
fix host_inject copy
randomanderson Jun 30, 2023
26ad459
Merge branch 'landerson/multi-ruby' into tonycthsu/gitlab-packaging
TonyCTHsu Jul 3, 2023
2caa84a
Install gem dependencies
TonyCTHsu Jul 3, 2023
11adbde
Remove slim image
TonyCTHsu Jul 3, 2023
faf2c66
Fix path for ruby script
TonyCTHsu Jul 3, 2023
7edbcbd
Fix ruby invocation
TonyCTHsu Jul 3, 2023
0ddad29
Remove pry
TonyCTHsu Jul 3, 2023
7d83048
Use Ruby 3.1 image
TonyCTHsu Jul 3, 2023
2cc2d82
Hack to skip signing
randomanderson Jul 5, 2023
22979ff
require rubygems
TonyCTHsu Jul 6, 2023
71961bc
Remove nested vendor
TonyCTHsu Jul 6, 2023
acf28ed
Fix lock file path
TonyCTHsu Jul 6, 2023
98f2578
Add ruby 3.2.2 image and manual image step
TonyCTHsu Jul 10, 2023
4e00f2f
Fix directory .gitlab
TonyCTHsu Jul 10, 2023
4cc3c73
Add ruby 3.0 and 3.1 images
TonyCTHsu Jul 10, 2023
5ed201e
Use manual images
TonyCTHsu Jul 10, 2023
1e2d17e
Disable system libffi
TonyCTHsu Jul 11, 2023
559c1e7
Skip profiling extension
TonyCTHsu Jul 11, 2023
37503a9
Rename directories by removing -static suffix
TonyCTHsu Jul 11, 2023
f41c4bb
Ensure read permissions
TonyCTHsu Jul 13, 2023
fa37f81
Remove temporary packaging before_script
TonyCTHsu Jul 13, 2023
8271515
Add Ruby 2.7 image & Use buster
TonyCTHsu Jul 13, 2023
b5bc658
Skip if bundler version not supported
TonyCTHsu Jul 13, 2023
8700cac
Ensure ::FileUtils is loaded correctly
TonyCTHsu Jul 13, 2023
63eecd1
Refactor build script
TonyCTHsu Jul 13, 2023
9e1fde5
Fix ffi installation
TonyCTHsu Jul 13, 2023
9581a39
Tweak pipeline with our own path
TonyCTHsu Jul 14, 2023
467d6b4
Add env to cmd
TonyCTHsu Jul 14, 2023
e880da7
Merge branch 'master' into tonycthsu/gitlab-packaging
TonyCTHsu Jul 17, 2023
a74ceaf
Add documentation
TonyCTHsu Jul 17, 2023
99c1818
Update lib-injection/README.md
TonyCTHsu Jul 20, 2023
0cbeb7e
Fix gitlab rules for building manual images
TonyCTHsu Jul 20, 2023
c20f314
Better message
TonyCTHsu Jul 20, 2023
bc544f0
Improve with Rb::Config["ruby_version"]
TonyCTHsu Jul 20, 2023
be71f96
Symlink
TonyCTHsu Jul 20, 2023
2719fbc
Cleanup ruby script
TonyCTHsu Jul 21, 2023
d0e9bd9
Use pkg folder
TonyCTHsu Jul 21, 2023
8dd90f2
More documentation
TonyCTHsu Jul 21, 2023
06670f6
Clean up pipeline script
TonyCTHsu Jul 21, 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
56 changes: 54 additions & 2 deletions .gitlab-ci.yml
Original file line number Diff line number Diff line change
@@ -1,22 +1,74 @@
stages:
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
- package
- deploy
- macrobenchmarks
- microbenchmarks

include: ".gitlab/benchmarks.yml"
include:
- remote: https://gitlab-templates.ddbuild.io/apm/packaging.yml
- local: ".gitlab/benchmarks.yml"

# -----------------------------------------------------
# Reliability Environment configuration
# -----------------------------------------------------

variables:
RUBY_PACKAGE_VERSION:
description: "The version of the gem to build the rpm/deb package"
DOWNSTREAM_BRANCH:
value: "master"
description: "Run a specific datadog-reliability-env branch downstream"

.common: &common
default:
tags: [ "runner:main", "size:large" ]

install-base-ruby-gems:
image: registry.ddbuild.io/images/mirror/ruby:3.2.2
stage: package
rules:
- if: $RUBY_PACKAGE_VERSION
when: on_success
- if: '$CI_COMMIT_TAG =~ /^v.*/'
when: on_success
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
script:
- .gitlab/install-gem-to-folder.sh
artifacts:
paths:
- vendor

install-version-dependant-gems:
image: registry.ddbuild.io/images/mirror/ruby:$RUBY_VERSION
parallel:
matrix:
- RUBY_VERSION: [ "3.0.0", "3.1.4"]
rules:
- if: $RUBY_PACKAGE_VERSION
when: on_success
- if: '$CI_COMMIT_TAG =~ /^v.*/'
when: on_success
stage: package
needs: [ "install-base-ruby-gems" ]
script:
- .gitlab/install-gem-to-folder-version-specific.sh
artifacts:
paths:
- vendor

package:
extends: .package
needs: ["install-version-dependant-gems", "install-base-ruby-gems"]
rules:
- if: $RUBY_PACKAGE_VERSION
when: on_success
- if: '$CI_COMMIT_TAG =~ /^v.*/'
when: on_success
script:
- ls ../vendor
- ../.gitlab/build-deb-rpm.sh

.release-package:
stage: deploy

deploy_to_reliability_env:
stage: deploy
rules:
Expand Down
17 changes: 17 additions & 0 deletions .gitlab/build-deb-rpm.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#!/bin/bash
Copy link
Member

Choose a reason for hiding this comment

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

Is the intention here to build a rpm (or deb) with the gems already installed and the dependencies pre-compiled?

Because that usually means that we need to have variants for every Ruby supported, it's usually problematic to pick a native extension that was compiled for some Ruby version and then use it a different Ruby version.


if [ -n "$CI_COMMIT_TAG" ] && [ -z "$RUBY_PACKAGE_VERSION" ]; then
RUBY_PACKAGE_VERSION=${CI_COMMIT_TAG##v}
fi

source common_build_functions.sh

# Not sure how it is called
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
fpm_wrapper "datadog-apm-library-ruby" "$RUBY_PACKAGE_VERSION" \
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
--input-type dir \
--url "https://github.com/DataDog/dd-trace-rb" \
--description "Datadog APM client library for Ruby" \
--license "BSD-3-Clause" \
--chdir=../vendor \
--prefix "$LIBRARIES_INSTALL_BASE/ruby" \
.=.
6 changes: 6 additions & 0 deletions .gitlab/install-gem-to-folder-version-specific.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/bin/bash

cd vendor

export INSTALL_DDTRACE_NATIVE_DEPS=true
ruby install_ddtrace_deps.rb
26 changes: 26 additions & 0 deletions .gitlab/install-gem-to-folder.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#!/bin/bash

set -e

if [ -n "$CI_COMMIT_TAG" ] && [ -z "$RUBY_PACKAGE_VERSION" ]; then
RUBY_PACKAGE_VERSION=${CI_COMMIT_TAG##v}
fi

mkdir -p vendor
cat > Gemfile << EOF
source "https://rubygems.org"

gem 'ddtrace', "$RUBY_PACKAGE_VERSION"
EOF

bundle lock

cp Gemfile vendor
cp Gemfile.lock vendor
cp .gitlab/install_ddtrace_deps.rb vendor
cp lib-injection/host_inject.rb vendor

export INSTALL_DDTRACE_NATIVE_DEPS=true
export INSTALL_DDTRACE_NON_NATIVE_DEPS=true

ruby vendor/install_ddtrace_deps.rb
78 changes: 78 additions & 0 deletions .gitlab/install_ddtrace_deps.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# require "fileutils"
require "open3"
require "bundler"

lock_file_path = "./Gemfile.lock"
install_dir = "./vendor"

# lock_file_path = "/opt/datadog/apm/library/ruby/Gemfile.lock"
# install_dir = "./vendor"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

lock_file_parser = Bundler::LockfileParser.new(Bundler.read_file(lock_file_path))

gem_version_mapping = lock_file_parser.specs.each_with_object({}) do |spec, hash|
hash[spec.name] = spec.version.to_s
hash
end

def install_ddtrace_deps_without_native_extensions(gem_version_mapping: ,location: )
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
[
"debase-ruby_core_source",
"libdatadog",
"libddwaf"
].each do |gem|
gem_install_cmd = "gem install #{gem} "\
"--version #{gem_version_mapping[gem]} "\
"--install-dir #{location} "\
"--no-document "\
"--ignore-dependencies "

STDOUT.puts "Execute: #{gem_install_cmd}"
output, status = Open3.capture2e(gem_install_cmd)
STDOUT.puts output

if status.success?
next
else
break
end
end
end

def install_ddtrace_deps_with_native_extensions(gem_version_mapping: ,location: )
[
"msgpack",
"ffi",
"ddtrace"
].each do |gem|
gem_install_cmd = "gem install #{gem} "\
"--version #{gem_version_mapping[gem]} "\
"--install-dir #{location} "\
"--no-document "\
"--ignore-dependencies "

STDOUT.puts "Execute: #{gem_install_cmd}"
output, status = Open3.capture2e(gem_install_cmd)
STDOUT.puts output

if status.success?
next
else
break
end
end
end

if ENV["INSTALL_DDTRACE_NON_NATIVE_DEPS"] == 'true'
install_ddtrace_deps_without_native_extensions(
gem_version_mapping: gem_version_mapping,
location: install_dir
)
end

if ENV["INSTALL_DDTRACE_NATIVE_DEPS"] == 'true'
install_ddtrace_deps_with_native_extensions(
gem_version_mapping: gem_version_mapping,
location: "#{install_dir}/#{RUBY_VERSION.split(".")[0..1].join(".")}"
)
end
97 changes: 97 additions & 0 deletions lib-injection/host_inject.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
return if ENV["DD_TRACE_SKIP_LIB_INJECTION"] == "true"
Copy link
Member

Choose a reason for hiding this comment

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

This file seems like it copies a lot over from auto_inject.rb. Which in this case... may be easier than shipping multiple files.

Nevertheless, I suggest trying to refactor the common bits so that we could keep them in-sync by a simple copy/paste, as right now they're in a similar-but-not-the-same situation, which is a slightly dangerous middle ground to be in, because we can easily introduce bugs when trying to keep them in-sync, or forget to update one of them.


Gem.paths = {
"GEM_PATH" => "/opt/datadog/apm/library/ruby/#{RUBY_VERSION.split(".")[0..1].join(".")}:/opt/datadog/apm/library/ruby:#{ENV["GEM_PATH"]}"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
}

ENV["GEM_PATH"] = Gem.path.join(":")
marcotc marked this conversation as resolved.
Show resolved Hide resolved
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved

begin
require "open3"
require "bundler"
require "shellwords"
require "fileutils"

failure_prefix = "Datadog lib injection failed:"
support_message = "For help solving this issue, please contact Datadog support at https://docs.datadoghq.com/help/."

unless Bundler::SharedHelpers.in_bundle?
STDOUT.puts "[ddtrace] Not in bundle... skipping host injection" if ENV["DD_TRACE_DEBUG"] == "true"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
return
end

if Bundler.frozen_bundle?
warn "[ddtrace] #{failure_prefix} Cannot inject with frozen Gemfile, run `bundle config unset deployment` to allow lib injection. To learn more about bundler deployment, check https://bundler.io/guides/deploying.html#deploying-your-application. #{support_message}"
TonyCTHsu marked this conversation as resolved.
Show resolved Hide resolved
return
end

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

if status.success?
STDOUT.puts "[ddtrace] ddtrace already installed... skipping host injection" if ENV["DD_TRACE_DEBUG"] == "true"
return
end

# lock_file_parser = Bundler::LockfileParser.new(Bundler.read_file(Bundler.default_lockfile))
lock_file_parser = Bundler::LockfileParser.new(Bundler.read_file("/opt/datadog/apm/library/ruby/Gemfile.lock"))
gem_version_mapping = lock_file_parser.specs.each_with_object({}) do |spec, hash|
hash[spec.name] = spec.version.to_s
hash
end

[
"msgpack",
"ffi",
"debase-ruby_core_source",
"libdatadog",
"libddwaf",
"ddtrace"
].each do |g|
_, status = Open3.capture2e({"DD_TRACE_SKIP_LIB_INJECTION" => "true"}, "bundle show #{g}")
if status.success?
STDOUT.puts "[ddtrace] #{g} already installed... skipping..." if ENV["DD_TRACE_DEBUG"] == "true"
next
else
bundle_add_cmd = "bundle add #{g} --skip-install --version #{gem_version_mapping[g]} "

if g == "ddtrace"
bundle_add_cmd << "--require ddtrace/auto_instrument"
end

STDOUT.puts "[ddtrace] Performing lib injection with `#{bundle_add_cmd}`" if ENV["DD_TRACE_DEBUG"] == "true"

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

datadog_gemfile = gemfile.dirname + "datadog-Gemfile"
datadog_lockfile = lockfile.dirname + "datadog-Gemfile.lock"

begin
# Copies for trial
FileUtils.cp gemfile, datadog_gemfile
FileUtils.cp lockfile, datadog_lockfile

output, status = Open3.capture2e(
{"DD_TRACE_SKIP_LIB_INJECTION" => "true", "BUNDLE_GEMFILE" => datadog_gemfile.to_s},
bundle_add_cmd
)

if status.success?
STDOUT.puts "[ddtrace] Datadog lib injection successfully added #{g} to the application."

FileUtils.cp datadog_gemfile, gemfile
FileUtils.cp datadog_lockfile, lockfile
else
warn "[ddtrace] #{failure_prefix} Unable to add ddtrace. Error output:\n#{output.split("\n").map { |l| "[ddtrace] #{l}" }.join("\n")}\n#{support_message}"
end
ensure
# Remove the copies
FileUtils.rm datadog_gemfile
FileUtils.rm datadog_lockfile
end

end
end
rescue Exception => e
warn "[ddtrace] #{failure_prefix} #{e.class.name} #{e.message}\nBacktrace: #{e.backtrace.join("\n")}\n#{support_message}"
end
Loading