Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 18 additions & 4 deletions src/spring/azext_spring/migration/converter/app_converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
class AppConverter(ConverterTemplate):
def load_source(self, source):
self.source = source
self.managed_components = source['managedComponents']
self.is_enterprise = source['isEnterprise']
# print(f"App source: {self.source}")

def calculate_data(self):
Expand Down Expand Up @@ -37,7 +39,7 @@ def get_app_name(input_string):
return input_string.split('/')[-1]

def _get_service_bind(self, source, envName):
enable_sba = source['enabled_sba']
enable_sba = self.managed_components['sba']
service_bind = []
addon = source['properties'].get('addonConfigs')

Expand All @@ -50,11 +52,23 @@ def _get_service_bind(self, source, envName):
"name": "bind-config",
"serviceId": f"resourceId('Microsoft.App/managedEnvironments/javaComponents', '{envName}', 'config')"
})
if self.is_enterprise != True and self.managed_components['config'] == True:
# standard tier enabled config server and bind all apps automatically
service_bind.append({
"name": "bind-config",
"serviceId": f"resourceId('Microsoft.App/managedEnvironments/javaComponents', '{envName}', 'config')"
})
if addon.get('serviceRegistry') is not None and addon['serviceRegistry'].get('resourceId') is not None:
service_bind.append({
"name": "bind-eureka",
"serviceId": f"resourceId('Microsoft.App/managedEnvironments/javaComponents', '{envName}', 'eureka')"
})
if self.is_enterprise != True and self.managed_components['eureka'] == True:
# standard tier enabled eureka server and bind all apps automatically
service_bind.append({
"name": "bind-eureka",
"serviceId": f"resourceId('Microsoft.App/managedEnvironments/javaComponents', '{envName}', 'eureka')"
})
if enable_sba:
service_bind.append({
"name": "bind-sba",
Expand Down Expand Up @@ -117,7 +131,7 @@ def _get_memory_by_cpu(self, cpu):

# create a method _convert_probe to convert the probe from the source to the target format
def _convert_probe(self, probe, tier):
print(f"probe: {probe}")
# print(f"probe: {probe}")
if probe is None:
return None
if probe.get("disableProbe") == True:
Expand Down Expand Up @@ -157,7 +171,7 @@ def _convert_tcp_probe_action(self, probe, tier):
}
else:
probeAction = None
print(f"probeAction: {probeAction}")
# print(f"probeAction: {probeAction}")
return probeAction

def _convert_http_probe_action(self, probe, tier):
Expand All @@ -170,6 +184,6 @@ def _convert_http_probe_action(self, probe, tier):
}
else:
probeAction = None
print(f"probeAction: {probeAction}")
# print(f"probeAction: {probeAction}")
return probeAction

51 changes: 34 additions & 17 deletions src/spring/azext_spring/migration/converter/conversion_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,24 @@ def run_converters(self, source):
source_wrapper = SourceDataWrapper(source)
asa_service = source_wrapper.get_resources_by_type('Microsoft.AppPlatform/Spring')[0]

converted_contents[self.get_converter(EnvironmentConverter).get_template_name()] = self.get_converter(EnvironmentConverter).convert(
asa_service
)
# Environment Converter
is_vnet = self._is_vnet(asa_service)
is_enterprise = self._is_enterprise_tier(asa_service)
asa_service['isVnet'] = is_vnet
converted_contents[self.get_converter(EnvironmentConverter).get_template_name()] = self.get_converter(EnvironmentConverter).convert(asa_service)

# Cert Converter
asa_certs = source_wrapper.get_resources_by_type('Microsoft.AppPlatform/Spring/certificates')
asa_kv_certs = []

for cert in asa_certs:
certName = cert['name'].split('/')[-1]
if cert['properties'].get('type') == "KeyVaultCertificate":
asa_kv_certs.append(cert)
converted_contents[certName+"_"+self.get_converter(CertConverter).get_template_name()] = self.get_converter(CertConverter).convert(cert)
elif cert['properties'].get('type') == "ContentCertificate":
converted_contents[certName+"_"+self.get_converter(CertConverter).get_template_name()] = self.get_converter(CertConverter).convert(cert)

