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

Get elastic-agent-managed-daemonset.yaml from upstream 7.x instead of using a local static file #452

Conversation

MichaelKatsoulis
Copy link
Contributor

This PR aims to close #328.

There is no need anymore for maintaining a static go file for elastic-agent-managed deployment.
Instead the upstream manifest (which creates a Daemonset) can be used. manifest

It is still in draft mode due to one dependancy.

@MichaelKatsoulis MichaelKatsoulis added enhancement New feature or request Team:Integrations Label for the Integrations team labels Jul 29, 2021
@elasticmachine
Copy link
Collaborator

Pinging @elastic/integrations (Team:Integrations)

@MichaelKatsoulis MichaelKatsoulis marked this pull request as draft July 29, 2021 14:17
@mtojek mtojek self-requested a review July 29, 2021 14:25
@elasticmachine
Copy link
Collaborator

elasticmachine commented Jul 29, 2021

💚 Build Succeeded

the below badges are clickable and redirect to their specific view in the CI or DOCS
Pipeline View Test View Changes Artifacts preview preview

Expand to view the summary

Build stats

  • Start Time: 2021-08-02T10:05:17.985+0000

  • Duration: 25 min 56 sec

  • Commit: cb63b32

Test stats 🧪

Test Results
Failed 0
Passed 316
Skipped 4
Total 320

Trends 🧪

Image of Build Times

Image of Tests

Copy link
Contributor

@mtojek mtojek left a comment

Choose a reason for hiding this comment

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

While I was reviewing this draft, I found a potential issue. This file will be downloaded during the installation procedure and be left there forever. If the remote file changes (new commits in 7.x), the elastic-package won't pick it up.
Also, the installation procedure doesn't require internet access so far, so this would be blocking. I think we should consider an alternative approach:

  1. Remove all local elastic-agent.yaml definitions.
  2. Replace the logic which uses local file with one downloading from remote location every time (you can also use the cache directory in ~/.elastic-package/cache).

@@ -238,3 +246,20 @@ func createServiceLogsDir(elasticPackagePath *locations.LocationManager) error {
}
return nil
}

