Skip to content
This repository has been archived by the owner on Sep 17, 2024. It is now read-only.

feat: sync Docker Compose files with Beats Integrations #84

Merged
merged 42 commits into from
Feb 19, 2020

Conversation

mdelapenya
Copy link
Contributor

@mdelapenya mdelapenya commented Feb 17, 2020

What does this PR do?

This PR syncs the docker compose files from the project with the existing ones in Beats for metricbeat's integrations.

To achieve that, we added a new command to the CLI (sync integrations [--remove, --remote]) which fetches the default Beats repo (elastic/beats:master) to the tool's workspace: ~/.op/git/beats. It's possible to instrument this command with two flags:

  • [-R | --remove]: to remove the existing local repository before cloning the repo
  • [-r | --remote]: to use a different remote, in the $USER:$BRANCH format (i.e. "mdelapenya:my-branch")

Once the Beats repo is cloned, we will copy the compose files into the tool's workspace, alongside the other compose files: ~/.op/compose/services.

To make this possible, we had to change the layout of the services and stacks. In the past, there was a YML file representing the service/stack to deploy, where its name was the service name. Now we are going to use the service name as a directory, in which we will copy the docker-compose.yml file coming from the Beats repo. Besides that, we downgraded the spec version of the files from '3.0' to '2.3', to match the spec version Beats files use.

Alongside with the compose files, we are copying the _meta directory from Beats repo, where there exists a supported-versions.yml file, which is responsible for the versions to support (as obvious). This will be mapped as environment variables into the running services to be able to define properly the variants for those services needing it. These files will be important, because ONLY those services with the file will be copied to the tool.

Talking about variants, we had to create two different Gherkin steps to cover this scenario, which is used by MySQL. It was super easy to create them and reuse common functionality.

Maybe we need to refactor those two new steps to share code with the old ones. I intentionally did not do it, as they are just two. Another occurrence and we must do it for sure.

