diff --git a/frontend/src/assets/Logos/gcp.svg b/frontend/src/assets/Logos/gcp.svg
new file mode 100644
index 0000000000..2e0200e474
--- /dev/null
+++ b/frontend/src/assets/Logos/gcp.svg
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/AccountActions/AccountActions.tsx b/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/AccountActions/AccountActions.tsx
index 55920fc262..efc60ae47b 100644
--- a/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/AccountActions/AccountActions.tsx
+++ b/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/AccountActions/AccountActions.tsx
@@ -20,6 +20,7 @@ import AzureAccountSettingsModal from '../../AzureCloudServices/EditAccount/Acco
import {
mapAccountDtoToAwsCloudAccount,
mapAccountDtoToAzureCloudAccount,
+ mapAccountDtoToGcpCloudAccount,
} from '../../mapCloudAccountFromDto';
import AwsCloudAccountSetupModal from '../AddNewAccount/CloudAccountSetupModal';
import AwsAccountSettingsModal from '../EditAccount/AccountSettingsModal';
@@ -156,6 +157,18 @@ function AccountActions({ type }: { type: IntegrationType }): JSX.Element {
});
}
+ if (type === IntegrationType.GCP_SERVICES) {
+ raw.forEach((account) => {
+ if (!account) {
+ return;
+ }
+ const mapped = mapAccountDtoToGcpCloudAccount(account);
+ if (mapped) {
+ mappedAccounts.push(mapped);
+ }
+ });
+ }
+
return mappedAccounts;
}, [listAccountsResponse, type]);
@@ -207,13 +220,23 @@ function AccountActions({ type }: { type: IntegrationType }): JSX.Element {
// log telemetry event when an account is viewed.
useEffect(() => {
if (activeAccount) {
+ const { config } = activeAccount;
+ let enabledRegions: string[];
+ if ('regions' in config) {
+ // AWS
+ enabledRegions = config.regions;
+ } else if ('resource_groups' in config) {
+ // Azure
+ enabledRegions = config.resource_groups;
+ } else {
+ // GCP
+ enabledRegions = config.project_ids;
+ }
+
logEvent(`${type} Integration: Account viewed`, {
cloudAccountId: activeAccount?.cloud_account_id,
status: activeAccount?.status,
- enabledRegions:
- 'regions' in activeAccount.config
- ? activeAccount.config.regions
- : activeAccount.config.resource_groups,
+ enabledRegions,
});
}
}, [activeAccount, type]);
diff --git a/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/ServiceDetails/ServiceDetails.tsx b/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/ServiceDetails/ServiceDetails.tsx
index ce03341cb9..0f28594965 100644
--- a/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/ServiceDetails/ServiceDetails.tsx
+++ b/frontend/src/container/Integrations/CloudIntegration/AmazonWebServices/ServiceDetails/ServiceDetails.tsx
@@ -46,14 +46,31 @@ const EMPTY_FORM_VALUES: ServiceConfigFormValues = {
s3BucketsByRegion: {},
};
+function getIntegrationServiceConfig(
+ type: IntegrationType,
+ serviceDetailsData?: ServiceDetailsData,
+):
+ | { logs?: { enabled?: boolean }; metrics?: { enabled?: boolean } }
+ | undefined {
+ const config = serviceDetailsData?.cloudIntegrationService?.config;
+
+ if (type === IntegrationType.AWS_SERVICES) {
+ return config?.aws;
+ }
+ if (type === IntegrationType.GCP_SERVICES) {
+ return config?.gcp;
+ }
+ return config?.azure;
+}
+
function getInitialFormValues(
type: IntegrationType,
serviceDetailsData?: ServiceDetailsData,
): ServiceConfigFormValues {
- const integrationConfig =
- type === IntegrationType.AWS_SERVICES
- ? serviceDetailsData?.cloudIntegrationService?.config?.aws
- : serviceDetailsData?.cloudIntegrationService?.config?.azure;
+ const integrationConfig = getIntegrationServiceConfig(
+ type,
+ serviceDetailsData,
+ );
return {
logsEnabled: integrationConfig?.logs?.enabled || false,
@@ -98,16 +115,21 @@ function getServiceConfigPayload({
};
}
- return {
- azure: {
- logs: {
- enabled: isLogsSupported ? logsEnabled : false,
- },
- metrics: {
- enabled: isMetricsSupported ? metricsEnabled : false,
- },
+ // Azure and GCP share the same simple logs/metrics enable-flag shape.
+ const signalConfig = {
+ logs: {
+ enabled: isLogsSupported ? logsEnabled : false,
+ },
+ metrics: {
+ enabled: isMetricsSupported ? metricsEnabled : false,
},
};
+
+ if (type === IntegrationType.GCP_SERVICES) {
+ return { gcp: signalConfig };
+ }
+
+ return { azure: signalConfig };
}
function ServiceDetails({
@@ -163,10 +185,10 @@ function ServiceDetails({
? isAccountServiceLoading
: isReadOnlyServiceLoading;
- const integrationConfig =
- type === IntegrationType.AWS_SERVICES
- ? serviceDetailsData?.cloudIntegrationService?.config?.aws
- : serviceDetailsData?.cloudIntegrationService?.config?.azure;
+ const integrationConfig = getIntegrationServiceConfig(
+ type,
+ serviceDetailsData,
+ );
const isServiceEnabledInPersistedConfig =
Boolean(integrationConfig?.logs?.enabled) ||
Boolean(integrationConfig?.metrics?.enabled);
diff --git a/frontend/src/container/Integrations/CloudIntegration/AzureCloudServices/EditAccount/AccountSettingsModal.tsx b/frontend/src/container/Integrations/CloudIntegration/AzureCloudServices/EditAccount/AccountSettingsModal.tsx
index cbe0b1dc63..81b9ba9a3f 100644
--- a/frontend/src/container/Integrations/CloudIntegration/AzureCloudServices/EditAccount/AccountSettingsModal.tsx
+++ b/frontend/src/container/Integrations/CloudIntegration/AzureCloudServices/EditAccount/AccountSettingsModal.tsx
@@ -36,8 +36,12 @@ function AccountSettingsModal({
const queryClient = useQueryClient();
+ // `account.config` is the shared per-provider union (Azure | AWS | GCP).
+ // Narrow to Azure by `resource_groups` (Azure-only) rather than
+ // `deployment_region`, which GCP also has — so it no longer identifies
+ // Azure uniquely.
const azureConfig = useMemo(
- () => ('deployment_region' in account.config ? account.config : null),
+ () => ('resource_groups' in account.config ? account.config : null),
[account.config],
);
diff --git a/frontend/src/container/Integrations/CloudIntegration/RemoveAccount/RemoveIntegrationAccount.tsx b/frontend/src/container/Integrations/CloudIntegration/RemoveAccount/RemoveIntegrationAccount.tsx
index 9e3f166eb1..548046fa9e 100644
--- a/frontend/src/container/Integrations/CloudIntegration/RemoveAccount/RemoveIntegrationAccount.tsx
+++ b/frontend/src/container/Integrations/CloudIntegration/RemoveAccount/RemoveIntegrationAccount.tsx
@@ -60,6 +60,44 @@ function RemoveIntegrationAccount({
setIsModalOpen(false);
};
+ let modalDescription: JSX.Element;
+ if (cloudProvider === INTEGRATION_TYPES.AWS) {
+ modalDescription = (
+ <>
+ Removing this account will remove all components created for sending
+ telemetry to SigNoz in your AWS account within the next ~15 minutes
+ (cloudformation stacks named signoz-integration-telemetry-collection in
+ enabled regions).
+
+ After that, you can delete the cloudformation stack that was created
+ manually when connecting this account.
+ >
+ );
+ } else if (cloudProvider === INTEGRATION_TYPES.GCP) {
+ modalDescription = (
+ <>
+ Removing this account will stop SigNoz from monitoring it.
+
+ Since you manage the GCP resources yourself, remember to manually tear down
+ the OTel collector and Pub/Sub resources you created for this integration if
+ you no longer need them.
+ >
+ );
+ } else {
+ modalDescription = (
+ <>
+ Removing this account will remove all components created for sending
+ telemetry to SigNoz in your Azure subscription within the next ~15 minutes
+ (deployment stack named signoz-integration-telemetry will be deleted
+ automatically).
+
+ After that, you have to manually delete 'signoz-integration'
+ deployment stack that was created while connecting this account (Takes ~20
+ minutes to delete).
+ >
+ );
+ }
+
return (
);
diff --git a/frontend/src/container/Integrations/CloudIntegration/mapCloudAccountFromDto.ts b/frontend/src/container/Integrations/CloudIntegration/mapCloudAccountFromDto.ts
index cbd84f6338..71d0b15cdb 100644
--- a/frontend/src/container/Integrations/CloudIntegration/mapCloudAccountFromDto.ts
+++ b/frontend/src/container/Integrations/CloudIntegration/mapCloudAccountFromDto.ts
@@ -47,3 +47,27 @@ export function mapAccountDtoToAzureCloudAccount(
providerAccountId: account.providerAccountId,
};
}
+
+export function mapAccountDtoToGcpCloudAccount(
+ account: CloudintegrationtypesAccountDTO,
+): IntegrationCloudAccount | null {
+ if (!account.providerAccountId) {
+ return null;
+ }
+
+ return {
+ id: account.id,
+ cloud_account_id: account.id,
+ config: {
+ deployment_region: account.config?.gcp?.deploymentRegion ?? '',
+ deployment_project_id: account.config?.gcp?.deploymentProjectId ?? '',
+ project_ids: account.config?.gcp?.projectIds ?? [],
+ },
+ status: {
+ integration: {
+ last_heartbeat_ts_ms: account.agentReport?.timestampMillis ?? 0,
+ },
+ },
+ providerAccountId: account.providerAccountId,
+ };
+}
diff --git a/frontend/src/container/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx b/frontend/src/container/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
index 340b5e7f30..d58824468b 100644
--- a/frontend/src/container/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
+++ b/frontend/src/container/Integrations/IntegrationDetailPage/IntegrationDetailPage.tsx
@@ -13,8 +13,8 @@ import { ArrowLeft, MoveUpRight, RotateCw } from '@signozhq/icons';
import awwSnapUrl from '@/assets/Icons/awwSnap.svg';
import CloudIntegration from '../CloudIntegration/CloudIntegration';
-import { INTEGRATION_TYPES } from '../constants';
import { IntegrationType } from '../types';
+import { INTEGRATION_TYPES } from '../constants';
import { handleContactSupport } from '../utils';
import IntegrationDetailContent from './IntegrationDetailContent';
import IntegrationDetailHeader from './IntegrationDetailHeader';
@@ -24,6 +24,12 @@ import { getConnectionStatesFromConnectionStatus } from './utils';
import './IntegrationDetailPage.styles.scss';
+const cloudIntegrationTypeById: Record = {
+ [INTEGRATION_TYPES.AWS]: IntegrationType.AWS_SERVICES,
+ [INTEGRATION_TYPES.AZURE]: IntegrationType.AZURE_SERVICES,
+ [INTEGRATION_TYPES.GCP]: IntegrationType.GCP_SERVICES,
+};
+
// eslint-disable-next-line sonarjs/cognitive-complexity
function IntegrationDetailPage(): JSX.Element {
const history = useHistory();
@@ -55,19 +61,8 @@ function IntegrationDetailPage(): JSX.Element {
),
);
- if (
- integrationId === INTEGRATION_TYPES.AWS ||
- integrationId === INTEGRATION_TYPES.AZURE
- ) {
- return (
-
- );
+ if (integrationId && cloudIntegrationTypeById[integrationId]) {
+ return ;
}
return (
diff --git a/frontend/src/container/Integrations/constants.ts b/frontend/src/container/Integrations/constants.ts
index 8645bcf9a0..bc28506636 100644
--- a/frontend/src/container/Integrations/constants.ts
+++ b/frontend/src/container/Integrations/constants.ts
@@ -1,7 +1,8 @@
import awsDarkLogo from '@/assets/Logos/aws-dark.svg';
import azureOpenaiLogo from '@/assets/Logos/azure-openai.svg';
+import gcpLogo from '@/assets/Logos/gcp.svg';
-import { AzureRegion } from './types';
+import { AzureRegion, GCPRegion } from './types';
export const INTEGRATION_TELEMETRY_EVENTS = {
INTEGRATIONS_LIST_VISITED: 'Integrations Page: Visited the list page',
@@ -21,6 +22,7 @@ export const INTEGRATION_TELEMETRY_EVENTS = {
export const INTEGRATION_TYPES = {
AWS: 'aws',
AZURE: 'azure',
+ GCP: 'gcp',
};
export const AWS_INTEGRATION = {
@@ -53,7 +55,26 @@ export const AZURE_INTEGRATION = {
is_new: true,
};
-export const ONE_CLICK_INTEGRATIONS = [AWS_INTEGRATION, AZURE_INTEGRATION];
+export const GCP_INTEGRATION = {
+ id: INTEGRATION_TYPES.GCP,
+ title: 'Google Cloud Platform',
+ description: 'Setup for GCP monitoring with SigNoz',
+ author: {
+ name: 'SigNoz',
+ email: 'integrations@signoz.io',
+ homepage: 'https://signoz.io',
+ },
+ icon: gcpLogo,
+ icon_alt: 'gcp-logo',
+ is_installed: false,
+ is_new: true,
+};
+
+export const ONE_CLICK_INTEGRATIONS = [
+ AWS_INTEGRATION,
+ AZURE_INTEGRATION,
+ GCP_INTEGRATION,
+];
export const AZURE_REGIONS: AzureRegion[] = [
{
@@ -165,3 +186,66 @@ export const AZURE_REGIONS: AzureRegion[] = [
{ label: 'West US 2', value: 'westus2', geography: 'United States' },
{ label: 'West US 3', value: 'westus3', geography: 'United States' },
];
+
+// Source of truth: pkg/types/cloudintegrationtypes/regions.go (GCP regions).
+export const GCP_REGIONS: GCPRegion[] = [
+ { label: 'Johannesburg', value: 'africa-south1', geography: 'Africa' },
+ { label: 'Changhua County', value: 'asia-east1', geography: 'APAC' },
+ { label: 'Hong Kong', value: 'asia-east2', geography: 'APAC' },
+ { label: 'Tokyo', value: 'asia-northeast1', geography: 'APAC' },
+ { label: 'Osaka', value: 'asia-northeast2', geography: 'APAC' },
+ { label: 'Seoul', value: 'asia-northeast3', geography: 'APAC' },
+ { label: 'Mumbai', value: 'asia-south1', geography: 'APAC' },
+ { label: 'Delhi', value: 'asia-south2', geography: 'APAC' },
+ { label: 'Singapore', value: 'asia-southeast1', geography: 'APAC' },
+ { label: 'Jakarta', value: 'asia-southeast2', geography: 'APAC' },
+ { label: 'Bangkok', value: 'asia-southeast3', geography: 'APAC' },
+ { label: 'Sydney', value: 'australia-southeast1', geography: 'APAC' },
+ { label: 'Melbourne', value: 'australia-southeast2', geography: 'APAC' },
+ { label: 'Warsaw', value: 'europe-central2', geography: 'Europe' },
+ { label: 'Hamina', value: 'europe-north1', geography: 'Europe' },
+ { label: 'Stockholm', value: 'europe-north2', geography: 'Europe' },
+ { label: 'Madrid', value: 'europe-southwest1', geography: 'Europe' },
+ { label: 'St. Ghislain', value: 'europe-west1', geography: 'Europe' },
+ { label: 'London', value: 'europe-west2', geography: 'Europe' },
+ { label: 'Frankfurt', value: 'europe-west3', geography: 'Europe' },
+ { label: 'Eemshaven', value: 'europe-west4', geography: 'Europe' },
+ { label: 'Zurich', value: 'europe-west6', geography: 'Europe' },
+ { label: 'Milan', value: 'europe-west8', geography: 'Europe' },
+ { label: 'Paris', value: 'europe-west9', geography: 'Europe' },
+ { label: 'Berlin', value: 'europe-west10', geography: 'Europe' },
+ { label: 'Turin', value: 'europe-west12', geography: 'Europe' },
+ { label: 'Doha', value: 'me-central1', geography: 'Middle East' },
+ { label: 'Dammam', value: 'me-central2', geography: 'Middle East' },
+ { label: 'Tel Aviv', value: 'me-west1', geography: 'Middle East' },
+ {
+ label: 'Montréal',
+ value: 'northamerica-northeast1',
+ geography: 'North America',
+ },
+ {
+ label: 'Toronto',
+ value: 'northamerica-northeast2',
+ geography: 'North America',
+ },
+ {
+ label: 'Querétaro',
+ value: 'northamerica-south1',
+ geography: 'North America',
+ },
+ {
+ label: 'São Paulo',
+ value: 'southamerica-east1',
+ geography: 'South America',
+ },
+ { label: 'Santiago', value: 'southamerica-west1', geography: 'South America' },
+ { label: 'Council Bluffs', value: 'us-central1', geography: 'North America' },
+ { label: 'Moncks Corner', value: 'us-east1', geography: 'North America' },
+ { label: 'Ashburn', value: 'us-east4', geography: 'North America' },
+ { label: 'Columbus', value: 'us-east5', geography: 'North America' },
+ { label: 'Dallas', value: 'us-south1', geography: 'North America' },
+ { label: 'The Dalles', value: 'us-west1', geography: 'North America' },
+ { label: 'Los Angeles', value: 'us-west2', geography: 'North America' },
+ { label: 'Salt Lake City', value: 'us-west3', geography: 'North America' },
+ { label: 'Las Vegas', value: 'us-west4', geography: 'North America' },
+];
diff --git a/frontend/src/container/Integrations/types.ts b/frontend/src/container/Integrations/types.ts
index 9e29a1a087..aa154898b3 100644
--- a/frontend/src/container/Integrations/types.ts
+++ b/frontend/src/container/Integrations/types.ts
@@ -6,6 +6,7 @@ import {
export enum IntegrationType {
AWS_SERVICES = 'aws',
AZURE_SERVICES = 'azure',
+ GCP_SERVICES = 'gcp',
}
interface LogField {
@@ -87,7 +88,10 @@ export interface ServiceData {
export interface CloudAccount {
id: string;
cloud_account_id: string;
- config: AzureCloudAccountConfig | AWSCloudAccountConfig;
+ config:
+ | AzureCloudAccountConfig
+ | AWSCloudAccountConfig
+ | GCPCloudAccountConfig;
status: AccountStatus | IServiceStatus;
providerAccountId: string;
}
@@ -97,6 +101,12 @@ export interface AzureCloudAccountConfig {
resource_groups: string[];
}
+export interface GCPCloudAccountConfig {
+ deployment_region: string;
+ deployment_project_id: string;
+ project_ids: string[];
+}
+
export interface AccountStatus {
integration: IntegrationStatus;
}
@@ -111,6 +121,12 @@ export interface AzureRegion {
value: string;
}
+export interface GCPRegion {
+ label: string;
+ geography: string;
+ value: string;
+}
+
export interface UpdateServiceConfigPayload {
cloud_account_id: string;
config: AzureServicesConfig;
diff --git a/frontend/src/hooks/integration/azure/useAccountSettingsModal.ts b/frontend/src/hooks/integration/azure/useAccountSettingsModal.ts
index 25eb705b41..7ffb9af58a 100644
--- a/frontend/src/hooks/integration/azure/useAccountSettingsModal.ts
+++ b/frontend/src/hooks/integration/azure/useAccountSettingsModal.ts
@@ -39,8 +39,12 @@ export function useAccountSettingsModal({
}: UseAccountSettingsModalProps): UseAccountSettingsModal {
const [form] = Form.useForm();
const { mutate: updateAccount, isLoading } = useUpdateAccount();
+ // `account.config` is the shared per-provider union (Azure | AWS | GCP).
+ // Narrow to Azure by `resource_groups` (Azure-only) rather than
+ // `deployment_region`, which GCP also has — so it no longer identifies
+ // Azure uniquely.
const accountConfig = useMemo(
- () => ('deployment_region' in account.config ? account.config : null),
+ () => ('resource_groups' in account.config ? account.config : null),
[account.config],
);
const [resourceGroups, setResourceGroups] = useState(