Add necessary improvements and configs for grafana version 10.3.3 #396

Merged
navodzoysa merged 5 commits from Sasini_Sandamali/device-mgt-core-forked:master into master 5 months ago

@ -107,6 +107,23 @@ public interface GrafanaAPIProxyService {
) )
Response frontendMetrics(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo); Response frontendMetrics(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo);
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/user/auth-tokens/rotate")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "POST",
value = "Rotate authentication tokens",
tags = "Analytics",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "grafana:api:view")
})
}
)
Response rotateAuthToken(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo);
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/dashboards/uid/{uid}") @Path("/dashboards/uid/{uid}")
@ -123,6 +140,22 @@ public interface GrafanaAPIProxyService {
) )
Response getDashboard(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException; Response getDashboard(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/folders/{uid}")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Grafana dashboard folder information",
tags = "Analytics",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "grafana:api:view")
})
}
)
Response getFolders(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@ -140,6 +173,23 @@ public interface GrafanaAPIProxyService {
) )
Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException; Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
@GET
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/prometheus/grafana/api/v1/rules")
@ApiOperation(
produces = MediaType.APPLICATION_JSON,
httpMethod = "GET",
value = "Accessing Grafana Prometheus rule information",
tags = "Analytics",
extensions = {
@Extension(properties = {
@ExtensionProperty(name = SCOPE, value = "grafana:api:view")
})
}
)
Response prometheusRuleInfo(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) throws ClassNotFoundException;
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/alerts/states-for-dashboard") @Path("/alerts/states-for-dashboard")

