Skip to content
This repository was archived by the owner on Feb 23, 2024. It is now read-only.

Commit 82f50e2

Browse files
authored
Merge pull request #160 from Azure/lucashh-creatorextractor-features
Lucashh creatorextractor features
2 parents 12d3503 + d0a86b9 commit 82f50e2

27 files changed

+534
-307
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,8 @@ API developers will fork the publisher repository to a developer repository and
4040
We realize there are two challenges for API developers when working with Resource Manager templates:
4141

4242
* First, API developers often work with [OpenAPI Specification](https://github.com/OAI/OpenAPI-Specification) and may not be familiar with Resource Manager schemas. Authoring templates manually might be an error-prone task. Therefore, we created a utility tool called [**Creator**](./src/APIM_ARMTemplate/README.md#Creator) to automate the creation of API templates based on an Open API Specification file. Optionally, developers can supply API Management policies for an API in XML format. Basically, the tool inserts the Open API specification and policies into a Resource Manager template in the proper format. With this tool, API developers can continue focusing on the formats and artifacts they are familiar with.
43-
* Second, for customers who have already been using API Management, another challenge is how to extract existing configurations into Resource Manager templates. For those customers, We have created another tool called [**Extrator**](./src/APIM_ARMTemplate/README.md#Extractor) to help them generate templates by extracting configurations from their exisitng API Management instances.
43+
44+
* Second, for customers who have already been using API Management, another challenge is how to extract existing configurations into Resource Manager templates. For those customers, We have created another tool called [**Extrator**](./src/APIM_ARMTemplate/README.md#extractor) to help them generate templates by extracting configurations from their exisitng API Management instances.
4445

4546
Once API developers have finished developing and testing an API, and have generated the API template, they can submit a pull request to merge the changes to the publisher repository. API publishers can validate the pull request and make sure the changes are safe and compliant. For example, they can check if only HTTPS is allowed to communicate with the API. Most of these validations can be automated as a step in the CI/CD pipeline. Once the changes are approved and merged successfully, API publishers can choose to deploy them to the Production instance either on schedule or on demand. The deployment of the templates can be automated using [Azure Pipeline](https://docs.microsoft.com/en-us/azure/devops/pipelines/?view=azure-devops), [PowerShell](https://docs.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-deploy), [Azure CLI](Azure-cli-example.md) or other tools.
4647

src/APIM_ARMTemplate/apimtemplate/Commands/Create.cs

Lines changed: 100 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
using System;
44
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Common;
55
using System.Collections.Generic;
6+
using System.Linq;
67

78
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create
89
{
910
public class CreateCommand : CommandLineApplication
1011
{
1112
public CreateCommand()
1213
{
13-
this.Name = Constants.CreateName;
14-
this.Description = Constants.CreateDescription;
14+
this.Name = GlobalConstants.CreateName;
15+
this.Description = GlobalConstants.CreateDescription;
1516

1617
// list command options
1718
CommandOption configFile = this.Option("--configFile <configFile>", "Config YAML file location", CommandOptionType.SingleValue).IsRequired();
@@ -31,48 +32,76 @@ public CreateCommand()
3132

3233
// initialize helper classes
3334
FileWriter fileWriter = new FileWriter();
35+
FileNameGenerator fileNameGenerator = new FileNameGenerator();
3436
TemplateCreator templateCreator = new TemplateCreator();
3537
APIVersionSetTemplateCreator apiVersionSetTemplateCreator = new APIVersionSetTemplateCreator(templateCreator);
38+
LoggerTemplateCreator loggerTemplateCreator = new LoggerTemplateCreator(templateCreator);
39+
ProductTemplateCreator productTemplateCreator = new ProductTemplateCreator(templateCreator);
3640
ProductAPITemplateCreator productAPITemplateCreator = new ProductAPITemplateCreator();
3741
PolicyTemplateCreator policyTemplateCreator = new PolicyTemplateCreator(fileReader);
3842
DiagnosticTemplateCreator diagnosticTemplateCreator = new DiagnosticTemplateCreator();
3943
APITemplateCreator apiTemplateCreator = new APITemplateCreator(fileReader, templateCreator, policyTemplateCreator, productAPITemplateCreator, diagnosticTemplateCreator);
4044
MasterTemplateCreator masterTemplateCreator = new MasterTemplateCreator(templateCreator);
45+
CreatorFileNames creatorFileNames = fileNameGenerator.GenerateCreatorLinkedFileNames(creatorConfig);
4146

4247
// create templates from provided configuration
43-
Template apiVersionSetTemplate = creatorConfig.apiVersionSet != null ? apiVersionSetTemplateCreator.CreateAPIVersionSetTemplate(creatorConfig) : null;
44-
Template initialAPITemplate = await apiTemplateCreator.CreateInitialAPITemplateAsync(creatorConfig);
45-
Template subsequentAPITemplate = apiTemplateCreator.CreateSubsequentAPITemplate(creatorConfig);
46-
CreatorFileNames creatorFileNames = fileWriter.GenerateCreatorLinkedFileNames(creatorConfig);
48+
Template apiVersionSetsTemplate = creatorConfig.apiVersionSets != null ? apiVersionSetTemplateCreator.CreateAPIVersionSetTemplate(creatorConfig) : null;
49+
Template productsTemplate = creatorConfig.products != null ? productTemplateCreator.CreateProductTemplate(creatorConfig) : null;
50+
Template loggersTemplate = creatorConfig.loggers != null ? loggerTemplateCreator.CreateLoggerTemplate(creatorConfig) : null;
51+
// store name and full template on each api necessary to build unlinked templates
52+
Dictionary<string, Template> initialAPITemplates = new Dictionary<string, Template>();
53+
Dictionary<string, Template> subsequentAPITemplates = new Dictionary<string, Template>();
54+
// store name and whether the api will depend on the version set template each api necessary to build linked templates
55+
List<LinkedMasterTemplateAPIInformation> apiInformation = new List<LinkedMasterTemplateAPIInformation>();
56+
// create parameters file
57+
Template masterTemplateParameters = masterTemplateCreator.CreateMasterTemplateParameterValues(creatorConfig);
4758

59+
foreach (APIConfig api in creatorConfig.apis)
60+
{
61+
Template initialAPITemplate = await apiTemplateCreator.CreateInitialAPITemplateAsync(creatorConfig, api);
62+
Template subsequentAPITemplate = apiTemplateCreator.CreateSubsequentAPITemplate(api);
63+
initialAPITemplates.Add(api.name, initialAPITemplate);
64+
subsequentAPITemplates.Add(api.name, subsequentAPITemplate);
65+
apiInformation.Add(new LinkedMasterTemplateAPIInformation()
66+
{
67+
name = api.name,
68+
dependsOnVersionSets = api.apiVersionSetId != null,
69+
dependsOnProducts = api.products != null,
70+
dependsOnLoggers = masterTemplateCreator.DetermineIfAPIDependsOnLogger(api, fileReader)
71+
});
72+
}
73+
74+
// write templates to outputLocation
4875
if (creatorConfig.linked == true)
4976
{
5077
// create linked master template
51-
Template masterTemplate = masterTemplateCreator.CreateLinkedMasterTemplate(apiVersionSetTemplate, initialAPITemplate, subsequentAPITemplate, creatorFileNames);
52-
Template masterTemplateParameters = masterTemplateCreator.CreateMasterTemplateParameterValues(creatorConfig);
53-
54-
// write templates to outputLocation
55-
if (apiVersionSetTemplate != null)
56-
{
57-
fileWriter.WriteJSONToFile(apiVersionSetTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.apiVersionSet));
58-
}
59-
fileWriter.WriteJSONToFile(initialAPITemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.initialAPI));
60-
fileWriter.WriteJSONToFile(subsequentAPITemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.subsequentAPI));
78+
Template masterTemplate = masterTemplateCreator.CreateLinkedMasterTemplate(apiVersionSetsTemplate, productsTemplate, loggersTemplate, apiInformation, creatorFileNames, fileNameGenerator);
6179
fileWriter.WriteJSONToFile(masterTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.linkedMaster));
62-
fileWriter.WriteJSONToFile(masterTemplateParameters, String.Concat(creatorConfig.outputLocation, creatorFileNames.masterParameters));
6380
}
64-
else
81+
foreach (KeyValuePair<string, Template> initialAPITemplatePair in initialAPITemplates)
6582
{
66-
// create unlinked master template
67-
Template initialMasterTemplate = masterTemplateCreator.CreateInitialUnlinkedMasterTemplate(apiVersionSetTemplate, initialAPITemplate);
68-
Template subsequentMasterTemplate = masterTemplateCreator.CreateSubsequentUnlinkedMasterTemplate(subsequentAPITemplate);
69-
Template masterTemplateParameters = masterTemplateCreator.CreateMasterTemplateParameterValues(creatorConfig);
70-
71-
// write templates to outputLocation
72-
fileWriter.WriteJSONToFile(initialMasterTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.unlinkedMasterOne));
73-
fileWriter.WriteJSONToFile(subsequentMasterTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.unlinkedMasterTwo));
74-
fileWriter.WriteJSONToFile(masterTemplateParameters, String.Concat(creatorConfig.outputLocation, creatorFileNames.masterParameters));
83+
string initialAPIFileName = fileNameGenerator.GenerateAPIFileName(initialAPITemplatePair.Key, true);
84+
fileWriter.WriteJSONToFile(initialAPITemplatePair.Value, String.Concat(creatorConfig.outputLocation, initialAPIFileName));
85+
}
86+
foreach (KeyValuePair<string, Template> subsequentAPITemplatePair in subsequentAPITemplates)
87+
{
88+
string subsequentAPIFileName = fileNameGenerator.GenerateAPIFileName(subsequentAPITemplatePair.Key, false);
89+
fileWriter.WriteJSONToFile(subsequentAPITemplatePair.Value, String.Concat(creatorConfig.outputLocation, subsequentAPIFileName));
90+
}
91+
if (apiVersionSetsTemplate != null)
92+
{
93+
fileWriter.WriteJSONToFile(apiVersionSetsTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.apiVersionSets));
94+
}
95+
if (productsTemplate != null)
96+
{
97+
fileWriter.WriteJSONToFile(productsTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.products));
98+
}
99+
if (loggersTemplate != null)
100+
{
101+
fileWriter.WriteJSONToFile(loggersTemplate, String.Concat(creatorConfig.outputLocation, creatorFileNames.loggers));
75102
}
103+
// write parameters to outputLocation
104+
fileWriter.WriteJSONToFile(masterTemplateParameters, String.Concat(creatorConfig.outputLocation, creatorConfig.linked == true ? creatorFileNames.linkedParameters : creatorFileNames.unlinkedParameters));
76105
ColoredConsole.WriteLine("Templates written to output location");
77106
}
78107
return 0;
@@ -98,56 +127,62 @@ public bool ValidateCreatorConfig(CreatorConfig creatorConfig)
98127
isValid = false;
99128
throw new CommandParsingException(this, "APIM service name is required");
100129
}
101-
if (creatorConfig.api == null)
102-
{
103-
isValid = false;
104-
throw new CommandParsingException(this, "API configuration is required");
105-
}
106-
if (creatorConfig.api.openApiSpec == null)
107-
{
108-
isValid = false;
109-
throw new CommandParsingException(this, "Open API Spec is required");
110-
}
111-
if (creatorConfig.api.suffix == null)
112-
{
113-
isValid = false;
114-
throw new CommandParsingException(this, "API suffix is required");
115-
}
116-
if (creatorConfig.api.name == null)
117-
{
118-
isValid = false;
119-
throw new CommandParsingException(this, "API name is required");
120-
}
121130
if (creatorConfig.linked == true && creatorConfig.linkedTemplatesBaseUrl == null)
122131
{
123132
isValid = false;
124133
throw new CommandParsingException(this, "LinkTemplatesBaseUrl is required for linked templates");
125134
}
126-
if (creatorConfig.apiVersionSet != null && creatorConfig.apiVersionSet.displayName == null)
135+
foreach (APIVersionSetConfig apiVersionSet in creatorConfig.apiVersionSets)
127136
{
128-
isValid = false;
129-
throw new CommandParsingException(this, "Display name is required if an API Version Set is provided");
130-
}
131-
if (creatorConfig.apiVersionSet != null && creatorConfig.apiVersionSet.versioningScheme == null)
132-
{
133-
isValid = false;
134-
throw new CommandParsingException(this, "Versioning scheme is required if an API Version Set is provided");
137+
if (apiVersionSet != null && apiVersionSet.displayName == null)
138+
{
139+
isValid = false;
140+
throw new CommandParsingException(this, "Display name is required if an API Version Set is provided");
141+
}
142+
if (apiVersionSet != null && apiVersionSet.versioningScheme == null)
143+
{
144+
isValid = false;
145+
throw new CommandParsingException(this, "Versioning scheme is required if an API Version Set is provided");
146+
}
135147
}
136-
if (creatorConfig.api.operations != null)
148+
foreach (APIConfig api in creatorConfig.apis)
137149
{
138-
foreach (KeyValuePair<string, OperationsConfig> operation in creatorConfig.api.operations)
150+
if (api == null)
139151
{
140-
if (operation.Value == null || operation.Value.policy == null)
152+
isValid = false;
153+
throw new CommandParsingException(this, "API configuration is required");
154+
}
155+
if (api.openApiSpec == null)
156+
{
157+
isValid = false;
158+
throw new CommandParsingException(this, "Open API Spec is required");
159+
}
160+
if (api.suffix == null)
161+
{
162+
isValid = false;
163+
throw new CommandParsingException(this, "API suffix is required");
164+
}
165+
if (api.name == null)
166+
{
167+
isValid = false;
168+
throw new CommandParsingException(this, "API name is required");
169+
}
170+
if (api.operations != null)
171+
{
172+
foreach (KeyValuePair<string, OperationsConfig> operation in api.operations)
141173
{
142-
isValid = false;
143-
throw new CommandParsingException(this, "Policy XML is required if an API operation is provided");
174+
if (operation.Value == null || operation.Value.policy == null)
175+
{
176+
isValid = false;
177+
throw new CommandParsingException(this, "Policy XML is required if an API operation is provided");
178+
}
144179
}
145180
}
146-
}
147-
if (creatorConfig.api.diagnostic != null && creatorConfig.api.diagnostic.loggerId == null)
148-
{
149-
isValid = false;
150-
throw new CommandParsingException(this, "LoggerId is required if an API diagnostic is provided");
181+
if (api.diagnostic != null && api.diagnostic.loggerId == null)
182+
{
183+
isValid = false;
184+
throw new CommandParsingException(this, "LoggerId is required if an API diagnostic is provided");
185+
}
151186
}
152187
return isValid;
153188
}

0 commit comments

Comments
 (0)