mirror of
https://github.com/SigNoz/signoz.git
synced 2026-04-23 12:20:31 +01:00
Compare commits
1 Commits
feat/cloud
...
test/resou
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2e04d805e9 |
@@ -167,7 +167,7 @@ func runServer(ctx context.Context, config signoz.Config, logger *slog.Logger) e
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider(defStore)
|
||||
azureCloudProviderModule := implcloudprovider.NewAzureCloudProvider()
|
||||
cloudProvidersMap := map[cloudintegrationtypes.CloudProviderType]cloudintegration.CloudProviderModule{
|
||||
cloudintegrationtypes.CloudProviderTypeAWS: awsCloudProviderModule,
|
||||
cloudintegrationtypes.CloudProviderTypeAzure: azureCloudProviderModule,
|
||||
|
||||
@@ -668,8 +668,8 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSAccountConfig'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureAccountConfig'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesAgentReport:
|
||||
nullable: true
|
||||
@@ -693,90 +693,6 @@ components:
|
||||
nullable: true
|
||||
type: array
|
||||
type: object
|
||||
CloudintegrationtypesAzureAccountConfig:
|
||||
properties:
|
||||
deploymentRegion:
|
||||
type: string
|
||||
resourceGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- deploymentRegion
|
||||
- resourceGroups
|
||||
type: object
|
||||
CloudintegrationtypesAzureConnectionArtifact:
|
||||
properties:
|
||||
cliCommand:
|
||||
type: string
|
||||
cloudPowerShellCommand:
|
||||
type: string
|
||||
required:
|
||||
- cliCommand
|
||||
- cloudPowerShellCommand
|
||||
type: object
|
||||
CloudintegrationtypesAzureIntegrationConfig:
|
||||
properties:
|
||||
deploymentRegion:
|
||||
type: string
|
||||
resourceGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
telemetryCollectionStrategy:
|
||||
items:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureTelemetryCollectionStrategy'
|
||||
type: array
|
||||
required:
|
||||
- deploymentRegion
|
||||
- resourceGroups
|
||||
- telemetryCollectionStrategy
|
||||
type: object
|
||||
CloudintegrationtypesAzureLogsCollectionStrategy:
|
||||
properties:
|
||||
categoryGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- categoryGroups
|
||||
type: object
|
||||
CloudintegrationtypesAzureMetricsCollectionStrategy:
|
||||
type: object
|
||||
CloudintegrationtypesAzureServiceConfig:
|
||||
properties:
|
||||
logs:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceLogsConfig'
|
||||
metrics:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceMetricsConfig'
|
||||
required:
|
||||
- logs
|
||||
- metrics
|
||||
type: object
|
||||
CloudintegrationtypesAzureServiceLogsConfig:
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
type: object
|
||||
CloudintegrationtypesAzureServiceMetricsConfig:
|
||||
properties:
|
||||
enabled:
|
||||
type: boolean
|
||||
type: object
|
||||
CloudintegrationtypesAzureTelemetryCollectionStrategy:
|
||||
properties:
|
||||
logs:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureLogsCollectionStrategy'
|
||||
metrics:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureMetricsCollectionStrategy'
|
||||
resourceProvider:
|
||||
type: string
|
||||
resourceType:
|
||||
type: string
|
||||
required:
|
||||
- resourceProvider
|
||||
- resourceType
|
||||
type: object
|
||||
CloudintegrationtypesCloudIntegrationService:
|
||||
nullable: true
|
||||
properties:
|
||||
@@ -821,8 +737,8 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSConnectionArtifact'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureConnectionArtifact'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesCredentials:
|
||||
properties:
|
||||
@@ -994,8 +910,8 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSPostableAccountConfig'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureAccountConfig'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesPostableAgentCheckIn:
|
||||
properties:
|
||||
@@ -1018,8 +934,8 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSIntegrationConfig'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureIntegrationConfig'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesService:
|
||||
properties:
|
||||
@@ -1056,8 +972,8 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSServiceConfig'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureServiceConfig'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesServiceID:
|
||||
enum:
|
||||
@@ -1074,8 +990,6 @@ components:
|
||||
- s3sync
|
||||
- sns
|
||||
- sqs
|
||||
- storageaccountsblob
|
||||
- cdnprofile
|
||||
type: string
|
||||
CloudintegrationtypesServiceMetadata:
|
||||
properties:
|
||||
@@ -1104,32 +1018,16 @@ components:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSTelemetryCollectionStrategy'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAzureTelemetryCollectionStrategy'
|
||||
required:
|
||||
- aws
|
||||
type: object
|
||||
CloudintegrationtypesUpdatableAccount:
|
||||
properties:
|
||||
config:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesUpdatableAccountConfig'
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAccountConfig'
|
||||
required:
|
||||
- config
|
||||
type: object
|
||||
CloudintegrationtypesUpdatableAccountConfig:
|
||||
properties:
|
||||
aws:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesAWSAccountConfig'
|
||||
azure:
|
||||
$ref: '#/components/schemas/CloudintegrationtypesUpdatableAzureAccountConfig'
|
||||
type: object
|
||||
CloudintegrationtypesUpdatableAzureAccountConfig:
|
||||
properties:
|
||||
resourceGroups:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- resourceGroups
|
||||
type: object
|
||||
CloudintegrationtypesUpdatableService:
|
||||
properties:
|
||||
config:
|
||||
|
||||
@@ -2,47 +2,27 @@ package implcloudprovider
|
||||
|
||||
import (
|
||||
"context"
|
||||
"sort"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/modules/cloudintegration"
|
||||
"github.com/SigNoz/signoz/pkg/types/cloudintegrationtypes"
|
||||
)
|
||||
|
||||
type azurecloudprovider struct {
|
||||
serviceDefinitions cloudintegrationtypes.ServiceDefinitionStore
|
||||
}
|
||||
type azurecloudprovider struct{}
|
||||
|
||||
func NewAzureCloudProvider(defStore cloudintegrationtypes.ServiceDefinitionStore) cloudintegration.CloudProviderModule {
|
||||
return &azurecloudprovider{
|
||||
serviceDefinitions: defStore,
|
||||
}
|
||||
func NewAzureCloudProvider() cloudintegration.CloudProviderModule {
|
||||
return &azurecloudprovider{}
|
||||
}
|
||||
|
||||
func (provider *azurecloudprovider) GetConnectionArtifact(ctx context.Context, account *cloudintegrationtypes.Account, req *cloudintegrationtypes.GetConnectionArtifactRequest) (*cloudintegrationtypes.ConnectionArtifact, error) {
|
||||
cliCommand := cloudintegrationtypes.NewAzureConnectionCLICommand(account.ID, req.Config.AgentVersion, req.Credentials, req.Config.Azure)
|
||||
psCommand := cloudintegrationtypes.NewAzureConnectionPowerShellCommand(account.ID, req.Config.AgentVersion, req.Credentials, req.Config.Azure)
|
||||
|
||||
return &cloudintegrationtypes.ConnectionArtifact{
|
||||
Azure: cloudintegrationtypes.NewAzureConnectionArtifact(cliCommand, psCommand),
|
||||
}, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (provider *azurecloudprovider) ListServiceDefinitions(ctx context.Context) ([]*cloudintegrationtypes.ServiceDefinition, error) {
|
||||
return provider.serviceDefinitions.List(ctx, cloudintegrationtypes.CloudProviderTypeAzure)
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (provider *azurecloudprovider) GetServiceDefinition(ctx context.Context, serviceID cloudintegrationtypes.ServiceID) (*cloudintegrationtypes.ServiceDefinition, error) {
|
||||
serviceDef, err := provider.serviceDefinitions.Get(ctx, cloudintegrationtypes.CloudProviderTypeAzure, serviceID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// override cloud integration dashboard id.
|
||||
for index, dashboard := range serviceDef.Assets.Dashboards {
|
||||
serviceDef.Assets.Dashboards[index].ID = cloudintegrationtypes.GetCloudIntegrationDashboardID(cloudintegrationtypes.CloudProviderTypeAzure, serviceID.StringValue(), dashboard.ID)
|
||||
}
|
||||
|
||||
return serviceDef, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (provider *azurecloudprovider) BuildIntegrationConfig(
|
||||
@@ -50,56 +30,5 @@ func (provider *azurecloudprovider) BuildIntegrationConfig(
|
||||
account *cloudintegrationtypes.Account,
|
||||
services []*cloudintegrationtypes.StorableCloudIntegrationService,
|
||||
) (*cloudintegrationtypes.ProviderIntegrationConfig, error) {
|
||||
sort.Slice(services, func(i, j int) bool {
|
||||
return services[i].Type.StringValue() < services[j].Type.StringValue()
|
||||
})
|
||||
|
||||
var strategies []*cloudintegrationtypes.AzureTelemetryCollectionStrategy
|
||||
|
||||
for _, storedSvc := range services {
|
||||
svcCfg, err := cloudintegrationtypes.NewServiceConfigFromJSON(cloudintegrationtypes.CloudProviderTypeAzure, storedSvc.Config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
svcDef, err := provider.GetServiceDefinition(ctx, storedSvc.Type)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
strategy := svcDef.TelemetryCollectionStrategy.Azure
|
||||
if strategy == nil {
|
||||
continue
|
||||
}
|
||||
|
||||
logsEnabled := svcCfg.IsLogsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
|
||||
metricsEnabled := svcCfg.IsMetricsEnabled(cloudintegrationtypes.CloudProviderTypeAzure)
|
||||
|
||||
if !logsEnabled && !metricsEnabled {
|
||||
continue
|
||||
}
|
||||
|
||||
entry := &cloudintegrationtypes.AzureTelemetryCollectionStrategy{
|
||||
ResourceProvider: strategy.ResourceProvider,
|
||||
ResourceType: strategy.ResourceType,
|
||||
}
|
||||
|
||||
if metricsEnabled && strategy.Metrics != nil {
|
||||
entry.Metrics = strategy.Metrics
|
||||
}
|
||||
|
||||
if logsEnabled && strategy.Logs != nil {
|
||||
entry.Logs = strategy.Logs
|
||||
}
|
||||
|
||||
strategies = append(strategies, entry)
|
||||
}
|
||||
|
||||
return &cloudintegrationtypes.ProviderIntegrationConfig{
|
||||
Azure: cloudintegrationtypes.NewAzureIntegrationConfig(
|
||||
account.Config.Azure.DeploymentRegion,
|
||||
account.Config.Azure.ResourceGroups,
|
||||
strategies,
|
||||
),
|
||||
}, nil
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
@@ -429,14 +429,10 @@ func (module *module) Collect(ctx context.Context, orgID valuer.UUID) (map[strin
|
||||
stats["cloudintegration.aws.connectedaccounts.count"] = awsAccountsCount
|
||||
}
|
||||
|
||||
// get connected accounts for Azure
|
||||
azureAccountsCount, err := module.store.CountConnectedAccounts(ctx, orgID, cloudintegrationtypes.CloudProviderTypeAzure)
|
||||
if err == nil {
|
||||
stats["cloudintegration.azure.connectedaccounts.count"] = azureAccountsCount
|
||||
}
|
||||
|
||||
// NOTE: not adding stats for services for now.
|
||||
|
||||
// TODO: add more cloud providers when supported
|
||||
|
||||
return stats, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -795,8 +795,7 @@ export interface CloudintegrationtypesAccountDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAccountConfigDTO {
|
||||
aws?: CloudintegrationtypesAWSAccountConfigDTO;
|
||||
azure?: CloudintegrationtypesAzureAccountConfigDTO;
|
||||
aws: CloudintegrationtypesAWSAccountConfigDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -830,86 +829,6 @@ export interface CloudintegrationtypesAssetsDTO {
|
||||
dashboards?: CloudintegrationtypesDashboardDTO[] | null;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureAccountConfigDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
deploymentRegion: string;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
resourceGroups: string[];
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureConnectionArtifactDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
cliCommand: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
cloudPowerShellCommand: string;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureIntegrationConfigDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
deploymentRegion: string;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
resourceGroups: string[];
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
telemetryCollectionStrategy: CloudintegrationtypesAzureTelemetryCollectionStrategyDTO[];
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureLogsCollectionStrategyDTO {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
categoryGroups: string[];
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureMetricsCollectionStrategyDTO {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureServiceConfigDTO {
|
||||
logs: CloudintegrationtypesAzureServiceLogsConfigDTO;
|
||||
metrics: CloudintegrationtypesAzureServiceMetricsConfigDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureServiceLogsConfigDTO {
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureServiceMetricsConfigDTO {
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesAzureTelemetryCollectionStrategyDTO {
|
||||
logs?: CloudintegrationtypesAzureLogsCollectionStrategyDTO;
|
||||
metrics?: CloudintegrationtypesAzureMetricsCollectionStrategyDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
resourceProvider: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
resourceType: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @nullable
|
||||
*/
|
||||
@@ -971,8 +890,7 @@ export interface CloudintegrationtypesCollectedMetricDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesConnectionArtifactDTO {
|
||||
aws?: CloudintegrationtypesAWSConnectionArtifactDTO;
|
||||
azure?: CloudintegrationtypesAzureConnectionArtifactDTO;
|
||||
aws: CloudintegrationtypesAWSConnectionArtifactDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesCredentialsDTO {
|
||||
@@ -1156,8 +1074,7 @@ export interface CloudintegrationtypesPostableAccountDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesPostableAccountConfigDTO {
|
||||
aws?: CloudintegrationtypesAWSPostableAccountConfigDTO;
|
||||
azure?: CloudintegrationtypesAzureAccountConfigDTO;
|
||||
aws: CloudintegrationtypesAWSPostableAccountConfigDTO;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1192,8 +1109,7 @@ export interface CloudintegrationtypesPostableAgentCheckInDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesProviderIntegrationConfigDTO {
|
||||
aws?: CloudintegrationtypesAWSIntegrationConfigDTO;
|
||||
azure?: CloudintegrationtypesAzureIntegrationConfigDTO;
|
||||
aws: CloudintegrationtypesAWSIntegrationConfigDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesServiceDTO {
|
||||
@@ -1221,8 +1137,7 @@ export interface CloudintegrationtypesServiceDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesServiceConfigDTO {
|
||||
aws?: CloudintegrationtypesAWSServiceConfigDTO;
|
||||
azure?: CloudintegrationtypesAzureServiceConfigDTO;
|
||||
aws: CloudintegrationtypesAWSServiceConfigDTO;
|
||||
}
|
||||
|
||||
export enum CloudintegrationtypesServiceIDDTO {
|
||||
@@ -1239,8 +1154,6 @@ export enum CloudintegrationtypesServiceIDDTO {
|
||||
s3sync = 's3sync',
|
||||
sns = 'sns',
|
||||
sqs = 'sqs',
|
||||
storageaccountsblob = 'storageaccountsblob',
|
||||
cdnprofile = 'cdnprofile',
|
||||
}
|
||||
export interface CloudintegrationtypesServiceMetadataDTO {
|
||||
/**
|
||||
@@ -1273,24 +1186,11 @@ export interface CloudintegrationtypesSupportedSignalsDTO {
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesTelemetryCollectionStrategyDTO {
|
||||
aws?: CloudintegrationtypesAWSTelemetryCollectionStrategyDTO;
|
||||
azure?: CloudintegrationtypesAzureTelemetryCollectionStrategyDTO;
|
||||
aws: CloudintegrationtypesAWSTelemetryCollectionStrategyDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesUpdatableAccountDTO {
|
||||
config: CloudintegrationtypesUpdatableAccountConfigDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesUpdatableAccountConfigDTO {
|
||||
aws?: CloudintegrationtypesAWSAccountConfigDTO;
|
||||
azure?: CloudintegrationtypesUpdatableAzureAccountConfigDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesUpdatableAzureAccountConfigDTO {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
resourceGroups: string[];
|
||||
config: CloudintegrationtypesAccountConfigDTO;
|
||||
}
|
||||
|
||||
export interface CloudintegrationtypesUpdatableServiceDTO {
|
||||
|
||||
@@ -164,8 +164,7 @@ export function useIntegrationModal({
|
||||
{
|
||||
onSuccess: (response: CreateAccountMutationResult) => {
|
||||
const accountId = response.data.id;
|
||||
const connectionUrl =
|
||||
response.data.connectionArtifact.aws?.connectionUrl ?? '';
|
||||
const connectionUrl = response.data.connectionArtifact.aws.connectionUrl;
|
||||
|
||||
logEvent(
|
||||
'AWS Integration: Account connection attempt redirected to AWS',
|
||||
|
||||
@@ -0,0 +1,577 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { QueryClient, QueryClientProvider } from 'react-query';
|
||||
import { Router } from 'react-router-dom';
|
||||
import { act, renderHook, waitFor } from '@testing-library/react';
|
||||
import { FeatureKeys } from 'constants/features';
|
||||
import ROUTES from 'constants/routes';
|
||||
import { createMemoryHistory, MemoryHistory } from 'history';
|
||||
import { encode } from 'js-base64';
|
||||
import { AppContext } from 'providers/App/App';
|
||||
import { IAppContext } from 'providers/App/types';
|
||||
import { getAppContextMock } from 'tests/test-utils';
|
||||
|
||||
import ResourceProvider from '../ResourceProvider';
|
||||
import useResourceAttribute from '../useResourceAttribute';
|
||||
|
||||
const mockSafeNavigate = jest.fn();
|
||||
|
||||
jest.mock('hooks/useSafeNavigate', () => ({
|
||||
useSafeNavigate: (): { safeNavigate: jest.Mock } => ({
|
||||
safeNavigate: mockSafeNavigate,
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock('lib/history', () => ({
|
||||
__esModule: true,
|
||||
default: {
|
||||
push: jest.fn(),
|
||||
location: {
|
||||
search: '',
|
||||
pathname: '/',
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('api/metrics/getResourceAttributes', () => ({
|
||||
getResourceAttributesTagKeys: jest.fn(),
|
||||
getResourceAttributesTagValues: jest.fn(),
|
||||
}));
|
||||
|
||||
// eslint-disable-next-line import/first, import/order
|
||||
import {
|
||||
getResourceAttributesTagKeys,
|
||||
getResourceAttributesTagValues,
|
||||
// eslint-disable-next-line import/newline-after-import
|
||||
} from 'api/metrics/getResourceAttributes';
|
||||
// eslint-disable-next-line import/first, import/order
|
||||
import history from 'lib/history';
|
||||
|
||||
const mockTagKeys = getResourceAttributesTagKeys as jest.MockedFunction<
|
||||
typeof getResourceAttributesTagKeys
|
||||
>;
|
||||
const mockTagValues = getResourceAttributesTagValues as jest.MockedFunction<
|
||||
typeof getResourceAttributesTagValues
|
||||
>;
|
||||
|
||||
function createWrapper({
|
||||
routerHistory,
|
||||
appContextOverrides,
|
||||
}: {
|
||||
routerHistory: MemoryHistory;
|
||||
appContextOverrides?: Partial<IAppContext>;
|
||||
}): ({ children }: { children: ReactNode }) => JSX.Element {
|
||||
const queryClient = new QueryClient({
|
||||
defaultOptions: { queries: { retry: false } },
|
||||
});
|
||||
return function Wrapper({ children }: { children: ReactNode }): JSX.Element {
|
||||
return (
|
||||
<QueryClientProvider client={queryClient}>
|
||||
<AppContext.Provider value={getAppContextMock('ADMIN', appContextOverrides)}>
|
||||
<Router history={routerHistory}>
|
||||
<ResourceProvider>{children}</ResourceProvider>
|
||||
</Router>
|
||||
</AppContext.Provider>
|
||||
</QueryClientProvider>
|
||||
);
|
||||
};
|
||||
}
|
||||
|
||||
function mockLibHistory(search = '', pathname = '/'): void {
|
||||
(history.location as { search: string; pathname: string }).search = search;
|
||||
(history.location as { search: string; pathname: string }).pathname = pathname;
|
||||
}
|
||||
|
||||
type TagKeysPayload = Parameters<typeof mockTagKeys.mockResolvedValue>[0];
|
||||
type TagValuesPayload = Parameters<typeof mockTagValues.mockResolvedValue>[0];
|
||||
|
||||
function successTagKeysPayload(keys: string[]): TagKeysPayload {
|
||||
return ({
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: 'ok',
|
||||
payload: {
|
||||
data: {
|
||||
attributeKeys: keys.map((key) => ({
|
||||
key,
|
||||
dataType: 'string',
|
||||
type: 'resource',
|
||||
isColumn: false,
|
||||
})),
|
||||
},
|
||||
},
|
||||
} as unknown) as TagKeysPayload;
|
||||
}
|
||||
|
||||
function successTagValuesPayload(values: string[]): TagValuesPayload {
|
||||
return ({
|
||||
statusCode: 200,
|
||||
error: null,
|
||||
message: 'ok',
|
||||
payload: {
|
||||
data: {
|
||||
stringAttributeValues: values,
|
||||
},
|
||||
},
|
||||
} as unknown) as TagValuesPayload;
|
||||
}
|
||||
|
||||
describe('ResourceProvider', () => {
|
||||
beforeEach(() => {
|
||||
mockSafeNavigate.mockReset();
|
||||
mockTagKeys.mockReset();
|
||||
mockTagValues.mockReset();
|
||||
mockLibHistory('', '/');
|
||||
});
|
||||
|
||||
describe('initial state', () => {
|
||||
it('starts loading with empty staging, selectedQuery, and queries', () => {
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
expect(result.current.loading).toBe(true);
|
||||
expect(result.current.queries).toStrictEqual([]);
|
||||
expect(result.current.staging).toStrictEqual([]);
|
||||
expect(result.current.selectedQuery).toStrictEqual([]);
|
||||
expect(result.current.optionsData).toStrictEqual({ mode: undefined, options: [] });
|
||||
});
|
||||
|
||||
it('hydrates queries from the resourceAttribute URL param on mount', () => {
|
||||
const seeded = [
|
||||
{
|
||||
id: 'abc',
|
||||
tagKey: 'resource_service_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['frontend'],
|
||||
},
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
expect(result.current.queries).toStrictEqual(seeded);
|
||||
});
|
||||
});
|
||||
|
||||
describe('state-machine transitions via handleFocus / handleChange', () => {
|
||||
it('Idle → TagKey fetches tag keys and populates options', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockTagKeys).toHaveBeenCalledTimes(1);
|
||||
expect(result.current.loading).toBe(false);
|
||||
expect(result.current.optionsData.options).toStrictEqual([
|
||||
{ label: 'service.name', value: 'resource_service_name' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('TagKey → Operator sets OperatorSchema on handleChange (no mode)', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
|
||||
act(() => {
|
||||
result.current.handleChange('resource_service_name');
|
||||
});
|
||||
|
||||
expect(result.current.staging).toStrictEqual(['resource_service_name']);
|
||||
expect(result.current.optionsData.options).toStrictEqual([
|
||||
{ label: 'IN', value: 'IN' },
|
||||
{ label: 'Not IN', value: 'Not IN' },
|
||||
]);
|
||||
});
|
||||
|
||||
it('Operator → TagValue fetches values using staging[0]', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
mockTagValues.mockResolvedValue(successTagValuesPayload(['frontend', 'backend']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
act(() => {
|
||||
result.current.handleChange('resource_service_name');
|
||||
});
|
||||
act(() => {
|
||||
result.current.handleChange('IN');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockTagValues).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ tagKey: 'resource_service_name' }),
|
||||
);
|
||||
expect(result.current.optionsData.mode).toBe('multiple');
|
||||
expect(result.current.optionsData.options).toStrictEqual([
|
||||
{ label: 'frontend', value: 'frontend' },
|
||||
{ label: 'backend', value: 'backend' },
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
it('handleChange with mode updates selectedQuery instead of staging', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
mockTagValues.mockResolvedValue(successTagValuesPayload(['frontend']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
act(() => {
|
||||
result.current.handleChange('resource_service_name');
|
||||
});
|
||||
act(() => {
|
||||
result.current.handleChange('IN');
|
||||
});
|
||||
await waitFor(() => expect(result.current.optionsData.mode).toBe('multiple'));
|
||||
|
||||
act(() => {
|
||||
// In multiple mode, handleChange treats value as iterable of selected values.
|
||||
result.current.handleChange(('frontend' as unknown) as string);
|
||||
});
|
||||
|
||||
expect(result.current.selectedQuery).toStrictEqual([
|
||||
'f',
|
||||
'r',
|
||||
'o',
|
||||
'n',
|
||||
't',
|
||||
'e',
|
||||
'n',
|
||||
'd',
|
||||
]);
|
||||
// Staging not advanced by mode-mode handleChange
|
||||
expect(result.current.staging).toStrictEqual(['resource_service_name', 'IN']);
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleBlur', () => {
|
||||
it('commits a query when TagValue staging is complete and selectedQuery non-empty', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
mockTagValues.mockResolvedValue(successTagValuesPayload(['frontend']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/svc'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
act(() => result.current.handleChange('resource_service_name'));
|
||||
act(() => result.current.handleChange('IN'));
|
||||
await waitFor(() => expect(result.current.optionsData.mode).toBe('multiple'));
|
||||
act(() => {
|
||||
// Build selectedQuery = ['frontend']
|
||||
result.current.handleChange((['frontend'] as unknown) as string);
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleBlur();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queries).toHaveLength(1);
|
||||
expect(result.current.queries[0]).toMatchObject({
|
||||
tagKey: 'resource_service_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['frontend'],
|
||||
});
|
||||
expect(result.current.staging).toStrictEqual([]);
|
||||
expect(result.current.selectedQuery).toStrictEqual([]);
|
||||
expect(mockSafeNavigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('resets state without committing when staging is incomplete', async () => {
|
||||
mockTagKeys.mockResolvedValue(successTagKeysPayload(['resource_service_name']));
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleFocus();
|
||||
});
|
||||
await waitFor(() => expect(result.current.loading).toBe(false));
|
||||
act(() => result.current.handleChange('resource_service_name'));
|
||||
|
||||
act(() => {
|
||||
result.current.handleBlur();
|
||||
});
|
||||
|
||||
expect(result.current.queries).toStrictEqual([]);
|
||||
expect(result.current.staging).toStrictEqual([]);
|
||||
expect(mockSafeNavigate).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleClose / handleClearAll', () => {
|
||||
it('handleClose removes the matching query and navigates', async () => {
|
||||
const seeded = [
|
||||
{ id: 'a', tagKey: 'resource_a', operator: 'IN', tagValue: ['x'] },
|
||||
{ id: 'b', tagKey: 'resource_b', operator: 'IN', tagValue: ['y'] },
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
expect(result.current.queries).toHaveLength(2);
|
||||
|
||||
act(() => {
|
||||
result.current.handleClose('a');
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queries).toStrictEqual([seeded[1]]);
|
||||
expect(mockSafeNavigate).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
it('handleClearAll wipes queries, staging, selectedQuery, options', async () => {
|
||||
const seeded = [
|
||||
{ id: 'a', tagKey: 'resource_a', operator: 'IN', tagValue: ['x'] },
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleClearAll();
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queries).toStrictEqual([]);
|
||||
expect(result.current.staging).toStrictEqual([]);
|
||||
expect(result.current.optionsData).toStrictEqual({
|
||||
mode: undefined,
|
||||
options: [],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('handleEnvironmentChange', () => {
|
||||
it('adds an environment query when envs are provided', async () => {
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleEnvironmentChange(['production']);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queries).toHaveLength(1);
|
||||
expect(result.current.queries[0]).toMatchObject({
|
||||
tagKey: 'resource_deployment_environment',
|
||||
operator: 'IN',
|
||||
tagValue: ['production'],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it('clears the environment query when an empty array is passed', async () => {
|
||||
const seeded = [
|
||||
{
|
||||
id: 'env',
|
||||
tagKey: 'resource_deployment_environment',
|
||||
operator: 'IN',
|
||||
tagValue: ['production'],
|
||||
},
|
||||
{
|
||||
id: 'svc',
|
||||
tagKey: 'resource_service_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['frontend'],
|
||||
},
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleEnvironmentChange([]);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const tagKeys = result.current.queries.map((q) => q.tagKey);
|
||||
expect(tagKeys).not.toContain('resource_deployment_environment');
|
||||
expect(tagKeys).toContain('resource_service_name');
|
||||
});
|
||||
});
|
||||
|
||||
it('replaces an existing environment query rather than appending', async () => {
|
||||
const seeded = [
|
||||
{
|
||||
id: 'env',
|
||||
tagKey: 'resource_deployment_environment',
|
||||
operator: 'IN',
|
||||
tagValue: ['production'],
|
||||
},
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleEnvironmentChange(['staging']);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
const envQueries = result.current.queries.filter(
|
||||
(q) => q.tagKey === 'resource_deployment_environment',
|
||||
);
|
||||
expect(envQueries).toHaveLength(1);
|
||||
expect(envQueries[0].tagValue).toStrictEqual(['staging']);
|
||||
});
|
||||
});
|
||||
|
||||
it('uses the dotted deployment env key when DOT_METRICS_ENABLED is active', async () => {
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({
|
||||
routerHistory,
|
||||
appContextOverrides: {
|
||||
featureFlags: [
|
||||
{
|
||||
name: FeatureKeys.DOT_METRICS_ENABLED,
|
||||
active: true,
|
||||
usage: 0,
|
||||
usage_limit: -1,
|
||||
route: '',
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleEnvironmentChange(['production']);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(result.current.queries[0].tagKey).toBe(
|
||||
'resource_deployment.environment',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('preserves unrelated query params when dispatching', async () => {
|
||||
const routerHistory = createMemoryHistory({
|
||||
initialEntries: ['/?tab=overview'],
|
||||
});
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
act(() => {
|
||||
result.current.handleEnvironmentChange(['production']);
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
expect(mockSafeNavigate).toHaveBeenCalled();
|
||||
const calledWith = mockSafeNavigate.mock.calls[0][0] as string;
|
||||
expect(calledWith).toContain('tab=overview');
|
||||
expect(calledWith).toContain('resourceAttribute=');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('getVisibleQueries (SERVICE_MAP filtering)', () => {
|
||||
it('filters queries down to whitelisted keys on SERVICE_MAP', () => {
|
||||
const seeded = [
|
||||
{
|
||||
id: 'a',
|
||||
tagKey: 'resource_service_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['frontend'],
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
tagKey: 'resource_k8s_cluster_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['prod'],
|
||||
},
|
||||
];
|
||||
mockLibHistory(
|
||||
`?resourceAttribute=${encode(JSON.stringify(seeded))}`,
|
||||
ROUTES.SERVICE_MAP,
|
||||
);
|
||||
|
||||
const routerHistory = createMemoryHistory({
|
||||
initialEntries: [ROUTES.SERVICE_MAP],
|
||||
});
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
expect(result.current.queries).toStrictEqual([seeded[1]]);
|
||||
});
|
||||
|
||||
it('returns all queries on non-SERVICE_MAP routes', () => {
|
||||
const seeded = [
|
||||
{
|
||||
id: 'a',
|
||||
tagKey: 'resource_service_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['frontend'],
|
||||
},
|
||||
{
|
||||
id: 'b',
|
||||
tagKey: 'resource_k8s_cluster_name',
|
||||
operator: 'IN',
|
||||
tagValue: ['prod'],
|
||||
},
|
||||
];
|
||||
mockLibHistory(`?resourceAttribute=${encode(JSON.stringify(seeded))}`, '/services');
|
||||
|
||||
const routerHistory = createMemoryHistory({ initialEntries: ['/services'] });
|
||||
const { result } = renderHook(() => useResourceAttribute(), {
|
||||
wrapper: createWrapper({ routerHistory }),
|
||||
});
|
||||
|
||||
expect(result.current.queries).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1 +0,0 @@
|
||||
<svg id="b300f0d1-2ad8-4418-a1c5-23d0b9d21841" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="b8cad6fd-ec7f-45e9-be2a-125e8b87bd03" x1="10.79" y1="2.17" x2="10.79" y2="16.56" gradientUnits="userSpaceOnUse"><stop offset="0.18" stop-color="#5ea0ef"/><stop offset="1" stop-color="#0078d4"/></linearGradient></defs><title>Icon-web-43</title><rect x="3.7" y="5.49" width="1.18" height="5.26" rx="0.52" transform="translate(-3.83 12.41) rotate(-90)" fill="#b3b3b3"/><rect x="2.04" y="7.88" width="1.18" height="5.26" rx="0.52" transform="translate(-7.88 13.14) rotate(-90)" fill="#a3a3a3"/><rect x="3.7" y="10.26" width="1.18" height="5.26" rx="0.52" transform="translate(-8.6 17.19) rotate(-90)" fill="#7a7a7a"/><path d="M18,11a3.28,3.28,0,0,0-2.81-3.18,4.13,4.13,0,0,0-4.21-4,4.23,4.23,0,0,0-4,2.8,3.89,3.89,0,0,0-3.38,3.8,4,4,0,0,0,4.06,3.86l.36,0h6.58l.17,0A3.32,3.32,0,0,0,18,11Z" fill="url(#b8cad6fd-ec7f-45e9-be2a-125e8b87bd03)"/></svg>
|
||||
|
Before Width: | Height: | Size: 971 B |
@@ -1,167 +0,0 @@
|
||||
{
|
||||
"id": "cdnprofile",
|
||||
"title": "CDN Profile",
|
||||
"icon": "file://icon.svg",
|
||||
"overview": "file://overview.md",
|
||||
"supportedSignals": {
|
||||
"metrics": true,
|
||||
"logs": true
|
||||
},
|
||||
"dataCollected": {
|
||||
"metrics": [
|
||||
{
|
||||
"name": "azure_activewebsocketconnections_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_averagewebsocketconnectionduration_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_backendhealthpercentage_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_backendrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_backendrequestlatency_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_billableresponsesize_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_bytehitratio_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originhealthpercentage_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originlatency_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originshieldoriginrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originshieldratelimitrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originshieldrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_originshieldrequestsize_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_percentage4xx_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_percentage5xx_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_requestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_requestsize_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_responsesize_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_totallatency_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_webapplicationfirewallrequestcount_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"name": "Resource ID",
|
||||
"path": "resources.azure.resource.id",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"telemetryCollectionStrategy": {
|
||||
"azure": {
|
||||
"resourceProvider": "Microsoft.Cdn",
|
||||
"resourceType": "profiles",
|
||||
"metrics": {},
|
||||
"logs": {
|
||||
"categoryGroups": ["allLogs"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"assets": {
|
||||
"dashboards": [
|
||||
{
|
||||
"id": "overview",
|
||||
"title": "CDN Profile Overview",
|
||||
"description": "Overview of CDN Profile metrics",
|
||||
"definition": "file://assets/dashboards/overview.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
### Monitor Azure CDN Profile with SigNoz
|
||||
|
||||
Collect key CDN Profile metrics and view them with an out of the box dashboard.
|
||||
@@ -1 +0,0 @@
|
||||
{}
|
||||
@@ -1 +0,0 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 18 18"><defs><linearGradient id="a9c62307-1cd0-400c-911b-17ec6a9110ce" x1="9" y1="15.834" x2="9" y2="5.788" gradientUnits="userSpaceOnUse"><stop offset="0" stop-color="#32bedd"/><stop offset="0.775" stop-color="#32d4f5"/></linearGradient></defs><title>MsPortalFx.base.images-7</title><g id="f31d214e-f09e-49e3-b3d2-7c5d55682d09"><g><path d="M.5,5.788h17a0,0,0,0,1,0,0v9.478a.568.568,0,0,1-.568.568H1.068A.568.568,0,0,1,.5,15.266V5.788A0,0,0,0,1,.5,5.788Z" fill="url(#a9c62307-1cd0-400c-911b-17ec6a9110ce)"/><path d="M1.071,2.166H16.929a.568.568,0,0,1,.568.568V5.788a0,0,0,0,1,0,0H.5a0,0,0,0,1,0,0V2.734A.568.568,0,0,1,1.071,2.166Z" fill="#0078d4"/><rect x="2.328" y="7.049" width="6.281" height="3.408" rx="0.283" fill="#0078d4"/><rect x="9.336" y="7.049" width="6.281" height="3.408" rx="0.283" fill="#fff"/><rect x="2.296" y="11.128" width="6.281" height="3.408" rx="0.283" fill="#0078d4"/><rect x="9.304" y="11.128" width="6.281" height="3.408" rx="0.283" fill="#0078d4"/></g></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.0 KiB |
@@ -1,107 +0,0 @@
|
||||
{
|
||||
"id": "storageaccountsblob",
|
||||
"title": "Storage Accounts Blob Storage",
|
||||
"icon": "file://icon.svg",
|
||||
"overview": "file://overview.md",
|
||||
"supportedSignals": {
|
||||
"metrics": true,
|
||||
"logs": true
|
||||
},
|
||||
"dataCollected": {
|
||||
"metrics": [
|
||||
{
|
||||
"name": "azure_availability_average",
|
||||
"unit": "Percent",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_blobcapacity_average",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_blobcount_average",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_blobprovisionedsize_average",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_containercount_average",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_egress_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_indexcapacity_average",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_ingress_total",
|
||||
"unit": "Bytes",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_successe2elatency_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_successserverlatency_average",
|
||||
"unit": "Milliseconds",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
},
|
||||
{
|
||||
"name": "azure_transactions_total",
|
||||
"unit": "Count",
|
||||
"type": "Gauge",
|
||||
"description": ""
|
||||
}
|
||||
],
|
||||
"logs": [
|
||||
{
|
||||
"name": "Resource ID",
|
||||
"path": "resources.azure.resource.id",
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
"telemetryCollectionStrategy": {
|
||||
"azure": {
|
||||
"resourceProvider": "Microsoft.Storage",
|
||||
"resourceType": "storageAccounts/blobServices",
|
||||
"metrics": {},
|
||||
"logs": {
|
||||
"categoryGroups": ["allLogs"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"assets": {
|
||||
"dashboards": [
|
||||
{
|
||||
"id": "overview",
|
||||
"title": "Blob Storage Overview",
|
||||
"description": "Overview of Blob Storage",
|
||||
"definition": "file://assets/dashboards/overview.json"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
### Monitor Storage Accounts Blob Storage with SigNoz
|
||||
|
||||
Collect key Blob Storage metrics and view them with an out of the box dashboard.
|
||||
@@ -373,13 +373,7 @@ func (handler *handler) UpdateService(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
// update or create service
|
||||
if svc.CloudIntegrationService == nil {
|
||||
var cloudIntegrationService *cloudintegrationtypes.CloudIntegrationService
|
||||
cloudIntegrationService, err = cloudintegrationtypes.NewCloudIntegrationService(serviceID, cloudIntegrationID, provider, req.Config)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
cloudIntegrationService := cloudintegrationtypes.NewCloudIntegrationService(serviceID, cloudIntegrationID, req.Config)
|
||||
err = handler.module.CreateService(ctx, orgID, cloudIntegrationService, provider)
|
||||
} else {
|
||||
err = svc.CloudIntegrationService.Update(provider, serviceID, req.Config)
|
||||
@@ -440,4 +434,3 @@ func (handler *handler) AgentCheckIn(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableAgentCheckIn(provider, resp))
|
||||
}
|
||||
|
||||
|
||||
@@ -29,13 +29,8 @@ type AgentReport struct {
|
||||
}
|
||||
|
||||
type AccountConfig struct {
|
||||
AWS *AWSAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzureAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
}
|
||||
|
||||
type UpdatableAccountConfig struct {
|
||||
AWS *UpdatableAWSAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *UpdatableAzureAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
// required till new providers are added
|
||||
AWS *AWSAccountConfig `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type PostableAccount struct {
|
||||
@@ -46,8 +41,7 @@ type PostableAccount struct {
|
||||
type PostableAccountConfig struct {
|
||||
// as agent version is common for all providers, we can keep it at top level of this struct
|
||||
AgentVersion string
|
||||
AWS *AWSPostableAccountConfig `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzurePostableAccountConfig `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
AWS *AWSPostableAccountConfig `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type Credentials struct {
|
||||
@@ -64,8 +58,7 @@ type GettableAccountWithConnectionArtifact struct {
|
||||
|
||||
type ConnectionArtifact struct {
|
||||
// required till new providers are added
|
||||
AWS *AWSConnectionArtifact `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzureConnectionArtifact `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
AWS *AWSConnectionArtifact `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type GetConnectionArtifactRequest = PostableAccount
|
||||
@@ -75,7 +68,7 @@ type GettableAccounts struct {
|
||||
}
|
||||
|
||||
type UpdatableAccount struct {
|
||||
Config *UpdatableAccountConfig `json:"config" required:"true" nullable:"false"`
|
||||
Config *AccountConfig `json:"config" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
func NewAccount(orgID valuer.UUID, provider CloudProviderType, config *AccountConfig) *Account {
|
||||
@@ -126,13 +119,6 @@ func NewAccountFromStorable(storableAccount *StorableCloudIntegration) (*Account
|
||||
return nil, err
|
||||
}
|
||||
account.Config.AWS = awsConfig
|
||||
case CloudProviderTypeAzure:
|
||||
azureConfig := new(AzureAccountConfig)
|
||||
err := json.Unmarshal([]byte(storableAccount.Config), azureConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
account.Config.Azure = azureConfig
|
||||
}
|
||||
|
||||
if storableAccount.LastAgentReport != nil {
|
||||
@@ -193,24 +179,6 @@ func NewAccountConfigFromPostable(provider CloudProviderType, config *PostableAc
|
||||
}
|
||||
|
||||
return &AccountConfig{AWS: &AWSAccountConfig{Regions: config.AWS.Regions}}, nil
|
||||
case CloudProviderTypeAzure:
|
||||
if config.Azure == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config can not be nil for Azure provider")
|
||||
}
|
||||
|
||||
if config.Azure.DeploymentRegion == "" {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "deployment region is required for Azure provider")
|
||||
}
|
||||
|
||||
if err := validateAzureRegion(config.Azure.DeploymentRegion); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(config.Azure.ResourceGroups) == 0 {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "at least one resource group is required for Azure provider")
|
||||
}
|
||||
|
||||
return &AccountConfig{Azure: &AzureAccountConfig{DeploymentRegion: config.Azure.DeploymentRegion, ResourceGroups: config.Azure.ResourceGroups}}, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
}
|
||||
@@ -234,16 +202,6 @@ func NewAccountConfigFromUpdatable(provider CloudProviderType, config *Updatable
|
||||
}
|
||||
|
||||
return &AccountConfig{AWS: &AWSAccountConfig{Regions: config.Config.AWS.Regions}}, nil
|
||||
case CloudProviderTypeAzure:
|
||||
if config.Config.Azure == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config can not be nil for Azure provider")
|
||||
}
|
||||
|
||||
if len(config.Config.Azure.ResourceGroups) == 0 {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "at least one resource group is required for Azure provider")
|
||||
}
|
||||
|
||||
return &AccountConfig{Azure: &AzureAccountConfig{ResourceGroups: config.Config.Azure.ResourceGroups}}, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
}
|
||||
@@ -265,14 +223,8 @@ func GetSigNozAPIURLFromDeployment(deployment *zeustypes.GettableDeployment) (st
|
||||
}
|
||||
|
||||
func (account *Account) Update(provider CloudProviderType, config *AccountConfig) error {
|
||||
// deployment region can not be updated once set for Azure
|
||||
if provider == CloudProviderTypeAzure {
|
||||
config.Azure.DeploymentRegion = account.Config.Azure.DeploymentRegion
|
||||
}
|
||||
|
||||
account.Config = config
|
||||
account.UpdatedAt = time.Now()
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -336,10 +288,6 @@ func (config *AccountConfig) ToJSON() ([]byte, error) {
|
||||
return json.Marshal(config.AWS)
|
||||
}
|
||||
|
||||
if config.Azure != nil {
|
||||
return json.Marshal(config.Azure)
|
||||
}
|
||||
|
||||
return nil, errors.NewInternalf(errors.CodeInternal, "no provider account config found")
|
||||
}
|
||||
|
||||
|
||||
@@ -48,8 +48,7 @@ type IntegrationConfig struct {
|
||||
}
|
||||
|
||||
type ProviderIntegrationConfig struct {
|
||||
AWS *AWSIntegrationConfig `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzureIntegrationConfig `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
AWS *AWSIntegrationConfig `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
// NewGettableAgentCheckIn constructs a backward-compatible response from an AgentCheckInResponse.
|
||||
|
||||
@@ -61,8 +61,7 @@ type StorableCloudIntegrationService struct {
|
||||
// Following Service config types are only internally used to store service config in DB and use JSON snake case keys for backward compatibility.
|
||||
|
||||
type StorableServiceConfig struct {
|
||||
AWS *StorableAWSServiceConfig
|
||||
Azure *StorableAzureServiceConfig
|
||||
AWS *StorableAWSServiceConfig
|
||||
}
|
||||
|
||||
type StorableAWSServiceConfig struct {
|
||||
@@ -79,19 +78,6 @@ type StorableAWSMetricsServiceConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type StorableAzureServiceConfig struct {
|
||||
Logs *StorableAzureLogsServiceConfig `json:"logs,omitempty"`
|
||||
Metrics *StorableAzureMetricsServiceConfig `json:"metrics,omitempty"`
|
||||
}
|
||||
|
||||
type StorableAzureLogsServiceConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type StorableAzureMetricsServiceConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
// Scan scans value from DB.
|
||||
func (r *StorableAgentReport) Scan(src any) error {
|
||||
var data []byte
|
||||
@@ -201,30 +187,6 @@ func newStorableServiceConfig(provider CloudProviderType, serviceID ServiceID, s
|
||||
}
|
||||
|
||||
return &StorableServiceConfig{AWS: storableAWSServiceConfig}, nil
|
||||
case CloudProviderTypeAzure:
|
||||
storableAzureServiceConfig := new(StorableAzureServiceConfig)
|
||||
|
||||
if supportedSignals.Logs {
|
||||
if serviceConfig.Azure.Logs == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudIntegrationInvalidConfig, "logs config is required for Azure service: %s", serviceID.StringValue())
|
||||
}
|
||||
|
||||
storableAzureServiceConfig.Logs = &StorableAzureLogsServiceConfig{
|
||||
Enabled: serviceConfig.Azure.Logs.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
if supportedSignals.Metrics {
|
||||
if serviceConfig.Azure.Metrics == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudIntegrationInvalidConfig, "metrics config is required for Azure service: %s", serviceID.StringValue())
|
||||
}
|
||||
|
||||
storableAzureServiceConfig.Metrics = &StorableAzureMetricsServiceConfig{
|
||||
Enabled: serviceConfig.Azure.Metrics.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
return &StorableServiceConfig{Azure: storableAzureServiceConfig}, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
}
|
||||
@@ -239,13 +201,6 @@ func newStorableServiceConfigFromJSON(provider CloudProviderType, jsonStr string
|
||||
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't parse AWS service config JSON")
|
||||
}
|
||||
return &StorableServiceConfig{AWS: awsConfig}, nil
|
||||
case CloudProviderTypeAzure:
|
||||
azureConfig := new(StorableAzureServiceConfig)
|
||||
err := json.Unmarshal([]byte(jsonStr), azureConfig)
|
||||
if err != nil {
|
||||
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't parse Azure service config JSON")
|
||||
}
|
||||
return &StorableServiceConfig{Azure: azureConfig}, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
}
|
||||
@@ -259,13 +214,6 @@ func (config *StorableServiceConfig) toJSON(provider CloudProviderType) ([]byte,
|
||||
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize AWS service config to JSON")
|
||||
}
|
||||
|
||||
return jsonBytes, nil
|
||||
case CloudProviderTypeAzure:
|
||||
jsonBytes, err := json.Marshal(config.Azure)
|
||||
if err != nil {
|
||||
return nil, errors.WrapInternalf(err, errors.CodeInternal, "couldn't serialize Azure service config to JSON")
|
||||
}
|
||||
|
||||
return jsonBytes, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
|
||||
@@ -23,8 +23,6 @@ type AWSAccountConfig struct {
|
||||
Regions []string `json:"regions" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type UpdatableAWSAccountConfig = AWSAccountConfig
|
||||
|
||||
// OldAWSCollectionStrategy is the backward-compatible snake_case form of AWSCollectionStrategy,
|
||||
// used in the legacy integration_config response field for older agents.
|
||||
type OldAWSCollectionStrategy struct {
|
||||
|
||||
@@ -1,148 +0,0 @@
|
||||
package cloudintegrationtypes
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
var (
|
||||
AgentArmTemplateS3Path = valuer.NewString("https://signoz-integrations.s3.us-east-1.amazonaws.com/azure-arm-template-%s.json")
|
||||
AgentDeploymentStackName = valuer.NewString("signoz-integration")
|
||||
)
|
||||
|
||||
type AzureAccountConfig struct {
|
||||
DeploymentRegion string `json:"deploymentRegion" required:"true"`
|
||||
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type UpdatableAzureAccountConfig struct {
|
||||
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type AzurePostableAccountConfig = AzureAccountConfig
|
||||
|
||||
type AzureConnectionArtifact struct {
|
||||
CLICommand string `json:"cliCommand" required:"true"`
|
||||
CloudPowerShellCommand string `json:"cloudPowerShellCommand" required:"true"`
|
||||
}
|
||||
|
||||
type AzureServiceConfig struct {
|
||||
Logs *AzureServiceLogsConfig `json:"logs" required:"true"`
|
||||
Metrics *AzureServiceMetricsConfig `json:"metrics" required:"true"`
|
||||
}
|
||||
|
||||
type AzureServiceLogsConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type AzureServiceMetricsConfig struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
}
|
||||
|
||||
type AzureTelemetryCollectionStrategy struct {
|
||||
//https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/resource-providers-and-types
|
||||
ResourceProvider string `json:"resourceProvider" required:"true"`
|
||||
ResourceType string `json:"resourceType" required:"true"`
|
||||
Metrics *AzureMetricsCollectionStrategy `json:"metrics,omitempty" required:"false" nullable:"false"`
|
||||
Logs *AzureLogsCollectionStrategy `json:"logs,omitempty" required:"false" nullable:"false"`
|
||||
}
|
||||
|
||||
// AzureMetricsCollectionStrategy no additional config required for metrics, will be added in future as required.
|
||||
type AzureMetricsCollectionStrategy struct{}
|
||||
|
||||
type AzureLogsCollectionStrategy struct {
|
||||
// List of categories to enable for diagnostic settings, to start with it will have 'allLogs' and no filtering.
|
||||
CategoryGroups []string `json:"categoryGroups" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type AzureIntegrationConfig struct {
|
||||
DeploymentRegion string `json:"deploymentRegion" required:"true"`
|
||||
ResourceGroups []string `json:"resourceGroups" required:"true" nullable:"false"`
|
||||
TelemetryCollectionStrategy []*AzureTelemetryCollectionStrategy `json:"telemetryCollectionStrategy" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
func NewAzureIntegrationConfig(
|
||||
deploymentRegion string,
|
||||
resourceGroups []string,
|
||||
strategies []*AzureTelemetryCollectionStrategy,
|
||||
) *AzureIntegrationConfig {
|
||||
return &AzureIntegrationConfig{
|
||||
DeploymentRegion: deploymentRegion,
|
||||
ResourceGroups: resourceGroups,
|
||||
TelemetryCollectionStrategy: strategies,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAzureConnectionArtifact(cliCommand, cloudPowerShellCommand string) *AzureConnectionArtifact {
|
||||
return &AzureConnectionArtifact{
|
||||
CLICommand: cliCommand,
|
||||
CloudPowerShellCommand: cloudPowerShellCommand,
|
||||
}
|
||||
}
|
||||
|
||||
func NewAzureConnectionCLICommand(
|
||||
accountID valuer.UUID,
|
||||
agentVersion string,
|
||||
creds *Credentials,
|
||||
cfg *AzurePostableAccountConfig,
|
||||
) string {
|
||||
templateURL := fmt.Sprintf(AgentArmTemplateS3Path.StringValue(), agentVersion)
|
||||
lines := []string{
|
||||
"az stack sub create",
|
||||
fmt.Sprintf(" --name %s", AgentDeploymentStackName.StringValue()),
|
||||
fmt.Sprintf(" --location %s", cfg.DeploymentRegion),
|
||||
fmt.Sprintf(" --template-uri %s", templateURL),
|
||||
" --parameters",
|
||||
fmt.Sprintf(" location='%s'", cfg.DeploymentRegion),
|
||||
fmt.Sprintf(" signozApiKey='%s'", creds.SigNozAPIKey),
|
||||
fmt.Sprintf(" signozApiUrl='%s'", creds.SigNozAPIURL),
|
||||
fmt.Sprintf(" signozIngestionUrl='%s'", creds.IngestionURL),
|
||||
fmt.Sprintf(" signozIngestionKey='%s'", creds.IngestionKey),
|
||||
fmt.Sprintf(" signozIntegrationAccountId='%s'", accountID.StringValue()),
|
||||
fmt.Sprintf(" signozIntegrationAgentVersion='%s'", agentVersion),
|
||||
" --action-on-unmanage deleteAll",
|
||||
" --deny-settings-mode denyDelete",
|
||||
}
|
||||
return strings.Join(lines, " \\\n")
|
||||
}
|
||||
|
||||
func NewAzureConnectionPowerShellCommand(
|
||||
accountID valuer.UUID,
|
||||
agentVersion string,
|
||||
creds *Credentials,
|
||||
cfg *AzurePostableAccountConfig,
|
||||
) string {
|
||||
params := []struct{ k, v string }{
|
||||
{"location", cfg.DeploymentRegion},
|
||||
{"signozApiKey", creds.SigNozAPIKey},
|
||||
{"signozApiUrl", creds.SigNozAPIURL},
|
||||
{"signozIngestionUrl", creds.IngestionURL},
|
||||
{"signozIngestionKey", creds.IngestionKey},
|
||||
{"signozIntegrationAccountId", accountID.StringValue()},
|
||||
{"signozIntegrationAgentVersion", agentVersion},
|
||||
{"rgName", "signoz-integration-rg"},
|
||||
{"containerEnvName", "signoz-integration-agent-env"},
|
||||
{"deploymentEnv", "production"},
|
||||
}
|
||||
|
||||
const keyWidth = 36
|
||||
var paramLines []string
|
||||
for _, p := range params {
|
||||
paramLines = append(paramLines, fmt.Sprintf(" %-*s= \"%s\"", keyWidth, p.k, p.v))
|
||||
}
|
||||
|
||||
templateURL := fmt.Sprintf(AgentArmTemplateS3Path.StringValue(), agentVersion)
|
||||
return strings.Join([]string{
|
||||
"New-AzSubscriptionDeploymentStack `",
|
||||
fmt.Sprintf(" -Name \"%s\" `", AgentDeploymentStackName.StringValue()),
|
||||
fmt.Sprintf(" -Location \"%s\" `", cfg.DeploymentRegion),
|
||||
fmt.Sprintf(" -TemplateUri \"%s\" `", templateURL),
|
||||
" -TemplateParameterObject @{",
|
||||
strings.Join(paramLines, "\n"),
|
||||
" } `",
|
||||
" -ActionOnUnmanage \"deleteAll\" `",
|
||||
" -DenySettingsMode \"denyDelete\"",
|
||||
}, "\n")
|
||||
}
|
||||
@@ -165,13 +165,3 @@ func validateAWSRegion(region string) error {
|
||||
|
||||
return errors.NewInvalidInputf(ErrCodeInvalidCloudRegion, "invalid AWS region: %s", region)
|
||||
}
|
||||
|
||||
func validateAzureRegion(region string) error {
|
||||
for _, r := range SupportedRegions[CloudProviderTypeAzure] {
|
||||
if r.StringValue() == region {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
return errors.NewInvalidInputf(ErrCodeInvalidCloudRegion, "invalid Azure region: %s", region)
|
||||
}
|
||||
|
||||
@@ -21,8 +21,8 @@ type CloudIntegrationService struct {
|
||||
}
|
||||
|
||||
type ServiceConfig struct {
|
||||
AWS *AWSServiceConfig `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzureServiceConfig `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
// required till new providers are added
|
||||
AWS *AWSServiceConfig `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
// ServiceMetadata helps to quickly list available services and whether it is enabled or not.
|
||||
@@ -88,8 +88,7 @@ type DataCollected struct {
|
||||
// TelemetryCollectionStrategy is cloud provider specific configuration for signal collection,
|
||||
// this is used by agent to understand the nitty-gritty for collecting telemetry for the cloud provider.
|
||||
type TelemetryCollectionStrategy struct {
|
||||
AWS *AWSTelemetryCollectionStrategy `json:"aws,omitempty" required:"false" nullable:"false"`
|
||||
Azure *AzureTelemetryCollectionStrategy `json:"azure,omitempty" required:"false" nullable:"false"`
|
||||
AWS *AWSTelemetryCollectionStrategy `json:"aws" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
// Assets represents the collection of dashboards.
|
||||
@@ -123,18 +122,7 @@ type Dashboard struct {
|
||||
Definition dashboardtypes.StorableDashboardData `json:"definition,omitempty"`
|
||||
}
|
||||
|
||||
func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.UUID, provider CloudProviderType, config *ServiceConfig) (*CloudIntegrationService, error) {
|
||||
switch provider {
|
||||
case CloudProviderTypeAWS:
|
||||
if config.AWS == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "AWS config is required for AWS service")
|
||||
}
|
||||
case CloudProviderTypeAzure:
|
||||
if config.Azure == nil {
|
||||
return nil, errors.NewInvalidInputf(ErrCodeInvalidInput, "Azure config is required for Azure service")
|
||||
}
|
||||
}
|
||||
|
||||
func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.UUID, config *ServiceConfig) *CloudIntegrationService {
|
||||
return &CloudIntegrationService{
|
||||
Identifiable: types.Identifiable{
|
||||
ID: valuer.GenerateUUID(),
|
||||
@@ -146,7 +134,7 @@ func NewCloudIntegrationService(serviceID ServiceID, cloudIntegrationID valuer.U
|
||||
Type: serviceID,
|
||||
Config: config,
|
||||
CloudIntegrationID: cloudIntegrationID,
|
||||
}, nil
|
||||
}
|
||||
}
|
||||
|
||||
func NewCloudIntegrationServiceFromStorable(stored *StorableCloudIntegrationService, config *ServiceConfig) *CloudIntegrationService {
|
||||
@@ -203,22 +191,6 @@ func NewServiceConfigFromJSON(provider CloudProviderType, jsonString string) (*S
|
||||
}
|
||||
|
||||
return &ServiceConfig{AWS: awsServiceConfig}, nil
|
||||
case CloudProviderTypeAzure:
|
||||
azureServiceConfig := new(AzureServiceConfig)
|
||||
|
||||
if storableServiceConfig.Azure.Logs != nil {
|
||||
azureServiceConfig.Logs = &AzureServiceLogsConfig{
|
||||
Enabled: storableServiceConfig.Azure.Logs.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
if storableServiceConfig.Azure.Metrics != nil {
|
||||
azureServiceConfig.Metrics = &AzureServiceMetricsConfig{
|
||||
Enabled: storableServiceConfig.Azure.Metrics.Enabled,
|
||||
}
|
||||
}
|
||||
|
||||
return &ServiceConfig{Azure: azureServiceConfig}, nil
|
||||
default:
|
||||
return nil, errors.NewInvalidInputf(ErrCodeCloudProviderInvalidInput, "invalid cloud provider: %s", provider.StringValue())
|
||||
}
|
||||
@@ -256,10 +228,6 @@ func (config *ServiceConfig) IsServiceEnabled(provider CloudProviderType) bool {
|
||||
logsEnabled := config.AWS.Logs != nil && config.AWS.Logs.Enabled
|
||||
metricsEnabled := config.AWS.Metrics != nil && config.AWS.Metrics.Enabled
|
||||
return logsEnabled || metricsEnabled
|
||||
case CloudProviderTypeAzure:
|
||||
logsEnabled := config.Azure.Logs != nil && config.Azure.Logs.Enabled
|
||||
metricsEnabled := config.Azure.Metrics != nil && config.Azure.Metrics.Enabled
|
||||
return logsEnabled || metricsEnabled
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -271,8 +239,6 @@ func (config *ServiceConfig) IsMetricsEnabled(provider CloudProviderType) bool {
|
||||
switch provider {
|
||||
case CloudProviderTypeAWS:
|
||||
return config.AWS.Metrics != nil && config.AWS.Metrics.Enabled
|
||||
case CloudProviderTypeAzure:
|
||||
return config.Azure.Metrics != nil && config.Azure.Metrics.Enabled
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -283,8 +249,6 @@ func (config *ServiceConfig) IsLogsEnabled(provider CloudProviderType) bool {
|
||||
switch provider {
|
||||
case CloudProviderTypeAWS:
|
||||
return config.AWS.Logs != nil && config.AWS.Logs.Enabled
|
||||
case CloudProviderTypeAzure:
|
||||
return config.Azure.Logs != nil && config.Azure.Logs.Enabled
|
||||
default:
|
||||
return false
|
||||
}
|
||||
@@ -367,3 +331,4 @@ func GetDashboardsFromAssets(
|
||||
|
||||
return dashboards
|
||||
}
|
||||
|
||||
|
||||
@@ -23,10 +23,6 @@ var (
|
||||
AWSServiceS3Sync = ServiceID{valuer.NewString("s3sync")}
|
||||
AWSServiceSNS = ServiceID{valuer.NewString("sns")}
|
||||
AWSServiceSQS = ServiceID{valuer.NewString("sqs")}
|
||||
|
||||
// Azure services.
|
||||
AzureServiceStorageAccountsBlob = ServiceID{valuer.NewString("storageaccountsblob")}
|
||||
AzureServiceCDNProfile = ServiceID{valuer.NewString("cdnprofile")}
|
||||
)
|
||||
|
||||
func (ServiceID) Enum() []any {
|
||||
@@ -44,8 +40,6 @@ func (ServiceID) Enum() []any {
|
||||
AWSServiceS3Sync,
|
||||
AWSServiceSNS,
|
||||
AWSServiceSQS,
|
||||
AzureServiceStorageAccountsBlob,
|
||||
AzureServiceCDNProfile,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,10 +60,6 @@ var SupportedServices = map[CloudProviderType][]ServiceID{
|
||||
AWSServiceSNS,
|
||||
AWSServiceSQS,
|
||||
},
|
||||
CloudProviderTypeAzure: {
|
||||
AzureServiceStorageAccountsBlob,
|
||||
AzureServiceCDNProfile,
|
||||
},
|
||||
}
|
||||
|
||||
func NewServiceID(provider CloudProviderType, service string) (ServiceID, error) {
|
||||
|
||||
Reference in New Issue
Block a user