@ -26,6 +26,8 @@ import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util.Grafa
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util.GrafanaRequestHandlerUtil; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.impl.util.GrafanaRequestHandlerUtil;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.common.exception.GrafanaManagementException; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.common.exception.GrafanaManagementException;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.bean.GrafanaPanelIdentifier; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.bean.GrafanaPanelIdentifier;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.GrafanaConfiguration;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.GrafanaConfigurationManager;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.exception.MaliciousQueryAttempt; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.exception.MaliciousQueryAttempt;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
@ -56,9 +58,13 @@ public class GrafanaAPIProxyServiceImpl implements GrafanaAPIProxyService {
@Override @Override
public Response queryDatasource(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) { public Response queryDatasource(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
try { try {
GrafanaConfiguration configuration = GrafanaConfigurationManager.getInstance().getGrafanaConfiguration();
GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers); GrafanaPanelIdentifier panelIdentifier = GrafanaRequestHandlerUtil.getPanelIdentifier(headers);
GrafanaMgtAPIUtils.getGrafanaQueryService().buildSafeQuery(body, panelIdentifier.getDashboardId(), boolean queryValidationConfig = configuration.getValidationConfig().getDSQueryValidation();
panelIdentifier.getPanelId(), requestUriInfo.getRequestUri()); if (queryValidationConfig) {
GrafanaMgtAPIUtils.getGrafanaQueryService().buildSafeQuery(body, panelIdentifier.getDashboardId(),
panelIdentifier.getPanelId(), requestUriInfo.getRequestUri());
}
return GrafanaRequestHandlerUtil.proxyPassPostRequest(body, requestUriInfo, panelIdentifier.getOrgId()); return GrafanaRequestHandlerUtil.proxyPassPostRequest(body, requestUriInfo, panelIdentifier.getOrgId());
} catch (MaliciousQueryAttempt e) { } catch (MaliciousQueryAttempt e) {
return Response.status(Response.Status.BAD_REQUEST).entity( return Response.status(Response.Status.BAD_REQUEST).entity(
@ -83,6 +89,15 @@ public class GrafanaAPIProxyServiceImpl implements GrafanaAPIProxyService {
return proxyPassPostRequest(body, headers, requestUriInfo); return proxyPassPostRequest(body, headers, requestUriInfo);
} }
@POST
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/user/auth-tokens/rotate")
@Override
public Response rotateAuthToken(JsonObject body, @Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
return proxyPassPostRequest(body, headers, requestUriInfo);
}
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/dashboards/uid/{uid}") @Path("/dashboards/uid/{uid}")
@ -91,6 +106,14 @@ public class GrafanaAPIProxyServiceImpl implements GrafanaAPIProxyService {
return proxyPassGetRequest(headers, requestUriInfo); return proxyPassGetRequest(headers, requestUriInfo);
} }
@GET
@Produces(MediaType.APPLICATION_JSON)
@Path("/folders/{uid}")
@Override
public Response getFolders(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
return proxyPassGetRequest(headers, requestUriInfo);
}
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON)
@ -99,6 +122,16 @@ public class GrafanaAPIProxyServiceImpl implements GrafanaAPIProxyService {
public Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) { public Response getAnnotations(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
return proxyPassGetRequest(headers, requestUriInfo); return proxyPassGetRequest(headers, requestUriInfo);
} }
@GET
@Produces(MediaType.APPLICATION_JSON)
@Consumes(MediaType.APPLICATION_JSON)
@Path("/prometheus/grafana/api/v1/rules")
@Override
public Response prometheusRuleInfo(@Context HttpHeaders headers, @Context UriInfo requestUriInfo) {
return proxyPassGetRequest(headers, requestUriInfo);
}
@GET @GET
@Produces(MediaType.APPLICATION_JSON) @Produces(MediaType.APPLICATION_JSON)
@Path("/alerts/states-for-dashboard") @Path("/alerts/states-for-dashboard")

@ -22,6 +22,8 @@ import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.bean.ErrorRespo
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.exception.RefererNotValid; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.api.exception.RefererNotValid;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.common.exception.GrafanaManagementException; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.common.exception.GrafanaManagementException;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.bean.GrafanaPanelIdentifier; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.bean.GrafanaPanelIdentifier;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.GrafanaConfiguration;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.GrafanaConfigurationManager;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.exception.GrafanaEnvVariablesNotDefined; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.exception.GrafanaEnvVariablesNotDefined;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.util.GrafanaConstants; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.util.GrafanaConstants;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.util.GrafanaUtil; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.util.GrafanaUtil;
@ -120,19 +122,23 @@ public class GrafanaRequestHandlerUtil {
return path; return path;
} }
public static GrafanaPanelIdentifier getPanelIdentifier(HttpHeaders headers) throws RefererNotValid { public static GrafanaPanelIdentifier getPanelIdentifier(HttpHeaders headers) throws RefererNotValid, GrafanaManagementException {
String referer = headers.getHeaderString(GrafanaConstants.REFERER_HEADER); String referer = headers.getHeaderString(GrafanaConstants.REFERER_HEADER);
if(referer == null) { if (referer == null) {
String errMsg = "Request does not contain Referer header"; String errMsg = "Request does not contain Referer header";
log.error(errMsg); log.error(errMsg);
throw new RefererNotValid(errMsg); throw new RefererNotValid(errMsg);
} }
GrafanaConfiguration configuration = GrafanaConfigurationManager.getInstance().getGrafanaConfiguration();
boolean dashboardIntegrationConfig = configuration.getValidationConfig().getDashboardIntegration();
GrafanaPanelIdentifier panelIdentifier = GrafanaUtil.getPanelIdentifierFromReferer(referer); GrafanaPanelIdentifier panelIdentifier = GrafanaUtil.getPanelIdentifierFromReferer(referer);
if(panelIdentifier.getDashboardId() == null || if (!dashboardIntegrationConfig) {
panelIdentifier.getPanelId() == null || panelIdentifier.getOrgId() == null) { if (panelIdentifier.getDashboardId() == null ||
String errMsg = "Referer must contain dashboardId, panelId and orgId"; panelIdentifier.getPanelId() == null || panelIdentifier.getOrgId() == null) {
log.error(errMsg); String errMsg = "Referer must contain dashboardId, panelId, and orgId";
throw new RefererNotValid(errMsg); log.error(errMsg);
throw new RefererNotValid(errMsg);
}
} }
return panelIdentifier; return panelIdentifier;
} }

@ -19,6 +19,7 @@
package io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config; package io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean.CacheConfiguration; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean.CacheConfiguration;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean.ValidationConfig;
import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean.User; import io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean.User;
import javax.xml.bind.annotation.XmlElement; import javax.xml.bind.annotation.XmlElement;
@ -30,6 +31,7 @@ import java.util.List;
public class GrafanaConfiguration { public class GrafanaConfiguration {
private User adminUser; private User adminUser;
private ValidationConfig validationConfig;
private List<CacheConfiguration> caches; private List<CacheConfiguration> caches;
@XmlElement(name = "AdminUser") @XmlElement(name = "AdminUser")
@ -37,6 +39,15 @@ public class GrafanaConfiguration {
return adminUser; return adminUser;
} }
@XmlElement(name = "ValidationConfig")
public ValidationConfig getValidationConfig() {
return validationConfig;
}
public void setValidationConfig(ValidationConfig validationConfig) {
this.validationConfig = validationConfig;
}
public void setAdminUser(User user) { public void setAdminUser(User user) {
this.adminUser = user; this.adminUser = user;
} }

@ -0,0 +1,45 @@
/*
* Copyright (c) 2018 - 2024, Entgra (Pvt) Ltd. (http://www.entgra.io) All Rights Reserved.
*
* Entgra (Pvt) Ltd. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package io.entgra.device.mgt.core.analytics.mgt.grafana.proxy.core.config.xml.bean;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
@XmlRootElement(name = "ValidationConfig")
public class ValidationConfig {
private boolean dsQueryValidation;
private boolean dashboardIntegration;
@XmlElement(name = "DSQueryValidation")
public boolean getDSQueryValidation() {
return dsQueryValidation;
}
public void setDSQueryValidation(boolean dsQueryValidation) {
this.dsQueryValidation = dsQueryValidation;
}
@XmlElement(name = "DashboardIntegration")
public boolean getDashboardIntegration() {
return dashboardIntegration;
}
public void setDashboardIntegration(boolean dashboardIntegration) {
this.dashboardIntegration = dashboardIntegration;
}
}

@ -32,4 +32,10 @@
<Username>admin</Username> <Username>admin</Username>
<Password>admin</Password> <Password>admin</Password>
</AdminUser> </AdminUser>
<ValidationConfig>
<!-- Enable/Disable data source query validation. -->
<DSQueryValidation>true</DSQueryValidation>
<!-- Enable/Disable dashboard integration. -->
<DashboardIntegration>false</DashboardIntegration>
</ValidationConfig>
</GrafanaConfiguration> </GrafanaConfiguration>

@ -32,4 +32,10 @@
<Username>admin</Username> <Username>admin</Username>
<Password>admin</Password> <Password>admin</Password>
</AdminUser> </AdminUser>
<ValidationConfig>
<!-- Enable/Disable data source query validation. -->
<DSQueryValidation>true</DSQueryValidation>
<!-- Enable/Disable dashboard integration. -->
<DashboardIntegration>false</DashboardIntegration>
</ValidationConfig>
</GrafanaConfiguration> </GrafanaConfiguration>

Loading…
Cancel
Save