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

Extract logs retriever API #311

Merged
merged 3 commits into from
Feb 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,26 @@

package io.jenkins.plugins.opentelemetry.backend;

import com.cloudbees.plugins.credentials.Credentials;
import com.cloudbees.plugins.credentials.SystemCredentialsProvider;
import com.cloudbees.plugins.credentials.common.IdCredentials;
import com.cloudbees.plugins.credentials.common.StandardListBoxModel;
import com.cloudbees.plugins.credentials.common.StandardUsernameCredentials;
import com.cloudbees.plugins.credentials.common.UsernamePasswordCredentials;
import hudson.Extension;
import hudson.Util;
import hudson.model.Item;
import hudson.security.ACL;
import hudson.util.FormValidation;
import hudson.util.ListBoxModel;
import io.jenkins.plugins.opentelemetry.backend.elastic.ElasticsearchRetriever;
import io.jenkins.plugins.opentelemetry.backend.elastic.ElasticsearchLogStorageRetriever;
import io.jenkins.plugins.opentelemetry.job.log.LogStorageRetriever;
import jenkins.model.Jenkins;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestClientBuilder;
import org.jenkinsci.Symbol;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.interceptor.RequirePOST;

import javax.annotation.CheckForNull;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
Expand Down Expand Up @@ -71,7 +63,7 @@ public class ElasticBackend extends ObservabilityBackend {
@CheckForNull
private String elasticsearchUrl;
@CheckForNull
private String elasticsearcCredentialsId;
private String elasticsearchCredentialsId;
@CheckForNull
private String indexPattern = "logs-*";

Expand Down Expand Up @@ -154,6 +146,16 @@ public String getMetricsVisualizationUrlTemplate() {
}
}

@Nullable
@Override
public LogStorageRetriever getLogStorageRetriever() {
if (StringUtils.isNotBlank(this.elasticsearchUrl)) {
return new ElasticsearchLogStorageRetriever(this.elasticsearchUrl, ElasticsearchLogStorageRetriever.getCredentials(this.elasticsearchCredentialsId), indexPattern);
} else {
return null;
}
}

public String getKibanaSpaceIdentifier() {
return Objects.toString(kibanaSpaceIdentifier, DEFAULT_KIBANA_SPACE_IDENTIFIER);
}
Expand Down Expand Up @@ -191,8 +193,8 @@ public void setDisplayKibanaDashboardLink(boolean displayKibanaDashboardLink) {
}