# Managed components Converter
managed_components = {
'gateway': False,
'config': False,
Expand All @@ -65,26 +71,31 @@ def run_converters(self, source):
converted_contents = self._convert_live_view(source_wrapper, converted_contents, managed_components)
converted_contents = self._convert_eureka_and_service_registry(source_wrapper, converted_contents, asa_service, managed_components)

# Apps Converter
asa_apps = source_wrapper.get_resources_by_type('Microsoft.AppPlatform/Spring/apps')
asa_deployments = source_wrapper.get_resources_by_type('Microsoft.AppPlatform/Spring/apps/deployments')
# print(asa_deployments)

for app in asa_apps:
appName = app['name'].split('/')[-1]
app['enabled_sba'] = managed_components['sba']
app['deployments'] = [deployment for deployment in asa_deployments if deployment['name'].startswith(f"{app['name']}/")]
converted_contents[appName+"_"+self.get_converter(AppConverter).get_template_name()] = self.get_converter(AppConverter).convert(app)
for app_source in asa_apps:
appName = app_source['name'].split('/')[-1]
app_source['deployments'] = [deployment for deployment in asa_deployments if deployment['name'].startswith(f"{app_source['name']}/")]
app_source['managedComponents'] = managed_components
app_source['isEnterprise'] = is_enterprise
converted_contents[appName+"_"+self.get_converter(AppConverter).get_template_name()] = self.get_converter(AppConverter).convert(app_source)

main_source = {
# Param, readme and main Converter
full_source = {
"asa": asa_service,
"apps": asa_apps,
"certs": asa_kv_certs,
"managedComponents": managed_components,
"isVnet": is_vnet,
"inEnterprise": is_enterprise,
}
converted_contents[self.get_converter(ParamConverter).get_template_name()] = self.get_converter(ParamConverter).convert(asa_apps)
converted_contents[self.get_converter(ReadMeConverter).get_template_name()] = self.get_converter(ReadMeConverter).convert(None)
converted_contents[self.get_converter(MainConverter).get_template_name()] = self.get_converter(MainConverter).convert(
main_source
)

converted_contents[self.get_converter(ParamConverter).get_template_name()] = self.get_converter(ParamConverter).convert(full_source)
converted_contents[self.get_converter(ReadMeConverter).get_template_name()] = self.get_converter(ReadMeConverter).convert(full_source)
converted_contents[self.get_converter(MainConverter).get_template_name()] = self.get_converter(MainConverter).convert(full_source)

return converted_contents

def save_to_files(self, converted_contents, output_path):
Expand Down Expand Up @@ -151,12 +162,18 @@ def _convert_eureka_and_service_registry(self, source_wrapper, converted_content
if not is_enterprise_tier:
managed_components['eureka'] = True
eureka_key = self.get_converter(EurekaConverter).get_template_name()
converted_contents[eureka_key] = self.get_converter(EurekaConverter).convert()
converted_contents[eureka_key] = self.get_converter(EurekaConverter).convert(None)
return converted_contents

def _is_enterprise_tier(self, asa_service):
return asa_service['sku']['tier'] == 'Enterprise'

def _is_vnet(self, asa_service):
networkProfile = asa_service['properties'].get('networkProfile')
if networkProfile is None:
return False
return networkProfile.get('appSubnetId') is not None

class SourceDataWrapper:
def __init__(self, source):
self.source = source
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ def calculate_data(self):
"containerAppLogAnalyticsName": f"log-{name}",
}

isVnet = self.source['isVnet']
if isVnet:
self.data["vnetConfiguration"] = {
"internal": str(True).lower(),
}

asa_zone_redundant = self.source['properties'].get('zoneRedundant')
if asa_zone_redundant is not None:
self.data["zoneRedundant"] = str(asa_zone_redundant).lower()
Expand All @@ -25,7 +31,6 @@ def calculate_data(self):
}]
self.data["scheduledEntries"] = aca_maintenance_window

