Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
@@ -0,0 +1,29 @@
/*
* Copyright (C) 2023 Intergral GmbH
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/

package com.intergral.deep.agent.api;

public class DeepRuntimeException extends RuntimeException {

public DeepRuntimeException(final String message) {
super(message);
}

public DeepRuntimeException(final String message, final Throwable cause) {
super(message, cause);
}
}
19 changes: 19 additions & 0 deletions agent-api/src/main/java/com/intergral/deep/agent/api/IDeep.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,25 @@
*/
public interface IDeep {

/**
* Get the current state of deep.
*
* @return {@code true} if deep is currently enabled and sending requests, else {@code false}
*/
boolean isEnabled();


/**
* This method can be used to disabled or enable Deep.
* <p>
* Changing the state to {@code false} (ie disabled) will cause deep to uninstall all the tracepoints and clear the current config.
* Meaning that when deep is enabled again it will have to reinstall the configuration. It is therefore advised to not call this function
* too frequently.
*
* @param enabled the new state to become
*/
void setEnabled(final boolean enabled);

/**
* Get the version of deep being used.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,17 @@
/**
* This is a generic interface from the result of a registration.
*/
public interface IRegistration {
public interface IRegistration<T> {

/**
* Unregister the item registered.
*/
void unregister();

/**
* Get the registered item
*
* @return the item that this registration is for.
*/
T get();
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@

package com.intergral.deep.agent.api.auth;

import com.intergral.deep.agent.api.DeepRuntimeException;
import com.intergral.deep.agent.api.plugin.IPlugin;
import com.intergral.deep.agent.api.settings.ISettings;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
Expand All @@ -32,6 +34,18 @@ public static IAuthProvider provider(final ISettings settings) {
if (serviceAuthProvider == null || serviceAuthProvider.trim().isEmpty()) {
return NOOP_PROVIDER;
}

// check if we have a plugin of this name that we can use
final IPlugin plugin = settings.getPlugin(serviceAuthProvider);
if (plugin != null) {
if (plugin instanceof IAuthProvider) {
return (IAuthProvider) plugin;
} else {
throw new DeepRuntimeException(
String.format("Cannot use plugin %s as auth provider, must implement IAuthProvider interface.", plugin.name()));
}
}

try {
final Class<?> aClass = Class.forName(serviceAuthProvider);
final Constructor<?> constructor = aClass.getConstructor(ISettings.class);
Expand All @@ -42,7 +56,7 @@ public static IAuthProvider provider(final ISettings settings) {
| InvocationTargetException
| InstantiationException
| IllegalAccessException e) {
throw new RuntimeException(e);
throw new RuntimeException(String.format("Cannot load auth provider %s", serviceAuthProvider), e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,14 @@ default boolean isActive(final ISettings settings) {
/**
* This type describes a registered plugin.
*/
interface IPluginRegistration extends IRegistration {
interface IPluginRegistration extends IRegistration<IPlugin> {

/**
* Indicates if this plugin is currently set to be the auth provider
*
* @return {@code true} if the registered plugin is an {@link com.intergral.deep.agent.api.auth.IAuthProvider} and deep is configured to
* use this provider, else {@code false}
*/
boolean isAuthProvider();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,18 @@ public final class ConfigurationException extends RuntimeException {

/**
* Create a new configuration exception with specified {@code message} and without a cause.
*
* @param message The exception message
*/
public ConfigurationException(String message) {
super(message);
}

/**
* Create a new configuration exception with specified {@code message} and {@code cause}.
*
* @param message The exception message
* @param cause The root cause of this exception
*/
public ConfigurationException(String message, Throwable cause) {
super(message, cause);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,43 @@

package com.intergral.deep.agent.api.settings;

import com.intergral.deep.agent.api.plugin.IPlugin;
import com.intergral.deep.agent.api.resource.Resource;
import java.util.Map;

public interface ISettings {

/**
* This is the settings key for the configured auth provider
*/
String KEY_AUTH_PROVIDER = "service.auth.provider";

/**
* This is the setting key for enabling or disabling deep.
*/
String KEY_ENABLED = "enabled";

/**
* This is the setting key for the service url
*/
String KEY_SERVICE_URL = "service.url";

<T> T getSettingAs(String key, Class<T> clazz);

Map<String, String> getMap(String attributeProperty);

/**
* Returns the resource that describes this client
*
* @return the {@link Resource}
*/
Resource getResource();

/**
* Look for a plugin with the given name or class name.
*
* @param name the plugin name or the plugin class name
* @return the {@link IPlugin} or {@code null}
*/
IPlugin getPlugin(final String name);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ public interface Ordered {
* Returns the order of applying the SPI implementing this interface. Higher values are applied
* later, for example: an SPI with order=1 will run after an SPI with order=0. SPI implementations
* with equal values will be run in a non-deterministic order.
*
* @return the order value
*/
default int order() {
return 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ default String id() {
return UUID.randomUUID().toString();
}

interface ITracepointRegistration extends IRegistration {
interface ITracepointRegistration extends IRegistration<ITracepoint> {

}
}
85 changes: 83 additions & 2 deletions agent/src/main/java/com/intergral/deep/agent/DeepAgent.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,12 @@

import com.intergral.deep.agent.api.DeepVersion;
import com.intergral.deep.agent.api.IDeep;
import com.intergral.deep.agent.api.auth.IAuthProvider;
import com.intergral.deep.agent.api.plugin.IPlugin;
import com.intergral.deep.agent.api.plugin.IPlugin.IPluginRegistration;
import com.intergral.deep.agent.api.resource.Resource;
import com.intergral.deep.agent.api.settings.ISettings;
import com.intergral.deep.agent.api.tracepoint.ITracepoint;
import com.intergral.deep.agent.api.tracepoint.ITracepoint.ITracepointRegistration;
import com.intergral.deep.agent.grpc.GrpcService;
import com.intergral.deep.agent.plugins.PluginLoader;
Expand Down Expand Up @@ -74,7 +77,29 @@ public String getVersion() {

public IPluginRegistration registerPlugin(final IPlugin plugin) {
this.settings.addPlugin(plugin);
return () -> this.settings.removePlugin(plugin);
final boolean isAuthProvider;
if (plugin instanceof IAuthProvider) {
final String settingAs = this.settings.getSettingAs(ISettings.KEY_AUTH_PROVIDER, String.class);
isAuthProvider = settingAs != null && settingAs.equals(plugin.getClass().getName());
} else {
isAuthProvider = false;
}
return new IPluginRegistration() {
@Override
public boolean isAuthProvider() {
return isAuthProvider;
}

@Override
public void unregister() {
settings.removePlugin(plugin);
}

@Override
public IPlugin get() {
return plugin;
}
};
}

@Override
Expand All @@ -86,6 +111,62 @@ public ITracepointRegistration registerTracepoint(final String path, final int l
public ITracepointRegistration registerTracepoint(final String path, final int line, final Map<String, String> args,
final Collection<String> watches) {
final TracePointConfig tracePointConfig = this.tracepointConfig.addCustom(path, line, args, watches);
return () -> this.tracepointConfig.removeCustom(tracePointConfig);
return new ITracepointRegistration() {
@Override
public void unregister() {
tracepointConfig.removeCustom(tracePointConfig);
}

@Override
public ITracepoint get() {
return new ITracepoint() {
@Override
public String path() {
return path;
}

@Override
public int line() {
return line;
}

@Override
public Map<String, String> args() {
return args;
}

@Override
public Collection<String> watches() {
return watches;
}

@Override
public String id() {
return tracePointConfig.getId();
}
};
}
};
}

@Override
public boolean isEnabled() {
return this.settings.getSettingAs(ISettings.KEY_ENABLED, Boolean.class);
}

@Override
public synchronized void setEnabled(final boolean enabled) {
// we are already the desired state - so do nothing
if (isEnabled() == enabled) {
return;
}

// update config to new state
this.settings.setActive(enabled);

// if we are disabling then we need to clear configs
if (!enabled) {
this.tracepointConfig.configUpdate(0, null, Collections.emptyList());
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@ public void start(final ITracepointConfig tracepointConfig) {

@Override
public void run(long now) {
if (!this.settings.isActive()) {
// we have been disabled so skip this poll
// we will pause like normal and try again later
return;
}
final PollConfigGrpc.PollConfigBlockingStub blockingStub = this.grpcService.pollService();

final PollRequest.Builder builder = PollRequest.newBuilder();
Expand All @@ -69,7 +74,10 @@ public void run(long now) {
.build();

final PollResponse response = blockingStub.poll(pollRequest);

// check we are still active
if (!this.settings.isActive()) {
return;
}
if (response.getResponseType() == ResponseType.NO_CHANGE) {
this.tracepointConfig.noChange(response.getTsNanos());
} else {
Expand Down
Loading