diff --git a/.azuredevops/modulePipelines/ms.servicefabric.clusters.yml b/.azuredevops/modulePipelines/ms.servicefabric.clusters.yml new file mode 100644 index 0000000000..8e474d6696 --- /dev/null +++ b/.azuredevops/modulePipelines/ms.servicefabric.clusters.yml @@ -0,0 +1,63 @@ +name: 'Service Fabric - Clusters' + +parameters: + - name: removeDeployment + displayName: Remove deployed module + type: boolean + default: true + - name: versioningOption + displayName: The mode to handle the version increments [major|minor|patch] + type: string + default: patch + values: + - patch + - minor + - major + - name: customVersion + displayName: Custom version to apply. Used only if higher than latest + type: string + default: '0.0.1' + +trigger: + batch: true + branches: + include: + - main + paths: + include: + - '/.azuredevops/modulePipelines/ms.servicefabric.clusters.yml' + - '/.azuredevops/pipelineTemplates/module.*.yml' + - '/Microsoft.ServiceFabric/clusters/*' + exclude: + - '/**/*.md' + +variables: + - template: '/.azuredevops/pipelineVariables/global.variables.yml' + - group: 'PLATFORM_VARIABLES' + - name: modulePath + value: '/arm/Microsoft.ServiceFabric/clusters' + +stages: + - stage: Validation + displayName: Pester tests + jobs: + - template: /.azuredevops/pipelineTemplates/module.jobs.validate.yml + + - stage: Deployment + displayName: Deployment tests + jobs: + - template: /.azuredevops/pipelineTemplates/module.jobs.deploy.yml + parameters: + removeDeployment: '${{ parameters.removeDeployment }}' + deploymentBlocks: + - path: $(modulePath)/.parameters/min.parameters.json + - path: $(modulePath)/.parameters/parameters.json + + - stage: Publishing + displayName: Publish module + condition: and(succeeded(), eq(variables['Build.SourceBranch'], 'refs/heads/main')) + jobs: + - template: /.azuredevops/pipelineTemplates/module.jobs.publish.yml + parameters: + versioningOption: '${{ parameters.versioningOption }}' + customVersion: '${{ parameters.customVersion }}' diff --git a/.github/workflows/ms.servicefabric.clusters.yml b/.github/workflows/ms.servicefabric.clusters.yml new file mode 100644 index 0000000000..0fca4bf2c6 --- /dev/null +++ b/.github/workflows/ms.servicefabric.clusters.yml @@ -0,0 +1,147 @@ +name: 'Service Fabric: Clusters' + +on: + workflow_dispatch: + inputs: + removeDeployment: + type: boolean + description: 'Remove deployed module' + required: false + default: 'true' + versioningOption: + type: choice + description: 'The mode to handle the version increments [major|minor|patch]' + required: false + default: 'patch' + options: + - major + - minor + - patch + customVersion: + description: 'Custom version to apply. Used only if higher than latest' + required: false + default: '0.0.1' + push: + branches: + - main + paths: + - '.github/actions/templates/**' + - '.github/workflows/ms.servicefabric.clusters.yml' + - 'arm/Microsoft.ServiceFabric/clusters/**' + - '!*/**/readme.md' + - 'utilities/pipelines/**' + - '!utilities/pipelines/dependencies/**' + +env: + modulePath: 'arm/Microsoft.ServiceFabric/clusters' + workflowPath: '.github/workflows/ms.servicefabric.clusters.yml' + AZURE_CREDENTIALS: ${{ secrets.AZURE_CREDENTIALS }} + ARM_SUBSCRIPTION_ID: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + ARM_MGMTGROUP_ID: '${{ secrets.ARM_MGMTGROUP_ID }}' + ARM_TENANT_ID: '${{ secrets.ARM_TENANT_ID }}' + DEPLOYMENT_SP_ID: '${{ secrets.DEPLOYMENT_SP_ID }}' + +jobs: + ############################ + # SET INPUT PARAMETERS # + ############################ + job_set_workflow_param: + runs-on: ubuntu-20.04 + name: 'Set input parameters to output variables' + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: 'Set input parameters' + id: get-workflow-param + uses: ./.github/actions/templates/getWorkflowInput + with: + workflowPath: '${{ env.workflowPath}}' + outputs: + removeDeployment: ${{ steps.get-workflow-param.outputs.removeDeployment }} + versioningOption: ${{ steps.get-workflow-param.outputs.versioningOption }} + customVersion: ${{ steps.get-workflow-param.outputs.customVersion }} + + #################### + # Pester Tests # + #################### + job_module_pester_validation: + runs-on: ubuntu-20.04 + name: 'Pester tests' + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: 'Run tests' + uses: ./.github/actions/templates/validateModulePester + with: + modulePath: '${{ env.modulePath }}' + + #################### + # Deployment tests # + #################### + job_module_deploy_validation: + runs-on: ubuntu-20.04 + name: 'Deployment tests' + needs: + - job_set_workflow_param + - job_module_pester_validation + strategy: + fail-fast: false + matrix: + parameterFilePaths: ['min.parameters.json', 'parameters.json'] + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set environment variables + uses: deep-mm/set-variables@v1.0 + with: + variableFileName: 'global.variables' + - name: 'Using parameter file [${{ matrix.parameterFilePaths }}]' + uses: ./.github/actions/templates/validateModuleDeployment + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + parameterFilePath: '${{ env.modulePath }}/.parameters/${{ matrix.parameterFilePaths }}' + location: '${{ env.defaultLocation }}' + resourceGroupName: '${{ env.resourceGroupName }}' + subscriptionId: '${{ secrets.ARM_SUBSCRIPTION_ID }}' + managementGroupId: '${{ secrets.ARM_MGMTGROUP_ID }}' + removeDeployment: '${{ needs.job_set_workflow_param.outputs.removeDeployment }}' + + ############### + # PUBLISH # + ############### + job_publish_module: + name: 'Publish module' + if: github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' + runs-on: ubuntu-20.04 + needs: + - job_set_workflow_param + - job_module_deploy_validation + steps: + - name: 'Checkout' + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Set environment variables + uses: deep-mm/set-variables@v1.0 + with: + variableFileName: 'global.variables' + - name: 'Publish module' + uses: ./.github/actions/templates/publishModule + with: + templateFilePath: '${{ env.modulePath }}/deploy.bicep' + versioningOption: '${{ needs.job_set_workflow_param.outputs.versioningOption }}' + customVersion: '${{ needs.job_set_workflow_param.outputs.customVersion }}' + templateSpecsRGName: '${{ env.templateSpecsRGName }}' + templateSpecsRGLocation: '${{ env.templateSpecsRGLocation }}' + templateSpecsDescription: '${{ env.templateSpecsDescription }}' + templateSpecsDoPublish: '${{ env.templateSpecsDoPublish }}' + bicepRegistryName: '${{ env.bicepRegistryName }}' + bicepRegistryRGName: '${{ env.bicepRegistryRGName }}' + bicepRegistryRgLocation: '${{ env.bicepRegistryRgLocation }}' + bicepRegistryDoPublish: '${{ env.bicepRegistryDoPublish }}' diff --git a/arm/Microsoft.ServiceFabric/clusters/.bicep/nested_cuaId.bicep b/arm/Microsoft.ServiceFabric/clusters/.bicep/nested_cuaId.bicep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/arm/Microsoft.ServiceFabric/clusters/.bicep/nested_rbac.bicep b/arm/Microsoft.ServiceFabric/clusters/.bicep/nested_rbac.bicep new file mode 100644 index 0000000000..123939358a --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/.bicep/nested_rbac.bicep @@ -0,0 +1,32 @@ +param principalIds array +param roleDefinitionIdOrName string +param resourceId string + +var builtInRoleNames = { + 'Owner': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8e3af657-a8ff-443c-a75c-2fe8c4bcb635') + 'Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b24988ac-6180-42a0-ab88-20f7382dd24c') + 'Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'acdd72a7-3385-48ef-bd42-f606fba81ae7') + 'Log Analytics Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '92aaf0da-9dab-42b6-94a3-d43ce8d16293') + 'Log Analytics Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '73c42c96-874c-492b-b04d-ab87d138a893') + 'Managed Application Contributor Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '641177b8-a67a-45b9-a033-47bc880bb21e') + 'Managed Application Operator Role': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'c7393b34-138c-406f-901b-d8cf2b17e6ae') + 'Managed Applications Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', 'b9331d33-8a36-4f8c-b097-4f54124fdb44') + 'Monitoring Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '749f88d5-cbae-40b8-bcfc-e573ddc772fa') + 'Monitoring Metrics Publisher': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '3913510d-42f4-4e42-8a64-420c390055eb') + 'Monitoring Reader': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '43d0d8ad-25c7-4714-9337-8ba259a9fe05') + 'Resource Policy Contributor': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '36243c78-bf99-498c-9df9-86d9f8d28608') + 'User Access Administrator': subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '18d7d88d-d35e-4fb5-a5c3-7773c20a72d9') +} + +resource serviceFabricCluster 'Microsoft.ServiceFabric/clusters@2021-06-01' existing = { + name: last(split(resourceId, '/')) +} + +resource roleAssignment 'Microsoft.Authorization/roleAssignments@2020-04-01-preview' = [for principalId in principalIds: { + name: guid(serviceFabricCluster.name, principalId, roleDefinitionIdOrName) + properties: { + roleDefinitionId: contains(builtInRoleNames, roleDefinitionIdOrName) ? builtInRoleNames[roleDefinitionIdOrName] : roleDefinitionIdOrName + principalId: principalId + } + scope: serviceFabricCluster +}] diff --git a/arm/Microsoft.ServiceFabric/clusters/.parameters/cert.parameters.json b/arm/Microsoft.ServiceFabric/clusters/.parameters/cert.parameters.json new file mode 100644 index 0000000000..03ff74b75d --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/.parameters/cert.parameters.json @@ -0,0 +1,40 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "sxx-az-sfc-cert-001" + }, + "managementEndpoint": { + "value": "https://sxx-az-sfc-cert-001.westeurope.cloudapp.azure.com:19080" + }, + "reliabilityLevel": { + "value": "None" + }, + "certificate": { + "value": { + "thumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC130", // Mutual exclusive with the other cert specs + "x509StoreName": "My" + } + }, + "nodeTypes": { + "value": [ + { + "applicationPorts": { + "endPort": 30000, + "startPort": 20000 + }, + "clientConnectionEndpointPort": 19000, + "durabilityLevel": "Bronze", + "ephemeralPorts": { + "endPort": 65534, + "startPort": 49152 + }, + "httpGatewayEndpointPort": 19080, + "isPrimary": true, + "name": "Node01" + } + ] + } + } +} diff --git a/arm/Microsoft.ServiceFabric/clusters/.parameters/full.parameters.json b/arm/Microsoft.ServiceFabric/clusters/.parameters/full.parameters.json new file mode 100644 index 0000000000..8b24b1895f --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/.parameters/full.parameters.json @@ -0,0 +1,205 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "sxx-az-sfc-full-001" + }, + "tags": { + "value": { + "resourceType": "Service Fabric", + "clusterName": "sxx-az-sfc-full-001" + } + }, + "addOnFeatures": { + "value": [ + "RepairManager", + "DnsService", + "BackupRestoreService", + "ResourceMonitorService" + ] + }, + "maxUnusedVersionsToKeep": { + "value": 2 + }, + "azureActiveDirectory": { + "value": { + "clientApplication": "<>", + "clusterApplication": "cf33fea8-b30f-424f-ab73-c48d99e0b222", + "tenantId": "<>" + } + }, + "certificateCommonNames": { + "value": { + "commonNames": [ + { + "certificateCommonName": "certcommon", + "certificateIssuerThumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC130" + } + ], + "x509StoreName": "" + } + }, + "clientCertificateCommonNames": { + "value": [ + { + "certificateCommonName": "clientcommoncert1", + "certificateIssuerThumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC130", + "isAdmin": false + }, + { + "certificateCommonName": "clientcommoncert2", + "certificateIssuerThumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC131", + "isAdmin": false + } + ] + }, + "clientCertificateThumbprints": { + "value": [ + { + "certificateThumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC130", + "isAdmin": false + }, + { + "certificateThumbprint": "0AC113D5E1D94C401DDEB0EE2B1B96CC131", + "isAdmin": false + } + ] + }, + "diagnosticsStorageAccountConfig": { + "value": { + "blobEndpoint": "https://adpsxxazsaweux001.blob.core.windows.net/", + "protectedAccountKeyName": "StorageAccountKey1", + "queueEndpoint": "https://adpsxxazsaweux001.queue.core.windows.net/", + "storageAccountName": "adpsxxazsaweux001", + "tableEndpoint": "https://adpsxxazsaweux001.table.core.windows.net/" + } + }, + "fabricSettings": { + "value": [ + { + "name": "Security", + "parameters": [ + { + "name": "ClusterProtectionLevel", + "value": "EncryptAndSign" + } + ] + }, + { + "name": "UpgradeService", + "parameters": [ + { + "name": "AppPollIntervalInSeconds", + "value": "60" + } + ] + } + ] + }, + "managementEndpoint": { + "value": "https://sxx-az-sfc-full-001.westeurope.cloudapp.azure.com:19080" + }, + "nodeTypes": { + "value": [ + { + "applicationPorts": { + "endPort": 30000, + "startPort": 20000 + }, + "capacities": {}, + "clientConnectionEndpointPort": 19000, + "durabilityLevel": "Silver", + "ephemeralPorts": { + "endPort": 65534, + "startPort": 49152 + }, + "httpGatewayEndpointPort": 19080, + "isPrimary": true, + "isStateless": false, + "multipleAvailabilityZones": false, + "name": "Node01", + "placementProperties": {}, + "reverseProxyEndpointPort": "", + "vmInstanceCount": 5 + }, + { + "applicationPorts": { + "endPort": 30000, + "startPort": 20000 + }, + "clientConnectionEndpointPort": 19000, + "durabilityLevel": "Bronze", + "ephemeralPorts": { + "endPort": 64000, + "startPort": 49000 + }, + "httpGatewayEndpointPort": 19007, + "isPrimary": true, + "name": "Node02", + "vmInstanceCount": 5 + } + ] + }, + "notifications": { + "value": [ + { + "isEnabled": true, + "notificationCategory": "WaveProgress", + "notificationLevel": "Critical", + "notificationTargets": [ + { + "notificationChannel": "EmailUser", + "receivers": [ + "SomeReceiver" + ] + } + ] + } + ] + }, + "upgradeDescription": { + "value": { + "forceRestart": false, + "upgradeReplicaSetCheckTimeout": "1.00:00:00", + "healthCheckWaitDuration": "00:00:30", + "healthCheckStableDuration": "00:01:00", + "healthCheckRetryTimeout": "00:45:00", + "upgradeTimeout": "02:00:00", + "upgradeDomainTimeout": "02:00:00", + "healthPolicy": { + "maxPercentUnhealthyNodes": 0, + "maxPercentUnhealthyApplications": 0 + }, + "deltaHealthPolicy": { + "maxPercentDeltaUnhealthyNodes": 0, + "maxPercentUpgradeDomainDeltaUnhealthyNodes": 0, + "maxPercentDeltaUnhealthyApplications": 0 + } + } + }, + "reliabilityLevel": { + "value": "Silver" + }, + "vmImage": { + "value": "Linux" + }, + "roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "<>" + ] + } + ] + }, + "applicationTypes": { + "value": [ + { + "name": "WordCount" // not idempotent + } + ] + } + } +} diff --git a/arm/Microsoft.ServiceFabric/clusters/.parameters/min.parameters.json b/arm/Microsoft.ServiceFabric/clusters/.parameters/min.parameters.json new file mode 100644 index 0000000000..bcc750bdc3 --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/.parameters/min.parameters.json @@ -0,0 +1,34 @@ +{ + "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#", + "contentVersion": "1.0.0.0", + "parameters": { + "name": { + "value": "sxx-az-sfc-min-001" + }, + "managementEndpoint": { + "value": "https://sxx-az-sfc-min-001.westeurope.cloudapp.azure.com:19080" + }, + "reliabilityLevel": { + "value": "None" + }, + "nodeTypes": { + "value": [ + { + "applicationPorts": { + "endPort": 30000, + "startPort": 20000 + }, + "clientConnectionEndpointPort": 19000, + "durabilityLevel": "Bronze", + "ephemeralPorts": { + "endPort": 65534, + "startPort": 49152 + }, + "httpGatewayEndpointPort": 19080, + "isPrimary": true, + "name": "Node01" + } + ] + } + } +} diff --git a/arm/Microsoft.ServiceFabric/clusters/applicationTypes/.bicep/nested_cuaId.bicep b/arm/Microsoft.ServiceFabric/clusters/applicationTypes/.bicep/nested_cuaId.bicep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/arm/Microsoft.ServiceFabric/clusters/applicationTypes/deploy.bicep b/arm/Microsoft.ServiceFabric/clusters/applicationTypes/deploy.bicep new file mode 100644 index 0000000000..dbc0d3b70a --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/applicationTypes/deploy.bicep @@ -0,0 +1,35 @@ +@description('Required. Name of the Service Fabric cluster.') +param serviceFabricClusterName string = '' + +@description('Optional. Application type name.') +param name string = 'defaultApplicationType' + +@description('Optional. Tags of the resource.') +param tags object = {} + +@description('Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered') +param cuaId string = '' + +module pid_cuaId '.bicep/nested_cuaId.bicep' = if (!empty(cuaId)) { + name: 'pid-${cuaId}' + params: {} +} + +resource serviceFabricCluster 'Microsoft.ServiceFabric/clusters@2021-06-01' existing = { + name: serviceFabricClusterName +} + +resource applicationTypes 'Microsoft.ServiceFabric/clusters/applicationTypes@2021-06-01' = { + name: name + parent: serviceFabricCluster + tags: tags +} + +@description('The resource name of the Application type.') +output name string = applicationTypes.name + +@description('The resource group of the Application type.') +output resourceGroupName string = resourceGroup().name + +@description('The resource ID of the Application type.') +output resourceID string = applicationTypes.id diff --git a/arm/Microsoft.ServiceFabric/clusters/applicationTypes/readme.md b/arm/Microsoft.ServiceFabric/clusters/applicationTypes/readme.md new file mode 100644 index 0000000000..796bec35ef --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/applicationTypes/readme.md @@ -0,0 +1,47 @@ +# ServiceFabric Cluster Application Type `[Microsoft.ServiceFabric/clusters/applicationTypes]` + +This module deploys a ServiceFabric cluster application type. + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.ServiceFabric/clusters/applicationTypes` | 2021-06-01 | + +## Parameters + +| Parameter Name | Type | Default Value | Possible Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `cuaId` | string | | | Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered | +| `name` | string | `defaultApplicationType` | | Optional. Application type name. | +| `serviceFabricClusterName` | string | | | Required. Name of the Service Fabric cluster. | +| `tags` | object | `{object}` | | Optional. Tags of the resource. | + +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `name` | string | The resource name of the Application type. | +| `resourceGroupName` | string | The resource group of the Application type. | +| `resourceID` | string | The resource ID of the Application type. | + +## Template references + +- [Clusters/Applicationtypes](https://docs.microsoft.com/en-us/azure/templates/Microsoft.ServiceFabric/2021-06-01/clusters/applicationTypes) diff --git a/arm/Microsoft.ServiceFabric/clusters/deploy.bicep b/arm/Microsoft.ServiceFabric/clusters/deploy.bicep new file mode 100644 index 0000000000..e3f8499680 --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/deploy.bicep @@ -0,0 +1,313 @@ +@description('Required. Name of the Service Fabric cluster.') +param name string = '' + +@description('Optional. Location for all resources.') +param location string = resourceGroup().location + +@description('Optional. Tags of the resource.') +param tags object = {} + +@allowed([ + 'CanNotDelete' + 'NotSpecified' + 'ReadOnly' +]) +@description('Optional. Specify the type of lock.') +param lock string = 'NotSpecified' + +@description('Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered') +param cuaId string = '' + +@allowed([ + 'BackupRestoreService' + 'DnsService' + 'RepairManager' + 'ResourceMonitorService' +]) +@description('Optional. The list of add-on features to enable in the cluster.') +param addOnFeatures array = [] + +@description('Required. Number of unused versions per application type to keep.') +param maxUnusedVersionsToKeep int = 3 + +@description('Optional. The settings to enable AAD authentication on the cluster.') +param azureActiveDirectory object = {} + +@description('Optional. Describes the certificate details like thumbprint of the primary certificate, thumbprint of the secondary certificate and the local certificate store location') +param certificate object = {} + +@description('Optional. Describes a list of server certificates referenced by common name that are used to secure the cluster.') +param certificateCommonNames object = {} + +@description('Optional. The list of client certificates referenced by common name that are allowed to manage the cluster.') +param clientCertificateCommonNames array = [] + +@description('Optional. The list of client certificates referenced by thumbprint that are allowed to manage the cluster.') +param clientCertificateThumbprints array = [] + +@description('Optional. The Service Fabric runtime version of the cluster. This property can only by set the user when upgradeMode is set to "Manual". To get list of available Service Fabric versions for new clusters use ClusterVersion API. To get the list of available version for existing clusters use availableClusterVersions.') +param clusterCodeVersion string = '' + +@description('Optional. The storage account information for storing Service Fabric diagnostic logs.') +param diagnosticsStorageAccountConfig object = {} + +@description('Optional. Indicates if the event store service is enabled.') +param eventStoreServiceEnabled bool = false + +@description('Optional. The list of custom fabric settings to configure the cluster.') +param fabricSettings array = [] + +@description('Optional. Indicates if infrastructure service manager is enabled.') +param infrastructureServiceManager bool = false + +@description('Required. The http management endpoint of the cluster.') +param managementEndpoint string + +@description('Required. The list of node types in the cluster.') +param nodeTypes array = [] + +@description('Optional. Indicates a list of notification channels for cluster events.') +param notifications array = [] + +@allowed([ + 'Bronze' + 'Gold' + 'None' + 'Platinum' + 'Silver' +]) +@description('Optional. The reliability level sets the replica set size of system services. Learn about ReliabilityLevel (https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-capacity). - None - Run the System services with a target replica set count of 1. This should only be used for test clusters. - Bronze - Run the System services with a target replica set count of 3. This should only be used for test clusters. - Silver - Run the System services with a target replica set count of 5. - Gold - Run the System services with a target replica set count of 7. - Platinum - Run the System services with a target replica set count of 9.') +param reliabilityLevel string + +@description('Optional. Describes the certificate details.') +param reverseProxyCertificate object = {} + +@description('Optional. Describes a list of server certificates referenced by common name that are used to secure the cluster.') +param reverseProxyCertificateCommonNames object = {} + +@allowed([ + 'Hierarchical' + 'Parallel' +]) +@description('Optional. This property controls the logical grouping of VMs in upgrade domains (UDs). This property cannot be modified if a node type with multiple Availability Zones is already present in the cluster.') +param sfZonalUpgradeMode string = 'Hierarchical' + +@description('Optional. Describes the policy used when upgrading the cluster.') +param upgradeDescription object = {} + +@allowed([ + 'Automatic' + 'Manual' +]) +@description('Optional. The upgrade mode of the cluster when new Service Fabric runtime version is available.') +param upgradeMode string = 'Automatic' + +@description('Optional. Indicates the end date and time to pause automatic runtime version upgrades on the cluster for an specific period of time on the cluster (UTC).') +param upgradePauseEndTimestampUtc string = '' + +@description('Optional. Indicates the start date and time to pause automatic runtime version upgrades on the cluster for an specific period of time on the cluster (UTC).') +param upgradePauseStartTimestampUtc string = '' + +@allowed([ + 'Wave0' + 'Wave1' + 'Wave2' +]) +@description('Optional. Indicates when new cluster runtime version upgrades will be applied after they are released. By default is Wave0.') +param upgradeWave string = 'Wave0' + +@description('Optional. The VM image VMSS has been configured with. Generic names such as Windows or Linux can be used') +param vmImage string = '' + +@allowed([ + 'Hierarchical' + 'Parallel' +]) +@description('Optional. This property defines the upgrade mode for the virtual machine scale set, it is mandatory if a node type with multiple Availability Zones is added.') +param vmssZonalUpgradeMode string = 'Hierarchical' + +@description('Optional. Boolean to pause automatic runtime version upgrades to the cluster.') +param waveUpgradePaused bool = false + +@description('Optional. Array of role assignment objects that contain the \'roleDefinitionIdOrName\' and \'principalId\' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or it\'s fully qualified ID in the following format: \'/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11\'') +param roleAssignments array = [] + +@description('Optional. Array of Service Fabric cluster application types.') +param applicationTypes array = [] + +var clientCertificateCommonNames_var = [for clientCertificateCommonName in clientCertificateCommonNames: { + certificateCommonName: contains(clientCertificateCommonName, 'certificateCommonName') ? clientCertificateCommonName.certificateCommonName : null + certificateIssuerThumbprint: contains(clientCertificateCommonName, 'certificateIssuerThumbprint') ? clientCertificateCommonName.certificateIssuerThumbprint : null + isAdmin: contains(clientCertificateCommonName, 'isAdmin') ? clientCertificateCommonName.isAdmin : false +}] + +var clientCertificateThumbprints_var = [for clientCertificateThumbprint in clientCertificateThumbprints: { + certificateThumbprint: contains(clientCertificateThumbprint, 'certificateThumbprint') ? clientCertificateThumbprint.certificateThumbprint : null + isAdmin: contains(clientCertificateThumbprint, 'isAdmin') ? clientCertificateThumbprint.isAdmin : false +}] + +var fabricSettings_var = [for fabricSetting in fabricSettings: { + name: contains(fabricSetting, 'name') ? fabricSetting.name : null + parameters: contains(fabricSetting, 'parameters') ? fabricSetting.parameters : null +}] + +var nodeTypes_var = [for nodeType in nodeTypes: { + applicationPorts: contains(nodeType, 'applicationPorts') ? { + endPort: contains(nodeType.applicationPorts, 'endPort') ? nodeType.applicationPorts.endPort : null + startPort: contains(nodeType.applicationPorts, 'startPort') ? nodeType.applicationPorts.startPort : null + } : null + capacities: contains(nodeType, 'capacities') ? nodeType.capacities : null + clientConnectionEndpointPort: contains(nodeType, 'clientConnectionEndpointPort') ? nodeType.clientConnectionEndpointPort : null + durabilityLevel: contains(nodeType, 'durabilityLevel') ? nodeType.durabilityLevel : null + ephemeralPorts: contains(nodeType, 'ephemeralPorts') ? { + endPort: contains(nodeType.ephemeralPorts, 'endPort') ? nodeType.ephemeralPorts.endPort : null + startPort: contains(nodeType.ephemeralPorts, 'startPort') ? nodeType.ephemeralPorts.startPort : null + } : null + httpGatewayEndpointPort: contains(nodeType, 'httpGatewayEndpointPort') ? nodeType.httpGatewayEndpointPort : null + isPrimary: contains(nodeType, 'isPrimary') ? nodeType.isPrimary : null + isStateless: contains(nodeType, 'isStateless') ? nodeType.isStateless : null + multipleAvailabilityZones: contains(nodeType, 'multipleAvailabilityZones') ? nodeType.multipleAvailabilityZones : null + name: contains(nodeType, 'name') ? nodeType.name : 'Node00' + placementProperties: contains(nodeType, 'placementProperties') ? nodeType.placementProperties : null + reverseProxyEndpointPort: contains(nodeType, 'reverseProxyEndpointPort') ? nodeType.reverseProxyEndpointPort : null + vmInstanceCount: contains(nodeType, 'vmInstanceCount') ? nodeType.vmInstanceCount : 1 +}] + +var notifications_var = [for notification in notifications: { + isEnabled: contains(notification, 'isEnabled') ? notification.isEnabled : false + notificationCategory: contains(notification, 'notificationCategory') ? notification.notificationCategory : 'WaveProgress' + notificationLevel: contains(notification, 'notificationLevel') ? notification.notificationLevel : 'All' + notificationTargets: contains(notification, 'notificationTargets') ? notification.notificationTargets : [] +}] + +var upgradeDescription_var = union({ + deltaHealthPolicy: { + applicationDeltaHealthPolicies: contains(upgradeDescription, 'applicationDeltaHealthPolicies') ? upgradeDescription.applicationDeltaHealthPolicies : {} + maxPercentDeltaUnhealthyApplications: contains(upgradeDescription, 'maxPercentDeltaUnhealthyApplications') ? upgradeDescription.maxPercentDeltaUnhealthyApplications : 0 + maxPercentDeltaUnhealthyNodes: contains(upgradeDescription, 'maxPercentDeltaUnhealthyNodes') ? upgradeDescription.maxPercentDeltaUnhealthyNodes : 0 + maxPercentUpgradeDomainDeltaUnhealthyNodes: contains(upgradeDescription, 'maxPercentUpgradeDomainDeltaUnhealthyNodes') ? upgradeDescription.maxPercentUpgradeDomainDeltaUnhealthyNodes : 0 + } + forceRestart: contains(upgradeDescription, 'forceRestart') ? upgradeDescription.forceRestart : false + healthCheckRetryTimeout: contains(upgradeDescription, 'healthCheckRetryTimeout') ? upgradeDescription.healthCheckRetryTimeout : '00:45:00' + healthCheckStableDuration: contains(upgradeDescription, 'healthCheckStableDuration') ? upgradeDescription.healthCheckStableDuration : '00:01:00' + healthCheckWaitDuration: contains(upgradeDescription, 'healthCheckWaitDuration') ? upgradeDescription.healthCheckWaitDuration : '00:00:30' + upgradeDomainTimeout: contains(upgradeDescription, 'upgradeDomainTimeout') ? upgradeDescription.upgradeDomainTimeout : '02:00:00' + upgradeReplicaSetCheckTimeout: contains(upgradeDescription, 'upgradeReplicaSetCheckTimeout') ? upgradeDescription.upgradeReplicaSetCheckTimeout : '1.00:00:00' + upgradeTimeout: contains(upgradeDescription, 'upgradeTimeout') ? upgradeDescription.upgradeTimeout : '02:00:00' +}, contains(upgradeDescription, 'healthPolicy') ? { + healthPolicy: { + applicationHealthPolicies: contains(upgradeDescription.healthPolicy, 'applicationHealthPolicies') ? upgradeDescription.healthPolicy.applicationHealthPolicies : {} + maxPercentUnhealthyApplications: contains(upgradeDescription.healthPolicy, 'maxPercentUnhealthyApplications') ? upgradeDescription.healthPolicy.maxPercentUnhealthyApplications : 0 + maxPercentUnhealthyNodes: contains(upgradeDescription.healthPolicy, 'maxPercentUnhealthyNodes') ? upgradeDescription.healthPolicy.maxPercentUnhealthyNodes : 0 + } +} : {}) + +module pid_cuaId './.bicep/nested_cuaId.bicep' = if (!empty(cuaId)) { + name: 'pid-${cuaId}' + params: {} +} + +// Service Fabric cluster resource +resource serviceFabricCluster 'Microsoft.ServiceFabric/clusters@2021-06-01' = { + name: name + location: location + tags: tags + properties: { + addOnFeatures: addOnFeatures + applicationTypeVersionsCleanupPolicy: { + maxUnusedVersionsToKeep: maxUnusedVersionsToKeep + } + azureActiveDirectory: !empty(azureActiveDirectory) ? { + clientApplication: contains(azureActiveDirectory, 'clientApplication') ? azureActiveDirectory.clientApplication : null + clusterApplication: contains(azureActiveDirectory, 'clusterApplication') ? azureActiveDirectory.clusterApplication : null + tenantId: contains(azureActiveDirectory, 'tenantId') ? azureActiveDirectory.tenantId : null + } : null + certificate: !empty(certificate) ? { + thumbprint: contains(certificate, 'thumbprint') ? certificate.thumbprint : null + thumbprintSecondary: contains(certificate, 'thumbprintSecondary') ? certificate.thumbprintSecondary : null + x509StoreName: contains(certificate, 'x509StoreName') ? certificate.x509StoreName : null + } : null + certificateCommonNames: !empty(certificateCommonNames) ? { + commonNames: contains(certificateCommonNames, 'commonNames') ? certificateCommonNames.commonNames : null + x509StoreName: contains(certificateCommonNames, 'certificateCommonNamesx509StoreName') ? certificateCommonNames.certificateCommonNamesx509StoreName : null + } : null + clientCertificateCommonNames: !empty(clientCertificateCommonNames) ? clientCertificateCommonNames_var : null + clientCertificateThumbprints: !empty(clientCertificateThumbprints) ? clientCertificateThumbprints_var : null + clusterCodeVersion: !empty(clusterCodeVersion) ? clusterCodeVersion : null + diagnosticsStorageAccountConfig: !empty(diagnosticsStorageAccountConfig) ? { + blobEndpoint: contains(diagnosticsStorageAccountConfig, 'blobEndpoint') ? diagnosticsStorageAccountConfig.blobEndpoint : null + protectedAccountKeyName: contains(diagnosticsStorageAccountConfig, 'protectedAccountKeyName') ? diagnosticsStorageAccountConfig.protectedAccountKeyName : null + protectedAccountKeyName2: contains(diagnosticsStorageAccountConfig, 'protectedAccountKeyName2') ? diagnosticsStorageAccountConfig.protectedAccountKeyName2 : null + queueEndpoint: contains(diagnosticsStorageAccountConfig, 'queueEndpoint') ? diagnosticsStorageAccountConfig.queueEndpoint : null + storageAccountName: contains(diagnosticsStorageAccountConfig, 'storageAccountName') ? diagnosticsStorageAccountConfig.storageAccountName : null + tableEndpoint: contains(diagnosticsStorageAccountConfig, 'tableEndpoint') ? diagnosticsStorageAccountConfig.tableEndpoint : null + } : null + eventStoreServiceEnabled: eventStoreServiceEnabled + fabricSettings: !empty(fabricSettings) ? fabricSettings_var : null + infrastructureServiceManager: infrastructureServiceManager + managementEndpoint: managementEndpoint + nodeTypes: !empty(nodeTypes) ? nodeTypes_var : [] + notifications: !empty(notifications) ? notifications_var : null + reliabilityLevel: !empty(reliabilityLevel) ? reliabilityLevel : 'None' + reverseProxyCertificate: !empty(reverseProxyCertificate) ? { + thumbprint: contains(reverseProxyCertificate, 'thumbprint') ? reverseProxyCertificate.thumbprint : null + thumbprintSecondary: contains(reverseProxyCertificate, 'thumbprintSecondary') ? reverseProxyCertificate.thumbprintSecondary : null + x509StoreName: contains(reverseProxyCertificate, 'x509StoreName') ? reverseProxyCertificate.x509StoreName : null + } : null + reverseProxyCertificateCommonNames: !empty(reverseProxyCertificateCommonNames) ? { + commonNames: contains(reverseProxyCertificateCommonNames, 'commonNames') ? reverseProxyCertificateCommonNames.commonNames : null + x509StoreName: contains(reverseProxyCertificateCommonNames, 'x509StoreName') ? reverseProxyCertificateCommonNames.x509StoreName : null + } : null + sfZonalUpgradeMode: !empty(sfZonalUpgradeMode) ? sfZonalUpgradeMode : null + upgradeDescription: !empty(upgradeDescription) ? upgradeDescription_var : null + upgradeMode: !empty(upgradeMode) ? upgradeMode : null + upgradePauseEndTimestampUtc: !empty(upgradePauseEndTimestampUtc) ? upgradePauseEndTimestampUtc : null + upgradePauseStartTimestampUtc: !empty(upgradePauseStartTimestampUtc) ? upgradePauseStartTimestampUtc : null + upgradeWave: !empty(upgradeWave) ? upgradeWave : null + vmImage: !empty(vmImage) ? vmImage : null + vmssZonalUpgradeMode: !empty(vmssZonalUpgradeMode) ? vmssZonalUpgradeMode : null + waveUpgradePaused: waveUpgradePaused + } +} + +// Service Fabric cluster resource lock +resource serviceFabricCluster_lock 'Microsoft.Authorization/locks@2016-09-01' = if (lock != 'NotSpecified') { + name: '${serviceFabricCluster.name}-${lock}-lock' + properties: { + level: lock + notes: lock == 'CanNotDelete' ? 'Cannot delete resource or child resources.' : 'Cannot modify the resource or child resources.' + } + scope: serviceFabricCluster +} + +// Service Fabric cluster RBAC assignment +module serviceFabricCluster_rbac '.bicep/nested_rbac.bicep' = [for (roleAssignment, index) in roleAssignments: { + name: '${uniqueString(deployment().name, location)}-ServiceFabric-Rbac-${index}' + params: { + principalIds: roleAssignment.principalIds + roleDefinitionIdOrName: roleAssignment.roleDefinitionIdOrName + resourceId: serviceFabricCluster.id + } +}] + +// Service Fabric cluster application types +module serviceFabricCluster_applicationTypes 'applicationTypes/deploy.bicep' = [for applicationType in applicationTypes: { + name: '${uniqueString(deployment().name, location)}-SFC-${applicationType.name}' + params: { + name: applicationType.name + serviceFabricClusterName: serviceFabricCluster.name + tags: contains(applicationType, 'tags') ? applicationType.tags : {} + } +}] + +@description('The Service Fabric Cluster name.') +output name string = serviceFabricCluster.name + +@description('The Service Fabric Cluster resource group.') +output resourceGroupName string = resourceGroup().name + +@description('The Service Fabric Cluster resource ID.') +output resourceId string = serviceFabricCluster.id + +@description('The Service Fabric Cluster endpoint.') +output endpoint string = serviceFabricCluster.properties.clusterEndpoint diff --git a/arm/Microsoft.ServiceFabric/clusters/readme.md b/arm/Microsoft.ServiceFabric/clusters/readme.md new file mode 100644 index 0000000000..d9fd43170b --- /dev/null +++ b/arm/Microsoft.ServiceFabric/clusters/readme.md @@ -0,0 +1,128 @@ +# ServiceFabric Cluster `[Microsoft.ServiceFabric/clusters]` + +This module deploys a service fabric cluster. + +## Resource Types + +| Resource Type | API Version | +| :-- | :-- | +| `Microsoft.Authorization/locks` | 2016-09-01 | +| `Microsoft.Authorization/roleAssignments` | 2020-04-01-preview | +| `Microsoft.ServiceFabric/clusters` | 2021-06-01 | +| `Microsoft.ServiceFabric/clusters/applicationTypes` | 2021-06-01 | + +## Parameters + +| Parameter Name | Type | Default Value | Possible Values | Description | +| :-- | :-- | :-- | :-- | :-- | +| `addOnFeatures` | array | `[]` | `[BackupRestoreService, DnsService, RepairManager, ResourceMonitorService]` | Optional. The list of add-on features to enable in the cluster. | +| `applicationTypes` | _[applicationTypes](applicationTypes/readme.md)_ array | `[]` | | Optional. Array of Service Fabric cluster application types. | +| `azureActiveDirectory` | object | `{object}` | | Optional. The settings to enable AAD authentication on the cluster. | +| `certificate` | object | `{object}` | | Optional. Describes the certificate details like thumbprint of the primary certificate, thumbprint of the secondary certificate and the local certificate store location | +| `certificateCommonNames` | object | `{object}` | | Optional. Describes a list of server certificates referenced by common name that are used to secure the cluster. | +| `clientCertificateCommonNames` | array | `[]` | | Optional. The list of client certificates referenced by common name that are allowed to manage the cluster. | +| `clientCertificateThumbprints` | array | `[]` | | Optional. The list of client certificates referenced by thumbprint that are allowed to manage the cluster. | +| `clusterCodeVersion` | string | | | Optional. The Service Fabric runtime version of the cluster. This property can only by set the user when upgradeMode is set to "Manual". To get list of available Service Fabric versions for new clusters use ClusterVersion API. To get the list of available version for existing clusters use availableClusterVersions. | +| `cuaId` | string | | | Optional. Customer Usage Attribution ID (GUID). This GUID must be previously registered | +| `diagnosticsStorageAccountConfig` | object | `{object}` | | Optional. The storage account information for storing Service Fabric diagnostic logs. | +| `eventStoreServiceEnabled` | bool | | | Optional. Indicates if the event store service is enabled. | +| `fabricSettings` | array | `[]` | | Optional. The list of custom fabric settings to configure the cluster. | +| `infrastructureServiceManager` | bool | | | Optional. Indicates if infrastructure service manager is enabled. | +| `location` | string | `[resourceGroup().location]` | | Optional. Location for all resources. | +| `lock` | string | `NotSpecified` | `[CanNotDelete, NotSpecified, ReadOnly]` | Optional. Specify the type of lock. | +| `managementEndpoint` | string | | | Required. The http management endpoint of the cluster. | +| `maxUnusedVersionsToKeep` | int | `3` | | Required. Number of unused versions per application type to keep. | +| `name` | string | | | Required. Name of the Service Fabric cluster. | +| `nodeTypes` | array | `[]` | | Required. The list of node types in the cluster. | +| `notifications` | array | `[]` | | Optional. Indicates a list of notification channels for cluster events. | +| `reliabilityLevel` | string | | `[Bronze, Gold, None, Platinum, Silver]` | Optional. The reliability level sets the replica set size of system services. Learn about ReliabilityLevel (https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-cluster-capacity). - None - Run the System services with a target replica set count of 1. This should only be used for test clusters. - Bronze - Run the System services with a target replica set count of 3. This should only be used for test clusters. - Silver - Run the System services with a target replica set count of 5. - Gold - Run the System services with a target replica set count of 7. - Platinum - Run the System services with a target replica set count of 9. | +| `reverseProxyCertificate` | object | `{object}` | | Optional. Describes the certificate details. | +| `reverseProxyCertificateCommonNames` | object | `{object}` | | Optional. Describes a list of server certificates referenced by common name that are used to secure the cluster. | +| `roleAssignments` | array | `[]` | | Optional. Array of role assignment objects that contain the 'roleDefinitionIdOrName' and 'principalId' to define RBAC role assignments on this resource. In the roleDefinitionIdOrName attribute, you can provide either the display name of the role definition, or it's fully qualified ID in the following format: '/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11' | +| `sfZonalUpgradeMode` | string | `Hierarchical` | `[Hierarchical, Parallel]` | Optional. This property controls the logical grouping of VMs in upgrade domains (UDs). This property cannot be modified if a node type with multiple Availability Zones is already present in the cluster. | +| `tags` | object | `{object}` | | Optional. Tags of the resource. | +| `upgradeDescription` | object | `{object}` | | Optional. Describes the policy used when upgrading the cluster. | +| `upgradeMode` | string | `Automatic` | `[Automatic, Manual]` | Optional. The upgrade mode of the cluster when new Service Fabric runtime version is available. | +| `upgradePauseEndTimestampUtc` | string | | | Optional. Indicates the end date and time to pause automatic runtime version upgrades on the cluster for an specific period of time on the cluster (UTC). | +| `upgradePauseStartTimestampUtc` | string | | | Optional. Indicates the start date and time to pause automatic runtime version upgrades on the cluster for an specific period of time on the cluster (UTC). | +| `upgradeWave` | string | `Wave0` | `[Wave0, Wave1, Wave2]` | Optional. Indicates when new cluster runtime version upgrades will be applied after they are released. By default is Wave0. | +| `vmImage` | string | | | Optional. The VM image VMSS has been configured with. Generic names such as Windows or Linux can be used | +| `vmssZonalUpgradeMode` | string | `Hierarchical` | `[Hierarchical, Parallel]` | Optional. This property defines the upgrade mode for the virtual machine scale set, it is mandatory if a node type with multiple Availability Zones is added. | +| `waveUpgradePaused` | bool | | | Optional. Boolean to pause automatic runtime version upgrades to the cluster. | + +### Parameter Usage: `notifications` + +```json +"notifications": { + "value": [ + { + "isEnabled": true, // Required. Indicates if the notification is enabled. + "notificationCategory": "WaveProgress", // Required. The category of notification. Possible values include: "WaveProgress". + "notificationLevel": "Critical", // Required. The level of notification. Possible values include: "Critical", "All". + "notificationTargets": [ + { + "notificationChannel": "EmailUser", // Required. The notification channel indicates the type of receivers subscribed to the notification, either user or subscription. Possible values include: "EmailUser", "EmailSubscription". + "receivers": [ + "SomeReceiver" // Required. List of targets that subscribe to the notification. + ] + } + ] + } + ] +} +``` + +### Parameter Usage: `roleAssignments` + +```json +"roleAssignments": { + "value": [ + { + "roleDefinitionIdOrName": "Reader", + "principalIds": [ + "12345678-1234-1234-1234-123456789012", // object 1 + "78945612-1234-1234-1234-123456789012" // object 2 + ] + }, + { + "roleDefinitionIdOrName": "/providers/Microsoft.Authorization/roleDefinitions/c2f4ef07-c644-48eb-af81-4b1b4947fb11", + "principalIds": [ + "12345678-1234-1234-1234-123456789012" // object 1 + ] + } + ] +} +``` + +### Parameter Usage: `tags` + +Tag names and tag values can be provided as needed. A tag can be left without a value. + +```json +"tags": { + "value": { + "Environment": "Non-Prod", + "Contact": "test.user@testcompany.com", + "PurchaseOrder": "1234", + "CostCenter": "7890", + "ServiceName": "DeploymentValidation", + "Role": "DeploymentValidation" + } +} +``` + +## Outputs + +| Output Name | Type | Description | +| :-- | :-- | :-- | +| `endpoint` | string | The Service Fabric Cluster endpoint. | +| `name` | string | The Service Fabric Cluster name. | +| `resourceGroupName` | string | The Service Fabric Cluster resource group. | +| `resourceId` | string | The Service Fabric Cluster resource ID. | + +## Template references + +- [Clusters](https://docs.microsoft.com/en-us/azure/templates/Microsoft.ServiceFabric/2021-06-01/clusters) +- [Clusters/Applicationtypes](https://docs.microsoft.com/en-us/azure/templates/Microsoft.ServiceFabric/2021-06-01/clusters/applicationTypes) +- [Locks](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2016-09-01/locks) +- [Roleassignments](https://docs.microsoft.com/en-us/azure/templates/Microsoft.Authorization/2020-04-01-preview/roleAssignments)