Skip to content

Commit f4c845c

Browse files
authored
Refactor - 2: Application create - part 1 (#46)
- Remove unnecessary methods in helpers pkg - Move some of the helper to respective dir - Use the newer methods in `application create` and refactor few things. - Will be continuing rest in subsequent PRs
1 parent 36b0851 commit f4c845c

File tree

10 files changed

+124
-193
lines changed

10 files changed

+124
-193
lines changed

ai-services/cmd/ai-services/cmd/application/create.go

Lines changed: 32 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,13 @@ import (
2020
"github.com/project-ai-services/ai-services/internal/pkg/cli/templates"
2121
"github.com/project-ai-services/ai-services/internal/pkg/constants"
2222
"github.com/project-ai-services/ai-services/internal/pkg/logger"
23+
"github.com/project-ai-services/ai-services/internal/pkg/models"
2324
"github.com/project-ai-services/ai-services/internal/pkg/runtime"
2425
"github.com/project-ai-services/ai-services/internal/pkg/runtime/podman"
26+
"github.com/project-ai-services/ai-services/internal/pkg/specs"
2527
"github.com/project-ai-services/ai-services/internal/pkg/spinner"
2628
"github.com/project-ai-services/ai-services/internal/pkg/utils"
29+
"github.com/project-ai-services/ai-services/internal/pkg/validators"
2730
"github.com/project-ai-services/ai-services/internal/pkg/vars"
2831
)
2932

@@ -105,31 +108,20 @@ var createCmd = &cobra.Command{
105108
}
106109
s.Stop("SMT level configured successfully")
107110

108-
// Fetch all the application Template names
109-
appTemplateNames, err := helpers.FetchApplicationTemplatesNames()
110-
if err != nil {
111-
return fmt.Errorf("failed to list templates: %w", err)
112-
}
113-
114-
var appTemplateName string
111+
tp := templates.NewEmbedTemplateProvider(templates.EmbedOptions{})
115112

116-
if index := fetchAppTemplateIndex(appTemplateNames, templateName); index == -1 {
117-
return errors.New("provided template name is wrong. Please provide a valid template name")
118-
} else {
119-
appTemplateName = appTemplateNames[index]
113+
// validate whether the provided template name is correct
114+
if err := validators.ValidateAppTemplateExist(tp, templateName); err != nil {
115+
return err
120116
}
121117

122-
applicationPodTemplatesPath := applicationPath + appTemplateName + "/templates"
123-
124-
tmpls, err := helpers.LoadAllTemplates(applicationPodTemplatesPath)
118+
tmpls, err := tp.LoadAllTemplates(templateName + "/templates")
125119
if err != nil {
126120
return fmt.Errorf("failed to parse the templates: %w", err)
127121
}
128122

129-
tp := templates.NewEmbedTemplateProvider(templates.EmbedOptions{})
130-
131123
// load metadata.yml to read the app metadata
132-
appMetadata, err := tp.LoadMetadata(appTemplateName)
124+
appMetadata, err := tp.LoadMetadata(templateName)
133125
if err != nil {
134126
return fmt.Errorf("failed to read the app metadata: %w", err)
135127
}
@@ -141,7 +133,7 @@ var createCmd = &cobra.Command{
141133
// ---- Validate Spyre card Requirements ----
142134

143135
// calculate the required spyre cards
144-
reqSpyreCardsCount, err := calculateReqSpyreCards(utils.ExtractMapKeys(tmpls), applicationPodTemplatesPath)
136+
reqSpyreCardsCount, err := calculateReqSpyreCards(tp, utils.ExtractMapKeys(tmpls), templateName)
145137
if err != nil {
146138
return err
147139
}
@@ -165,7 +157,7 @@ var createCmd = &cobra.Command{
165157
if !skipModelDownload {
166158
s = spinner.New("Downloading models as part of application creation...")
167159
s.Start(ctx)
168-
models, err := helpers.ListModels(appTemplateName)
160+
models, err := helpers.ListModels(templateName)
169161
if err != nil {
170162
s.Fail("failed to list models")
171163
return err
@@ -196,15 +188,15 @@ var createCmd = &cobra.Command{
196188
s = spinner.New("Deploying application '" + appName + "'...")
197189
s.Start(ctx)
198190
// execute the pod Templates
199-
if err := executePodTemplates(runtime, appName, appMetadata, tmpls, applicationPodTemplatesPath, pciAddresses); err != nil {
191+
if err := executePodTemplates(runtime, tp, appName, appMetadata, tmpls, pciAddresses); err != nil {
200192
return err
201193
}
202194
s.Stop("Application '" + appName + "' deployed successfully")
203195

204196
logger.Infoln("-------")
205197

206198
// print the next steps to be performed at the end of create
207-
if err := helpers.PrintNextSteps(runtime, appName, appTemplateName); err != nil {
199+
if err := helpers.PrintNextSteps(runtime, appName, templateName); err != nil {
208200
// do not want to fail the overall create if we cannot print next steps
209201
logger.Infof("failed to display next steps: %v\n", err)
210202
return nil
@@ -306,44 +298,22 @@ func setSMTLevel() error {
306298
}
307299

308300
func getTargetSMTLevel() (*int, error) {
309-
appTemplateNames, err := helpers.FetchApplicationTemplatesNames()
310-
if err != nil {
311-
return nil, fmt.Errorf("failed to list templates: %w", err)
312-
}
313-
314-
var appTemplateName string
301+
tp := templates.NewEmbedTemplateProvider(templates.EmbedOptions{})
315302

316-
if index := fetchAppTemplateIndex(appTemplateNames, templateName); index == -1 {
317-
return nil, errors.New("provided template name is wrong. Please provide a valid template name")
318-
} else {
319-
appTemplateName = appTemplateNames[index]
303+
// validate whether the provided template name is correct
304+
if err := validators.ValidateAppTemplateExist(tp, templateName); err != nil {
305+
return nil, err
320306
}
321307

322-
tp := templates.NewEmbedTemplateProvider(templates.EmbedOptions{})
323-
324308
// load metadata.yml to read the app metadata
325-
appMetadata, err := tp.LoadMetadata(appTemplateName)
309+
appMetadata, err := tp.LoadMetadata(templateName)
326310
if err != nil {
327311
return nil, fmt.Errorf("failed to read the app metadata: %w", err)
328312
}
329313

330314
return appMetadata.SMTLevel, nil
331315
}
332316

333-
// fetchAppTemplateIndex -> Returns the index of app template if exists, otherwise -1
334-
func fetchAppTemplateIndex(appTemplateNames []string, templateName string) int {
335-
appTemplateIndex := -1
336-
337-
for index, appTemplateName := range appTemplateNames {
338-
if strings.EqualFold(appTemplateName, templateName) {
339-
appTemplateIndex = index
340-
break
341-
}
342-
}
343-
344-
return appTemplateIndex
345-
}
346-
347317
func verifyPodTemplateExists(tmpls map[string]*template.Template, appMetadata *templates.AppMetadata) error {
348318
flattenPodTemplateExecutions := utils.FlattenArray(appMetadata.PodTemplateExecutions)
349319

@@ -361,8 +331,8 @@ func verifyPodTemplateExists(tmpls map[string]*template.Template, appMetadata *t
361331
return nil
362332
}
363333

364-
func executePodTemplates(runtime runtime.Runtime, appName string, appMetadata *templates.AppMetadata,
365-
tmpls map[string]*template.Template, podTemplatesPath string, pciAddresses []string) error {
334+
func executePodTemplates(runtime runtime.Runtime, tp templates.Template, appName string, appMetadata *templates.AppMetadata,
335+
tmpls map[string]*template.Template, pciAddresses []string) error {
366336

367337
globalParams := map[string]any{
368338
"AppName": appName,
@@ -390,10 +360,8 @@ func executePodTemplates(runtime runtime.Runtime, appName string, appMetadata *t
390360
// Shallow Copy globalParams Map
391361
params := utils.CopyMap(globalParams)
392362

393-
podTemplateFilePath := podTemplatesPath + "/" + podTemplateName
394-
395363
// fetch pod Spec
396-
podSpec, err := fetchPodSpec(podTemplateFilePath)
364+
podSpec, err := fetchPodSpec(tp, templateName, podTemplateName)
397365
if err != nil {
398366
errCh <- err
399367
}
@@ -496,18 +464,15 @@ func validateSpyreCardRequirements(req int, actual int) error {
496464
return nil
497465
}
498466

499-
func calculateReqSpyreCards(podTemplateFileNames []string, podTemplatesPath string) (int, error) {
467+
func calculateReqSpyreCards(tp templates.Template, podTemplateFileNames []string, appTemplateName string) (int, error) {
500468
totalReqSpyreCounts := 0
501469

502470
// Calculate Req Spyre Counts
503471
for _, podTemplateFileName := range podTemplateFileNames {
504-
505-
podTemplateFilePath := podTemplatesPath + "/" + podTemplateFileName
506-
507-
// load the pod Template
508-
podSpec, err := helpers.LoadPodTemplate(podTemplateFilePath)
472+
// fetch pod spec
473+
podSpec, err := fetchPodSpec(tp, appTemplateName, podTemplateFileName)
509474
if err != nil {
510-
return totalReqSpyreCounts, fmt.Errorf("failed to load pod Template: %s with error: %w", podTemplateFilePath, err)
475+
return totalReqSpyreCounts, fmt.Errorf("failed to load pod Template: '%s' for appTemplate: '%s' with error: %w", podTemplateFileName, appTemplateName, err)
511476
}
512477

513478
// fetch the spyreCount for all containers from the annotations
@@ -550,23 +515,23 @@ func fetchSpyreCardsFromPodAnnotations(annotations map[string]string) (int, map[
550515
return spyreCards, spyreCardContainerMap, nil
551516
}
552517

553-
func fetchPodSpec(podTemplateFilePath string) (*helpers.PodSpec, error) {
554-
podSpec, err := helpers.LoadPodTemplate(podTemplateFilePath)
518+
func fetchPodSpec(tp templates.Template, appTemplateName, podTemplateFileName string) (*models.PodSpec, error) {
519+
podSpec, err := tp.LoadPodTemplateWithDummyParams(appTemplateName, podTemplateFileName)
555520
if err != nil {
556-
return nil, fmt.Errorf("failed to load pod Template: %s with error: %w", podTemplateFilePath, err)
521+
return nil, fmt.Errorf("failed to load pod Template: '%s' for appTemplate: '%s' with error: %w", podTemplateFileName, appTemplateName, err)
557522
}
558523

559524
return podSpec, nil
560525
}
561526

562-
func fetchPodAnnotations(podSpec *helpers.PodSpec) map[string]string {
563-
return helpers.FetchPodAnnotations(*podSpec)
527+
func fetchPodAnnotations(podSpec *models.PodSpec) map[string]string {
528+
return specs.FetchPodAnnotations(*podSpec)
564529
}
565530

566-
func returnEnvParamsForPod(podSpec *helpers.PodSpec, podAnnotations map[string]string, pciAddresses *[]string) (map[string]map[string]string, error) {
531+
func returnEnvParamsForPod(podSpec *models.PodSpec, podAnnotations map[string]string, pciAddresses *[]string) (map[string]map[string]string, error) {
567532

568533
env := map[string]map[string]string{}
569-
podContainerNames := helpers.FetchContainerNames(*podSpec)
534+
podContainerNames := specs.FetchContainerNames(*podSpec)
570535

571536
// populate env with empty map
572537
for _, containerName := range podContainerNames {

ai-services/cmd/ai-services/cmd/application/templates.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import (
66

77
"github.com/spf13/cobra"
88

9-
"github.com/project-ai-services/ai-services/internal/pkg/cli/helpers"
9+
"github.com/project-ai-services/ai-services/internal/pkg/cli/templates"
1010
"github.com/project-ai-services/ai-services/internal/pkg/logger"
1111
)
1212

@@ -15,7 +15,9 @@ var templatesCmd = &cobra.Command{
1515
Short: "Lists the offered application templates",
1616
Long: `Retrieves information about the offered application templates`,
1717
RunE: func(cmd *cobra.Command, args []string) error {
18-
appTemplateNames, err := helpers.FetchApplicationTemplatesNames()
18+
tp := templates.NewEmbedTemplateProvider(templates.EmbedOptions{})
19+
20+
appTemplateNames, err := tp.ListApplications()
1921
if err != nil {
2022
return fmt.Errorf("failed to list application templates: %w", err)
2123
}

ai-services/internal/pkg/cli/helpers/helper.go

Lines changed: 0 additions & 100 deletions
Original file line numberDiff line numberDiff line change
@@ -2,79 +2,18 @@ package helpers
22

33
import (
44
"fmt"
5-
"io/fs"
65
"log"
76
"os"
87
"os/exec"
9-
"regexp"
10-
"slices"
118
"strings"
12-
"text/template"
139
"time"
1410

1511
"github.com/containers/podman/v5/libpod/define"
16-
v1 "github.com/containers/podman/v5/pkg/k8s.io/api/core/v1"
17-
"sigs.k8s.io/yaml"
1812

19-
"github.com/project-ai-services/ai-services/assets"
2013
"github.com/project-ai-services/ai-services/internal/pkg/logger"
2114
"github.com/project-ai-services/ai-services/internal/pkg/runtime"
2215
)
2316

24-
func FetchApplicationTemplatesNames() ([]string, error) {
25-
apps := []string{}
26-
27-
err := fs.WalkDir(assets.ApplicationFS, "applications", func(path string, d fs.DirEntry, err error) error {
28-
if err != nil {
29-
return err
30-
}
31-
if d.IsDir() {
32-
return nil
33-
}
34-
35-
// Templates Pattern :- "assets/applications/<AppName>/templates/*.yaml.tmpl"
36-
parts := strings.Split(path, "/")
37-
38-
if len(parts) >= 4 {
39-
appName := parts[1]
40-
if slices.Contains(apps, appName) {
41-
return nil
42-
}
43-
apps = append(apps, appName)
44-
}
45-
return nil
46-
})
47-
if err != nil {
48-
return nil, err
49-
}
50-
51-
return apps, nil
52-
}
53-
54-
// LoadAllTemplates -> Loads all templates under a specified root path
55-
func LoadAllTemplates(rootPath string) (map[string]*template.Template, error) {
56-
tmpls := make(map[string]*template.Template)
57-
58-
err := fs.WalkDir(assets.ApplicationFS, rootPath, func(path string, d fs.DirEntry, err error) error {
59-
if err != nil {
60-
return err
61-
}
62-
if d.IsDir() || !strings.HasSuffix(d.Name(), ".tmpl") {
63-
return nil
64-
}
65-
66-
t, err := template.ParseFS(assets.ApplicationFS, path)
67-
if err != nil {
68-
return fmt.Errorf("parse %s: %w", path, err)
69-
}
70-
71-
// key should be just the template file name (Eg:- pod1.yaml.tmpl)
72-
tmpls[strings.TrimPrefix(path, fmt.Sprintf("%s/", rootPath))] = t
73-
return nil
74-
})
75-
return tmpls, err
76-
}
77-
7817
type HealthStatus string
7918

8019
const (
@@ -186,45 +125,6 @@ func FindFreeSpyreCards() ([]string, error) {
186125
return free_spyre_dev_id_list, nil
187126
}
188127

189-
type PodSpec struct {
190-
v1.Pod
191-
}
192-
193-
func sanitizeTemplateForYaml(input []byte) []byte {
194-
re := regexp.MustCompile(`{{.*?}}`)
195-
return re.ReplaceAll(input, []byte("# template removed"))
196-
}
197-
198-
func LoadPodTemplate(path string) (*PodSpec, error) {
199-
data, err := assets.ApplicationFS.ReadFile(path)
200-
if err != nil {
201-
return nil, fmt.Errorf("read metadata: %w", err)
202-
}
203-
204-
// comment out template literals
205-
// Note: This will sanitize by removing the template literals
206-
// If we want to use with templating values, then apply templating and then read the file
207-
data = sanitizeTemplateForYaml(data)
208-
209-
var podSpec PodSpec
210-
if err := yaml.Unmarshal(data, &podSpec); err != nil {
211-
return nil, err
212-
}
213-
return &podSpec, nil
214-
}
215-
216-
func FetchPodAnnotations(podspec PodSpec) map[string]string {
217-
return podspec.Annotations
218-
}
219-
220-
func FetchContainerNames(podspec PodSpec) []string {
221-
var containerNames []string
222-
for _, v1Container := range podspec.Spec.Containers {
223-
containerNames = append(containerNames, v1Container.Name)
224-
}
225-
return containerNames
226-
}
227-
228128
func ParseSkipChecks(skipChecks []string) map[string]bool {
229129
skipMap := make(map[string]bool)
230130
for _, check := range skipChecks {

ai-services/internal/pkg/cli/helpers/images.go

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,13 @@ func ListImages(template string) ([]string, error) {
2323
return nil, fmt.Errorf("error loading templates for %s: %w", template, err)
2424
}
2525

26-
dummyParams := map[string]any{
27-
"AppName": "dummy-app",
28-
"AppTemplateName": "",
29-
"Version": "",
30-
}
31-
3226
images := []string{
3327
// include tool image as well which is used for all the housekeeping tasks
3428
vars.ToolImage,
3529
}
3630

3731
for _, tmpl := range tmpls {
38-
ps, err := tp.LoadPodTemplate(template, tmpl.Name(), dummyParams)
32+
ps, err := tp.LoadPodTemplateWithDummyParams(template, tmpl.Name())
3933
if err != nil {
4034
return nil, fmt.Errorf("error loading pod template: %w", err)
4135
}

0 commit comments

Comments
 (0)