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
4 changes: 4 additions & 0 deletions src/spring/azext_spring/migration/converter/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# --------------------------------------------------------------------------------------------
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See License.txt in the project root for license information.
# --------------------------------------------------------------------------------------------
24 changes: 24 additions & 0 deletions src/spring/azext_spring/migration/converter/app_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
from .base_converter import ConverterTemplate

# Concrete Converter Subclass for Container App
class AppConverter(ConverterTemplate):
def load_source(self, source):
self.source = []
for resource in source:
self.source.append(resource)

def calculate_data(self):
self.data.apps = []
for app in self.source:
self.data.apps.append({
"containerAppName": app["name"],
"containerImage": self.params["container_image"],
"targetPort": self.params["target_port"],
"cpuCore": app['properties']["cpu_core"],
"memorySize": app["memory_size"],
"minReplicas": app["min_replicas"],
"maxReplicas": app["max_replicas"],
})

def get_template_name(self):
return "app.bicep"
44 changes: 44 additions & 0 deletions src/spring/azext_spring/migration/converter/base_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import os

from abc import ABC, abstractmethod
from jinja2 import Template

# Abstract Base Class for Converter
# The converter is a template class that defines the structure of the conversion process
# The responsibility of the converter is to convert the input data into the output data
# The conversion process is divided into three steps:
# 1. Load the input data
# 2. Calculate the output data
# 3. Generate the output data
class ConverterTemplate(ABC):
def __init__(self):
self.params = {} # custom facing parameters for the converter
self.data = {} # output data of the converter
self.source = {} # input data of the converter

def set_params(self, params):
self.params = params

def convert(self, source):
self.load_source(source)
self.calculate_data()
return self.generate_output()

@abstractmethod
def load_source(self, source): # load the input data
pass

@abstractmethod
def calculate_data(self): # calculate the output data
pass

@abstractmethod
def get_template_name(self):
pass

def generate_output(self):
script_dir = os.path.dirname(os.path.abspath(__file__))
template_name = self.get_template_name()
with open(f"{script_dir}/templates/{template_name}.j2") as file:
template = Template(file.read())
return template.render(data=self.data, params=self.params)
67 changes: 67 additions & 0 deletions src/spring/azext_spring/migration/converter/conversion_context.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import os

from abc import ABC, abstractmethod
from jinja2 import Template
from .base_converter import ConverterTemplate
from .environment_converter import EnvironmentConverter
from .app_converter import AppConverter
from .revision_converter import RevisionConverter
from .readme_converter import ReadMeConverter
from .main_converter import MainConverter

# Context Class
class ConversionContext:
def __init__(self):
self.converters = []

def add_converter(self, converter: ConverterTemplate):
self.converters.append(converter)

def get_converter(self, converter_type: type):
for converter in self.converters:
if isinstance(converter, converter_type):
return converter
raise ValueError(f"Unknown converter type: {converter_type}")

def set_params_for_converter(self, converter_type, params):
for converter in self.converters:
if isinstance(converter, converter_type):
converter.set_params(params)

def run_converters(self, source):
converted_contents = []
source_wrapper = SourceDataWrapper(source)
# converted_contents.append(self.get_converter(MainConverter).convert(None))
converted_contents.append(
self.get_converter(EnvironmentConverter).convert(
source_wrapper.get_resources_by_type('Microsoft.AppPlatform/Spring')[0]
)
)
# converted_contents.append(
# self.get_converter(AppConverter).convert(
# source_wrapper.get_resources_by_type('Microsoft.AppPlatform/apps')
# )
# )
# converted_contents.append(
# self.get_converter(RevisionConverter).convert(
# source_wrapper.get_resources_by_type('Microsoft.AppPlatform/apps/deployments')
# )
# )
converted_contents.append(self.get_converter(ReadMeConverter).convert(None))
return converted_contents

def save_to_files(self, converted_contents, output_path):
print("Start to save the converted content to files ...")
os.makedirs(os.path.dirname(output_path), exist_ok=True)
for i, content in enumerate(converted_contents):
filename = f"{output_path}/export_script_{i+1}.bicep"
with open(filename, 'w', encoding='utf-8') as output_file:
print("Start to generate the {filename} file ...")
output_file.write(content)

class SourceDataWrapper:
def __init__(self, source):
self.source = source

def get_resources_by_type(self, resource_type):
return [resource for resource in self.source['resources'] if resource['type'] == resource_type]
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from .base_converter import ConverterTemplate