@DataBoundSetter
public void setElasticsearcCredentialsId(@CheckForNull String elasticsearcCredentialsId) {
this.elasticsearcCredentialsId = elasticsearcCredentialsId;
public void setElasticsearchCredentialsId(@CheckForNull String elasticsearchCredentialsId) {
this.elasticsearchCredentialsId = elasticsearchCredentialsId;
}

@CheckForNull
Expand All @@ -206,24 +208,8 @@ public void setIndexPattern(@CheckForNull String indexPattern) {
}

@CheckForNull
public String getElasticsearcCredentialsId() {
return elasticsearcCredentialsId;
}

@Nonnull
public UsernamePasswordCredentials getCredentials() throws NoSuchElementException {
return getCredentials(elasticsearcCredentialsId);
}

@Nonnull
public static UsernamePasswordCredentials getCredentials(String credentialsId) throws NoSuchElementException {
Optional<Credentials> optionalCredentials = SystemCredentialsProvider.getInstance().getCredentials().stream()
.filter(credentials ->
(credentials instanceof UsernamePasswordCredentials)
&& ((IdCredentials) credentials)
.getId().equals(credentialsId))
.findAny();
return (UsernamePasswordCredentials) optionalCredentials.get();
public String getElasticsearchCredentialsId() {
return elasticsearchCredentialsId;
}

@CheckForNull
Expand All @@ -247,12 +233,12 @@ public boolean equals(Object o) {
Objects.equals(kibanaDashboardTitle, that.kibanaDashboardTitle) &&
Objects.equals(kibanaDashboardUrlParameters, that.kibanaDashboardUrlParameters)
&& Objects.equals(elasticsearchUrl, that.elasticsearchUrl)
&& Objects.equals(elasticsearcCredentialsId, that.elasticsearcCredentialsId);
&& Objects.equals(elasticsearchCredentialsId, that.elasticsearchCredentialsId);
}

@Override
public int hashCode() {
return Objects.hash(displayKibanaDashboardLink, kibanaBaseUrl, kibanaSpaceIdentifier, kibanaDashboardTitle, kibanaDashboardUrlParameters, elasticsearchUrl, elasticsearcCredentialsId);
return Objects.hash(displayKibanaDashboardLink, kibanaBaseUrl, kibanaSpaceIdentifier, kibanaDashboardTitle, kibanaDashboardUrlParameters, elasticsearchUrl, elasticsearchCredentialsId);
}

@Extension
Expand Down Expand Up @@ -304,26 +290,26 @@ public FormValidation doCheckElasticsearchUrl(@QueryParameter("elasticsearchUrl"
}

@RequirePOST
public ListBoxModel doFillElasticsearcCredentialsIdItems(Item context, @QueryParameter String elasticsearcCredentialsId) {
public ListBoxModel doFillElasticsearchCredentialsIdItems(Item context, @QueryParameter String elasticsearchCredentialsId) {
if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)
|| context != null && !context.hasPermission(context.CONFIGURE)) {
return new StandardListBoxModel();
}

return new StandardListBoxModel().includeEmptyValue()
.includeAs(ACL.SYSTEM, context, StandardUsernameCredentials.class)
.includeCurrentValue(elasticsearcCredentialsId);
.includeCurrentValue(elasticsearchCredentialsId);
}

@RequirePOST
public FormValidation doCheckElasticsearcCredentialsId(Item context, @QueryParameter String elasticsearcCredentialsId) {
public FormValidation doCheckElasticsearchCredentialsId(Item context, @QueryParameter String elasticsearchCredentialsId) {
if (context == null && !Jenkins.get().hasPermission(Jenkins.ADMINISTER)
|| context != null && !context.hasPermission(context.CONFIGURE)) {
return FormValidation.ok();
}

try {
getCredentials(elasticsearcCredentialsId);
ElasticsearchLogStorageRetriever.getCredentials(elasticsearchCredentialsId);
} catch (NoSuchElementException e) {
return FormValidation.warning("The credentials are not valid.");
}
Expand All @@ -347,28 +333,17 @@ public FormValidation doValidate(@QueryParameter String credentialsId, @QueryPar
}

try {
UsernamePasswordCredentials jenkinsCredentials = getCredentials(credentialsId);
BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider();
org.apache.http.auth.UsernamePasswordCredentials credentials = new org.apache.http.auth.UsernamePasswordCredentials(
jenkinsCredentials.getUsername(), jenkinsCredentials.getPassword().getPlainText());
credentialsProvider.setCredentials(AuthScope.ANY, credentials);

RestClientBuilder builder = RestClient.builder(HttpHost.create(elasticsearchUrl));
builder.setHttpClientConfigCallback(
httpClientBuilder -> httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider));

ElasticsearchRetriever elasticsearchRetriever = new ElasticsearchRetriever(elasticsearchUrl, jenkinsCredentials.getUsername(),
jenkinsCredentials.getPassword().getPlainText(), indexPattern
);
if (elasticsearchRetriever.indexExists()) {
ElasticsearchLogStorageRetriever elasticsearchLogStorageRetriever = new ElasticsearchLogStorageRetriever(elasticsearchUrl, ElasticsearchLogStorageRetriever.getCredentials(credentialsId), indexPattern);

if (elasticsearchLogStorageRetriever.indexExists()) {
return FormValidation.ok("success");
}
} catch (NoSuchElementException e) {
return FormValidation.error("Invalid credentials.");
} catch (IllegalArgumentException e) {
return FormValidation.error(e, "Invalid Argument.");
return FormValidation.error(e, e.getMessage());
} catch (IOException e) {
return FormValidation.error(e, "Unable to connect.");
return FormValidation.error(e, e.getMessage());
} catch (Exception e) {
return FormValidation.error(e, e.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,23 @@

import com.google.common.base.Strings;
import com.google.common.collect.ComparisonChain;
import com.google.common.collect.Maps;
import groovy.lang.Binding;
import groovy.lang.MissingPropertyException;
import groovy.lang.Writable;
import groovy.text.GStringTemplateEngine;
import groovy.text.Template;
import hudson.DescriptorExtensionList;
import hudson.ExtensionPoint;
import hudson.model.Describable;
import hudson.model.Descriptor;
import io.opentelemetry.api.common.AttributeKey;
import io.jenkins.plugins.opentelemetry.job.log.LogStorageRetriever;
import io.opentelemetry.sdk.resources.Resource;
import jenkins.model.Jenkins;
import org.kohsuke.stapler.DataBoundSetter;

import javax.annotation.CheckForNull;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import java.util.function.BiConsumer;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -63,6 +58,14 @@ public abstract class ObservabilityBackend implements Describable<ObservabilityB
@Override
public abstract int hashCode();

/**
* @return the {@link LogStorageRetriever} of this backend if the backend is configured to retrieve logs. {@code null} otherwise.
*/
@CheckForNull
public LogStorageRetriever getLogStorageRetriever() {
return null;
}

/**
* For extensions
*/
Expand Down Expand Up @@ -118,7 +121,7 @@ public String getMetricsVisualizationUrl(Resource resource) {
}
Map<String, String> resourceMap =
resource.getAttributes().asMap().entrySet().stream()
.collect(Collectors.toMap(entry -> entry.getKey().getKey(), entry -> Objects.toString(entry.getValue())));
.collect(Collectors.toMap(entry -> entry.getKey().getKey(), entry -> Objects.toString(entry.getValue())));
Map<String, Object> mergedBindings = mergeBindings(Collections.singletonMap("resource", resourceMap));

try {
Expand Down
Loading