diff --git a/src/services/mySqlServers/data.ts b/src/services/mySqlServers/data.ts index 24b3d7f6..1938e29f 100644 --- a/src/services/mySqlServers/data.ts +++ b/src/services/mySqlServers/data.ts @@ -1,4 +1,10 @@ -import { MySQLManagementClient, Server } from '@azure/arm-mysql' +import { + Configuration, + FirewallRule, + MySQLManagementClient, + Server, + VirtualNetworkRule, +} from '@azure/arm-mysql' import { PagedAsyncIterableIterator } from '@azure/core-paging' import CloudGraph from '@cloudgraph/sdk' import azureLoggerText from '../../properties/logger' @@ -11,11 +17,97 @@ const { logger } = CloudGraph const lt = { ...azureLoggerText } const serviceName = 'MySQL Server' -export interface RawAzureMySqlServer - extends Omit { +export interface RawAzureMySqlServer extends Omit { region: string resourceGroupId: string Tags: TagMap + configurations: Configuration[] + firewallRules: FirewallRule[] + virtualNetworkRules: VirtualNetworkRule[] +} + +const listConfigurations = async ( + client: MySQLManagementClient, + resourceGroup: string, + serverName: string +): Promise => { + const configurations: Configuration[] = [] + const configurationsIterable = client.configurations.listByServer( + resourceGroup, + serverName + ) + await tryCatchWrapper( + async () => { + for await (const configuration of configurationsIterable) { + if (configuration) { + configurations.push(configuration) + } + } + }, + { + service: serviceName, + client, + scope: 'configurations', + operation: 'listByServer', + } + ) + return configurations +} + +const listFirewallRules = async ( + client: MySQLManagementClient, + resourceGroup: string, + serverName: string +): Promise => { + const firewallRules: FirewallRule[] = [] + const firewallRuleIterable = client.firewallRules.listByServer( + resourceGroup, + serverName + ) + await tryCatchWrapper( + async () => { + for await (const firewallRule of firewallRuleIterable) { + if (firewallRule) { + firewallRules.push(firewallRule) + } + } + }, + { + service: serviceName, + client, + scope: 'firewallRules', + operation: 'listByServer', + } + ) + return firewallRules +} + +const listVirtualNetworkRules = async ( + client: MySQLManagementClient, + resourceGroup: string, + serverName: string +): Promise => { + const virtualNetworkRules: VirtualNetworkRule[] = [] + const virtualNetworkRulesIterable = client.virtualNetworkRules.listByServer( + resourceGroup, + serverName + ) + await tryCatchWrapper( + async () => { + for await (const virtualNetworkRule of virtualNetworkRulesIterable) { + if (virtualNetworkRule) { + virtualNetworkRules.push(virtualNetworkRule) + } + } + }, + { + service: serviceName, + client, + scope: 'virtualNetworkRules', + operation: 'listByServer', + } + ) + return virtualNetworkRules } export default async ({ @@ -26,10 +118,7 @@ export default async ({ }> => { try { const { tokenCredentials, subscriptionId } = config - const client = new MySQLManagementClient( - tokenCredentials, - subscriptionId - ) + const client = new MySQLManagementClient(tokenCredentials, subscriptionId) const sqlServers: Server[] = [] const sqlServerIterable: PagedAsyncIterableIterator = client.servers.list() @@ -49,21 +138,40 @@ export default async ({ logger.debug(lt.foundMySqlServers(sqlServers.length)) const result: { [property: string]: RawAzureMySqlServer[] } = {} - sqlServers.map(({ location, tags, ...rest }) => { - const region = lowerCaseLocation(location) - if (regions.includes(region)) { - if (!result[region]) { - result[region] = [] + await Promise.all( + sqlServers.map(async ({ name, location, tags, ...rest }) => { + const region = lowerCaseLocation(location) + if (regions.includes(region)) { + if (!result[region]) { + result[region] = [] + } + const resourceGroupId = getResourceGroupFromEntity(rest) + result[region].push({ + name, + region, + ...rest, + resourceGroupId, + Tags: tags || {}, + configurations: await listConfigurations( + client, + resourceGroupId, + name + ), + firewallRules: await listFirewallRules( + client, + resourceGroupId, + name + ), + virtualNetworkRules: await listVirtualNetworkRules( + client, + resourceGroupId, + name + ), + }) } - const resourceGroupId = getResourceGroupFromEntity(rest) - result[region].push({ - region, - ...rest, - resourceGroupId, - Tags: tags || {}, - }) - } - }) + }) + ) + return result } catch (e) { logger.error(e) diff --git a/src/services/mySqlServers/format.ts b/src/services/mySqlServers/format.ts index cf324b24..bbe5983c 100644 --- a/src/services/mySqlServers/format.ts +++ b/src/services/mySqlServers/format.ts @@ -1,6 +1,11 @@ import { formatTagsFromMap } from '../../utils/format' import { RawAzureMySqlServer } from './data' -import { AzureMySqlServer } from '../../types/generated' +import { + AzureMySqlServer, + AzureMySqlServerConfiguration, + AzureMySqlServerFirewallRule, + AzureMySqlServerVirtualNetworkRule, +} from '../../types/generated' export default ({ service, @@ -33,6 +38,9 @@ export default ({ privateEndpointConnections, resourceGroupId, Tags, + configurations = [], + firewallRules = [], + virtualNetworkRules = [], } = service return { @@ -60,7 +68,47 @@ export default ({ privateEndpointConnections: privateEndpointConnections?.map(connection => ({ ...connection, id: connection.id, - })), + })), tags: formatTagsFromMap(Tags), + configurations: + configurations?.map( + ({ + id: configurationId, + name: configurationName, + type: configurationType, + }): AzureMySqlServerConfiguration => ({ + id: configurationId, + name: configurationName, + type: configurationType, + }) + ) ?? [], + firewallRules: + firewallRules?.map( + ({ + id: firewallRuleId, + name: firewallRuleName, + type: firewallRuleType, + startIpAddress, + endIpAddress, + }): AzureMySqlServerFirewallRule => ({ + id: firewallRuleId, + name: firewallRuleName, + type: firewallRuleType, + startIpAddress, + endIpAddress, + }) + ) ?? [], + virtualNetworkRules: + virtualNetworkRules?.map( + ({ + id: virtualNetworkRuleId, + name: virtualNetworkRuleName, + type: virtualNetworkRuleType, + }): AzureMySqlServerVirtualNetworkRule => ({ + id: virtualNetworkRuleId, + name: virtualNetworkRuleName, + type: virtualNetworkRuleType, + }) + ) ?? [], } -} \ No newline at end of file +} diff --git a/src/services/mySqlServers/schema.graphql b/src/services/mySqlServers/schema.graphql index 7f55001f..5c2b9af2 100644 --- a/src/services/mySqlServers/schema.graphql +++ b/src/services/mySqlServers/schema.graphql @@ -19,6 +19,9 @@ type azureMySqlServer implements azureResource replicaCapacity: Int @search publicNetworkAccess: String @search(by: [hash, regexp]) privateEndpointConnections: [azureMySqlServerServerPrivateEndpointConnection] + configurations: [azureMySqlServerConfiguration] + firewallRules: [azureMySqlServerFirewallRule] + virtualNetworkRules: [azureMySqlServerVirtualNetworkRule] databaseMySql: [azureDatabaseMySql] @hasInverse(field: mySqlServer) resourceGroup: [azureResourceGroup] @hasInverse(field: mySqlServer) } @@ -81,4 +84,42 @@ type azureMySqlServerServerPrivateLinkServiceConnectionStateProperty status: String @search(by: [hash, regexp]) description: String @search(by: [hash, regexp]) actionsRequired: String @search(by: [hash, regexp]) +} + +type azureMySqlServerConfiguration + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) + @key(fields: "id") { + id: String! @id @search(by: [hash]) + name: String @search(by: [hash, regexp]) + type: String @search(by: [hash, regexp]) +} + +type azureMySqlServerFirewallRule + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) + @key(fields: "id") { + id: String! @id @search(by: [hash]) + name: String @search(by: [hash, regexp]) + type: String @search(by: [hash, regexp]) + startIpAddress: String @search(by: [hash, regexp]) + endIpAddress: String @search(by: [hash, regexp]) +} + +type azureMySqlServerVirtualNetworkRule + @generate( + query: { get: false, query: true, aggregate: false } + mutation: { add: false, delete: false } + subscription: false + ) + @key(fields: "id") { + id: String! @id @search(by: [hash]) + name: String @search(by: [hash, regexp]) + type: String @search(by: [hash, regexp]) } \ No newline at end of file diff --git a/src/types/generated.ts b/src/types/generated.ts index 5b35a3ab..8e82639e 100644 --- a/src/types/generated.ts +++ b/src/types/generated.ts @@ -4078,8 +4078,10 @@ export type AzureMetricAlertMultiMetricCriteria = { export type AzureMySqlServer = AzureResource & { administratorLogin?: Maybe; byokEnforcement?: Maybe; + configurations?: Maybe>>; databaseMySql?: Maybe>>; earliestRestoreDate?: Maybe; + firewallRules?: Maybe>>; fullyQualifiedDomainName?: Maybe; identity?: Maybe; infrastructureEncryption?: Maybe; @@ -4094,6 +4096,21 @@ export type AzureMySqlServer = AzureResource & { storageProfile?: Maybe; userVisibleState?: Maybe; version?: Maybe; + virtualNetworkRules?: Maybe>>; +}; + +export type AzureMySqlServerConfiguration = { + id: Scalars['String']; + name?: Maybe; + type?: Maybe; +}; + +export type AzureMySqlServerFirewallRule = { + endIpAddress?: Maybe; + id: Scalars['String']; + name?: Maybe; + startIpAddress?: Maybe; + type?: Maybe; }; export type AzureMySqlServerPrivateEndpointProperty = { @@ -4130,6 +4147,12 @@ export type AzureMySqlServerStorageProfile = { storageMB?: Maybe; }; +export type AzureMySqlServerVirtualNetworkRule = { + id: Scalars['String']; + name?: Maybe; + type?: Maybe; +}; + export type AzureNameValueProperty = { id: Scalars['String']; name?: Maybe;