// DownloadFile will download a url from a path and return the response body as a string.
func DownloadFile(filepath string, url string) (string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: does it have to be exposed?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

no!

@@ -184,9 +187,14 @@ func writeKubernetesDeployerResources(elasticPackagePath *locations.LocationMana
return errors.Wrap(err, "can't read application configuration")
}

elasticAgentManagedYaml, err := DownloadFile("elastic-agent-managed-kubernetes.yaml", elasticAgentManagedYamlUrl)
Copy link
Contributor

Choose a reason for hiding this comment

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

I don't think that filepath is needed here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

😔 it is not

@@ -184,9 +187,14 @@ func writeKubernetesDeployerResources(elasticPackagePath *locations.LocationMana
return errors.Wrap(err, "can't read application configuration")
}

elasticAgentManagedYaml, err := DownloadFile("elastic-agent-managed-kubernetes.yaml", elasticAgentManagedYamlUrl)
if err != nil {
return errors.Wrap(err, "downloading elastic-agent-managed-kubernetes.yaml failed")
Copy link
Contributor

Choose a reason for hiding this comment

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

I would replace the filename with something abstract in case the filename changes.

// Get the data
resp, err := http.Get(url)
if err != nil {
return "", err
Copy link
Contributor

Choose a reason for hiding this comment

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

Please use the errors.Wrap to stick some context here.

// Convert to string
b, err := io.ReadAll(resp.Body)
if err != nil {
return "", err
Copy link
Contributor

Choose a reason for hiding this comment

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

same here

@@ -184,9 +187,14 @@ func writeKubernetesDeployerResources(elasticPackagePath *locations.LocationMana
return errors.Wrap(err, "can't read application configuration")
}

elasticAgentManagedYaml, err := DownloadFile("elastic-agent-managed-kubernetes.yaml", elasticAgentManagedYamlUrl)
Copy link
Contributor

Choose a reason for hiding this comment

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

WDYT to replace this function with less generic one like downloadElasticAgentManagedYAML()? I don't think we need generic DownloadFile function here.

@ChrsMark
Copy link
Member

Great to see this happening! It will help us eliminate issues when changes are happening on Beats/Agent regarding the deployment model/roles etc.

While I was reviewing this draft, I found a potential issue. This file will be downloaded during the installation procedure and be left there forever. If the remote file changes (new commits in 7.x), the elastic-package won't pick it up.
Also, the installation procedure doesn't require internet access so far, so this would be blocking. I think we should consider an alternative approach:

Why the file will stay there forever? I would expect a "download&replace" approach to work here. Or to be more consistent before downloading the deployer can try to k delete -f any old Agents and then download the new one and apply again. In case we want to save time and bandwidth we can download first and check the diff and if there is any do the update otherwise skip the delete+deploy steps.

@mtojek
Copy link
Contributor

mtojek commented Jul 29, 2021

Why the file will stay there forever? I would expect a "download&replace" approach to work here.

No, it's a different pattern. Logic behind EnsureInstalled runs an embedded "installer" which creates required files and directories in the ~/.elastic-package. It's executed only once per application revision (if newer application is installed, then it will replace the directory), on startup.

Or to be more consistent before downloading the deployer can try to k delete -f any old Agents and then download the new one and apply again. In case we want to save time and bandwidth we can download first and check the diff and if there is any do the update otherwise skip the delete+deploy steps.

That's why I suggested to use this approach. We can download the YAML file in runtime and cache it locally if necessary.

@@ -84,6 +84,22 @@ func Apply(definitionPaths ...string) error {
return nil
}

// ApplyStdin function adds resources to the Kubernetes cluster based on provided stdin.
func ApplyStdin(input string) error {
logger.Debugf("Apply Kubernetes definitions")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: ... from stdin.

logger.Debugf("Apply Kubernetes definitions")
out, err := applyKubernetesResourcesStdin(input)
if err != nil {
return errors.Wrap(err, "can't modify Kubernetes resources (apply)")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: ... apply from stdin

"strings"

"github.com/elastic/elastic-package/internal/install"
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: please sort this line (put it together with other internal

}
// Replace fleet url
elasticAgentManagedYaml = strings.ReplaceAll(elasticAgentManagedYaml,
"https://fleet-server:8220",
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I wonder if we should replace it with regexp in case somebody modifies it:

http(s){0,1}://fleet-server:(\d+)

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 a valid concern. I will change it

@@ -7,3 +7,7 @@
- name: service.type
type: keyword
description: Service type
- name: orchestrator.cluster.name
Copy link
Contributor

Choose a reason for hiding this comment

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

To enable dependency management here, you need to include build.yaml file.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So I will just add this file

Copy link
Contributor

Choose a reason for hiding this comment

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

You need to format it with elastic-package format:

[2021-07-30T13:08:28.902Z] Error: checking package failed: formatting the integration failed (path: /var/lib/jenkins/workspace/t-manager_elastic-package_PR-452/src/github.com/elastic/elastic-package/test/packages/kubernetes, failFast: true): walking through the integration files failed: formatting file failed (path: /var/lib/jenkins/workspace/t-manager_elastic-package_PR-452/src/github.com/elastic/elastic-package/test/packages/kubernetes/_dev/build/build.yml): file is not formatted (path: /var/lib/jenkins/workspace/t-manager_elastic-package_PR-452/src/github.com/elastic/elastic-package/test/packages/kubernetes/_dev/build/build.yml)

@MichaelKatsoulis MichaelKatsoulis marked this pull request as ready for review July 30, 2021 14:06
if err != nil {
return "", errors.Wrap(err, "can't read application configuration")
}
elasticAgentManagedYaml, err := downloadElasticAgentManagedYAML(elasticAgentManagedYamlURL)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: YAML comes as bytes. Did you check if we can skip converting to string? It seems that byte-body will fit well here.

if err != nil {
return "", errors.Wrap(err, "can't read application configuration")
}
elasticAgentManagedYaml, err := downloadElasticAgentManagedYAML(elasticAgentManagedYamlURL)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: please add a logger debug indicating the download from upstream

logger.Debugf("Apply Kubernetes stdin")
out, err := applyKubernetesResourcesStdin(input)
if err != nil {
return errors.Wrap(err, "can't modify Kubernetes resources (apply from stdin)")
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think you're right in L89, "apply stdin"

}

err = kubectl.Apply(locationManager.KubernetesDeployerAgentYml())
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: logger debug: downloaded N bytes

defer resp.Body.Close()

// Convert to string
b, err := io.ReadAll(resp.Body)
Copy link
Contributor

Choose a reason for hiding this comment

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

is it necessary to go with 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.

It is not necessary. I did that in order to use it later in Regexp ReplaceAllString.
But I can instead use ReplaceAll that takes a slice of bytes as input.

Copy link
Contributor

Choose a reason for hiding this comment

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

But I can instead use ReplaceAll that takes a slice of bytes as input.

Sounds good to me

// Get the data
resp, err := http.Get(url)
if err != nil {
return "", errors.Wrapf(err, "failed to get file from url %s", url)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: from URL

@@ -49,3 +50,21 @@ func modifyKubernetesResources(action string, definitionPaths ...string) ([]byte
}
return output, nil
}

// applyKubernetesResourcesStdin applies a kubernetes manifest provided as stdin.
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: a Kubernetes manifest

….com:MichaelKatsoulis/elastic-package into use_upstream_manifest_to_deploy_agent_on_k8s

// getElasticAgentYaml retrieves elastic-agent-managed.yaml from upstream and modifies the file as needed
// to run locally.
func getElasticAgentYaml() ([]byte, error) {
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: ...YAML()

@mtojek
Copy link
Contributor

mtojek commented Aug 2, 2021

@MichaelKatsoulis Ship it, please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request Team:Integrations Label for the Integrations team
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Use upstream's manifest to deploy agent on k8s for tests
4 participants