# Concrete Subclass for Container App Environment
class EnvironmentConverter(ConverterTemplate):
def load_source(self, source):
self.source = source

def calculate_data(self):
self.data = {
"containerAppEnvName": self.source['name'],
"location": self.source['location'],
"containerAppLogAnalyticsName": f"log-{self.source['name']}",
}

def get_template_name(self):
return "environment.bicep"
16 changes: 16 additions & 0 deletions src/spring/azext_spring/migration/converter/gateway_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from .base_converter import ConverterTemplate

# Concrete Converter Subclass for Gateway
class GatewayConverter(ConverterTemplate):
def __init__(self, client):
self.client = client

def load_source(self, source):
# Call the client to get additional data
pass

def calculate_data(self):
pass

def get_template_name(self):
return "gateway.bicep"
12 changes: 12 additions & 0 deletions src/spring/azext_spring/migration/converter/main_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .base_converter import ConverterTemplate

# Concrete Converter Subclass for Read Me
class MainConverter(ConverterTemplate):
def load_source(self, source):
pass

def calculate_data(self):
pass

def get_template_name(self):
return "main.bicep"
12 changes: 12 additions & 0 deletions src/spring/azext_spring/migration/converter/readme_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from .base_converter import ConverterTemplate

# Concrete Converter Subclass for Read Me
class ReadMeConverter(ConverterTemplate):
def load_source(self, source):
pass

def calculate_data(self):
pass

def get_template_name(self):
return "readme_template"
23 changes: 23 additions & 0 deletions src/spring/azext_spring/migration/converter/revision_converter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
from .base_converter import ConverterTemplate

# Concrete Converter Subclass for Revision
class RevisionConverter(ConverterTemplate):
def load_source(self, source):
self.source = []
for resource in source:
self.source.append(resource)

def calculate_data(self):
self.data.revisions = []
for revision in self.source:
self.data.revisions.append({
"name": revision["properties"]["name"],
"app": self.source.app_name,
"cpu_core": "0.5",
"memory_size": "1",
"min_replicas": 1,
"max_replicas": 5,
})

def get_template_name(self):
return "revision.bicep"
Original file line number Diff line number Diff line change
Expand Up @@ -52,23 +52,4 @@ resource containerApp 'Microsoft.App/containerApps@2024-03-01' = {
}
}

resource conainerAppRevision 'Microsoft.App/containerApp/revisions@2024-03-01' = [for revision in range(1, 2): {
name: '${containerAppName}-${revision}'
parent: containerApp
properties: {
template: {
containers: [
{
name: containerAppName
image: containerImage
resources: {
cpu: json(cpuCore)
memory: '${memorySize}Gi'
}
}
]
}
}
}]

output containerAppFQDN string = containerApp.properties.configuration.ingress.fqdn
Original file line number Diff line number Diff line change
@@ -1,26 +1,14 @@
// Env
param containerAppEnvName string
param containerAppLogAnalyticsName string
param location string
param apps array
param revisions object
param workloadProfileName string
param workloadProfileType string

// App
param containerAppName string
param containerImage string
param targetPort int
param cpuCore string
param memorySize string
param minReplicas int
param maxReplicas int

module containerAppEnv 'environment.bicep' = {
name: 'containerAppEnvDeployment'
params: {
containerAppEnvName: containerAppEnvName
containerAppLogAnalyticsName: containerAppLogAnalyticsName
location: location
workloadProfileName: workloadProfileName
workloadProfileType: workloadProfileType
Expand All @@ -31,13 +19,6 @@ module appModule 'app.bicep' = [for app in apps: {
name: '${app.name}'
dependsOn: [containerAppEnv]
params: {
containerAppName: containerAppName
containerImage: containerImage
targetPort: targetPort
cpuCore: cpuCore
memorySize: memorySize
minReplicas: minReplicas
maxReplicas: maxReplicas
containerAppEnvId: containerAppEnv.outputs.containerAppEnvId
}
}]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
param containerAppName string = {{containerAppName}}
param containerImage string = {{containerImage}}

param cpuCore string = {{cpuCore}}
param memorySize string = {{memorySize}}

param containerAppEnvId string

resource conainerAppRevision 'Microsoft.App/containerApp/revisions@2024-03-01' = [for revision in range(1, 2): {
name: '${containerAppName}-${revision}'
parent: containerApp
properties: {
template: {
containers: [
{
name: containerAppName
image: containerImage
resources: {
cpu: json(cpuCore)
memory: '${memorySize}Gi'
}
}
]
}
}
}]
Loading