asa_certs = self.source['properties'].get('certificates')

def get_template_name(self):
return "environment.bicep"
return "environment.bicep"
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ class EurekaConverter(ConverterTemplate):
def __init__(self):
super().__init__()

def load_source(self):
pass
def load_source(self, source):
self.source = source

def calculate_data(self):
name = "eureka"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ def load_source(self, source):
self.certs = source["certs"]

def calculate_data(self):
self.data["isVnet"] = self.source.get("isVnet", False)
self.data.setdefault("certs", [])
for item in self.certs:
certName = item['name'].split('/')[-1]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
# Concrete Converter Subclass for paramter
class ParamConverter(ConverterTemplate):
def load_source(self, source):
self.apps = source
self.apps = source['apps']
self.is_vnet = source['isVnet']

def calculate_data(self):
self.data.setdefault("apps", [])
Expand All @@ -13,6 +14,7 @@ def calculate_data(self):
"appName": appName,
"containerAppImageName": "containerImageFor_"+appName.replace("-", "_"),
})
self.data["isVnet"] = self.is_vnet

def get_template_name(self):
return "param.bicepparam"
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Params
param workloadProfileName string
param workloadProfileType string
param workloadProfileName = 'Dedicated'
param workloadProfileType = 'D4'
param minNodes = 1
param maxNodes = 10

param managedEnvName string = '{{data.containerAppEnvName}}'
param containerAppLogAnalyticsName string = '{{data.containerAppLogAnalyticsName}}'
param zoneRedundant bool = {{data.zoneRedundant}}
param vnetSubnetId string = ''

resource logAnalytics 'Microsoft.OperationalInsights/workspaces@2022-10-01' = {
name: containerAppLogAnalyticsName
name: '{{data.containerAppLogAnalyticsName}}'
location: resourceGroup().location
properties: {
sku: {
Expand All @@ -31,24 +31,30 @@ resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-pr
}

resource containerAppEnv 'Microsoft.App/managedEnvironments@2024-10-02-preview' = {
name: managedEnvName
name: '{{data.containerAppEnvName}}'
location: resourceGroup().location
{% if data.identity %}
identity: {
type: 'SystemAssigned'
}
{% endif %}
properties: {
// vnetConfiguration: {}
{% if data.vnetConfiguration %}
vnetConfiguration: {
internal: {{ data.vnetConfiguration.internal }}
infrastructureSubnetId: vnetSubnetId
}
{% endif %}
appLogsConfiguration: {
destination: 'azure-monitor'
}
zoneRedundant: zoneRedundant
// customDomainConfiguration: {}
zoneRedundant: {{data.zoneRedundant}}
workloadProfiles: [
{
name: workloadProfileName
workloadProfileType: workloadProfileType
// minimumCount: minNodes
// maximumCount: maxNodes
minimumCount: minNodes
maximumCount: maxNodes
}
]
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
// Params
param workloadProfileName string
param workloadProfileType string
{% if data.isVnet == true %}
param vnetSubnetId string
{% endif %}
{% for app in data.apps %}
param {{app.containerAppImageName}} string
{% endfor %}

module containerAppEnv 'environment.bicep' = {
name: 'containerAppEnvDeployment'
params: {
workloadProfileName: workloadProfileName
workloadProfileType: workloadProfileType
{% if data.isVnet == true %}
vnetSubnetId: vnetSubnetId
{% endif %}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
using './main.bicep'

param workloadProfileName = 'Consumption'
param workloadProfileType = 'Consumption'

{% for app in data.apps %}
param {{app.containerAppImageName}} = 'mcr.microsoft.com/azuredocs/containerapps-helloworld:latest'
{% endfor %}
{% endfor %}
{% if data.isVnet == true %}
// Replace this wth the actual vnet subnet id
param vnetSubnetId = '/subscriptions/00000000-0000-0000-0000-000000000000/resourceGroups/rg/providers/Microsoft.Network/virtualNetworks/vnet/subnets/subnet'
{% endif %}