Once the docker-compose files have been fetched from the git repo, they will be discoverable by the CLI tool, so any subcommand (i.e. run, stop, deploy, undeploy will know about them.

$ op run service dropwizard

A follow-up for this is asking the user for the versioning an interactive manner: reading the supported files on runtime and offering the user a list with the supported versions.

Because we want to match Beats integrations files, we also removed the default services that came bundled with the CLI. They will not be present for first time, and a sync must be done if we want to use them.

Another improvement we did in this PR is to address #36. With each run of the CLI will create a state file under tool's workspace (i.e. ~/.op/apache-service.run. These state files will hold information about the run: which environment variables were added to the run, including its version, and the services in the run in the case we deployed services to a stack. This file will be in YML format, and will contain a suffix in its name setting if the run if for a service or a stack. The CLI will update the state when needed, destroying it with the Down. On the other hand, the CLI will read the state to simplify its usage, and not forcing the user to pass again more variables (i.e. the version) with each command. As an example: if you run an apache service v2.4, then it's not needed to pass the version again when stopping it.

As a consequence of above requirements, we created several specialised Go files: io.go, shell.go, git.go, state.go, which will represent internal functionality for the CLI.

To finish, we used 7.6.0 as the default version for the stack and metricbeat, to match with current release (remember it's possible to modify it using environment variables: OP_STACK_VERSION and OP_METRICBEAT_VERSION.

Author's checklist

  • Tests for Apache passing
  • Tests for MySQL and ALL variants passing
  • Tests for Redis passing
  • Tests for vSphere passing

Follow-up

As a result of elastic/beats#16311, we are going to massage the fetched docker-compose files to remove the build section, which requires accessing a relative path which was not present at the first docker-compose file. This will be done in next commits in this PR, but I wanted to publish this work for you to review it 🙏

Related issues

We'll create adirectory per service/integration, which will need a modification
of the current behavior for fetching services: instead of using its name
as compose file, we will use that name as directory in where a
docker-compose.yml file will be located
We are going to copy the docker-compose.yml file AND the _meta directory for each service
We downgraded from 3 to 2.3 because Beats' iintegratioins use that version.

It's not possible to upgrade theirs, because they leverage 'depends_on' and
'extends', which are noot supported by 3.x
Those service in the file system take precedence over those boxed in the binary
Let's use the default ones, until the user syncs the integrations with the `sync integrations` command
We do not want to read from the packr box: use the available services struct
Retrieving a docker-compose file from the configuration should not expose
whether it's located in the file system or boxed in the binary
A run is an execution of the tool, be it a stack or a service. With the
tool we can add or remove services to a run

The .run file will contain the stack (optional) and the services in the
run, including the environment used for the ran, which will allow to
restore that state for future updates in the run.

We also support recovering and desttroying the state for a run
@mdelapenya mdelapenya self-assigned this Feb 17, 2020
@mdelapenya mdelapenya requested review from a team and jsoriano February 17, 2020 11:17
@@ -23,6 +23,9 @@ make -C metricbeat-tests fetch-binary
# Build runtime dependencies
STACK_VERSION=${STACK_VERSION} make -C metricbeat-tests run-elastic-stack

# Sync integrations
make -C metricbeat-tests sync-integrations
Copy link
Contributor Author

Choose a reason for hiding this comment

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

This is forcing the CI to get the compose files from Beats

func GetPackedCompose(isStack bool, composeName string) (string, error) {
composeFileName := composeName + ".yml"
func GetComposeFile(isStack bool, composeName string) (string, error) {
composeFileName := "docker-compose.yml"
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Because of the layout change, we can keep the name as the default one

// PutServiceEnvironment puts the environment variables for the service, replacing "SERVICE_"
// with service name in uppercase. The variables are:
// - SERVICE_VERSION: where it represents the version of the service (i.e. APACHE_VERSION)
// - SERVICE_PATH: where it represents the path to its compose file (i.e. APACHE_PATH)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Follow-up: we won't need the *_PATH after updating the fetched compose files to remove the build section.

"service": service,
}).Warn("Could not find compose file")
} else {
env[serviceUpper+"_PATH"] = filepath.Dir(srv.Path)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Follow-up: we won't need the *_PATH after updating the fetched compose files to remove the build section.

Copy link
Member

@jsoriano jsoriano left a comment

Choose a reason for hiding this comment

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

Great job here, I have added some comments, they can probably be follow ups.

cli/cmd/sync.go Show resolved Hide resolved
// - SERVICE_VARIANT: where SERVICE is the name of the service (i.e. APACHE_VARIANT)
// - SERVICE_VERSION: where it represents the version of the service (i.e. APACHE_VERSION)
func PutServiceVariantEnvironment(env map[string]string, service string, serviceVariant string, serviceVersion string) map[string]string {
type EnvVar interface{}
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 you can safely assume that this is going to be an string to string map.

Suggested change
type EnvVar interface{}
type EnvVar map[string]string

Copy link
Contributor Author

Choose a reason for hiding this comment

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

metricbeat-tests/metricbeat_test.go Show resolved Hide resolved
cli/config/config.go Show resolved Hide resolved
cli/internal/io.go Show resolved Hide resolved
metricbeat-tests/runner_test.go Show resolved Hide resolved
cli/README.md Outdated Show resolved Hide resolved
cli/README.md Outdated Show resolved Hide resolved
cli/cmd/sync.go Outdated Show resolved Hide resolved
cli/cmd/sync.go Show resolved Hide resolved
cli/config/config.go Show resolved Hide resolved
cli/internal/shell.go Outdated Show resolved Hide resolved
metricbeat-tests/runner_test.go Show resolved Hide resolved
@mdelapenya mdelapenya merged commit 81be30b into elastic:master Feb 19, 2020
@mdelapenya mdelapenya deleted the 79-sync-integrations branch February 19, 2020 09:07
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reuse beats' docker-compose files in the PoC Represent the state of the running services in a standard file
4 participants