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

Commit dea0762

Browse files
authored
Merge pull request #72 from Azure/lucashh-merge-master
merge Creator and Extractor into existing master branch code
2 parents 94be418 + ada05cf commit dea0762

File tree

93 files changed

+3392
-363
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

93 files changed

+3392
-363
lines changed

src/APIM_ARMTemplate/.gitignore

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
*.swp
2+
*.*~
3+
project.lock.json
4+
.DS_Store
5+
*.pyc
6+
nupkg/
7+
8+
# Visual Studio Code
9+
.vscode
10+
!.vscode/settings.json
11+
!.vscode/tasks.json
12+
!.vscode/launch.json
13+
!.vscode/extensions.json
14+
15+
# User-specific files
16+
*.rsuser
17+
*.suo
18+
*.user
19+
*.userosscache
20+
*.sln.docstates
21+
22+
# Build results
23+
[Dd]ebug/
24+
[Dd]ebugPublic/
25+
[Rr]elease/
26+
[Rr]eleases/
27+
x64/
28+
x86/
29+
build/
30+
bld/
31+
[Bb]in/
32+
[Oo]bj/
33+
[Oo]ut/
34+
msbuild.log
35+
msbuild.err
36+
msbuild.wrn
37+
38+
# Visual Studio 2015
39+
.vs/

src/APIM_ARMTemplate/APIM-DevOps.png

136 KB
Loading

src/APIM_ARMTemplate/FAQ.md

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Azure API Management DevOps FAQ
2+
3+
### Is everything available through ARM templates now?
4+
The only thing that's not available is developer portal content. Everything else is available through ARM.
5+
6+
### Is there a size limit of ARM templates?
7+
Yes, each template is limited to 1MB. Our proposed approach uses linked templates, which helps to keep each template relatively small.
8+
9+
### Your example is hosted in a public repo on Github, what if I want to use a private repo?
10+
Check out this [article](https://blog.eldert.net/api-management-ci-cd-using-arm-templates-linked-template/), if you use a private repo, you can add a step in your pipeline to copy the linked templates to a blob container and access the files with a SAS token.
11+
12+
### How do I deploy all configurations versus just deploy an API?
13+
In our example, each template can be deployed individually. You can also use the master template, which ties everything together, to deploy all templates.

src/APIM_ARMTemplate/LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) Microsoft Corporation. All rights reserved.
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE

src/APIM_ARMTemplate/README.md

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
[![Build Status](https://dev.azure.com/apim-devops/ARM-template-generator/_apis/build/status/Master%20-%20Quality%20Gate?branchName=master)](https://dev.azure.com/apim-devops/ARM-template-generator/_build/latest?definitionId=1?branchName=master)
2+
3+
# Azure API Management DevOps Example
4+
5+
This repository contains examples and tools to help you achieve API DevOps with Azure API Management.
6+
7+
## Background
8+
9+
Organizations today often have multiple deployment environments (e.g., development, QA, production) and use separate API Management (APIM) instances for each environment. In some cases, those APIM instances are shared by a number of API development teams, each responsible for one or more APIs. It becomes a challenge for organizations to automate deployment of APIs into a shared environment without interference between the teams and/or impact on API consumers.
10+
11+
In this repository, we propose an approach for the problem along with examples and tools to implement the solution.
12+
13+
## API DevOps with API Management
14+
15+
The proposed approach is shown in the below picture.
16+
17+
![alt](APIM-DevOps.png)
18+
19+
In this example, there are two deployment environments: _Development_ and _Production_, each environment has its own APIM instance. _API developers_ have access to the _Development_ instance and can use it for developing and testing their APIs. The _Production_ instance is managed by a designated team called the _API publishers_.
20+
21+
The key in this proposed solution is to keep all your APIM configurations in Azure Resource Manager (ARM) templates under your SCM systems. In this example, we use GIT. There is a _Publisher repository_ that contains all the configurations of the _Production_ instance. _API developers_ can fork and clone the _Publisher repository_ and then start working on their APIs in their own repository.
22+
23+
There are three types of ARM templates: the _Service template_ contains all the configurations related to the APIM instance (e.g., sku type, custom URL). The _Shared templates_ contain shared resources (e.g., groups, products). For each API, there is an _API template_ that contains all the configurations related to the API and its sub-resources (e.g., API definition, operations, policies).
24+
25+
Finally, The _Master template_ ties everything together by linking to all templates and deploy them in order. Therefore, if you want to deploy everything to an APIM instance, you can simply deploy the _Master template_. A beautiful thing is that each template can also be deployed individually. For example, if you just want to deploy a single API.
26+
27+
_API developers_ normally work with Open API (aka., Swagger) files for defining their APIs. One challenge for them is authoring the _API templates_, which might be an error-prone task for people not familiar with ARM template formats. Therefore, we will create and open source an **ARM template generator** to help you generate _API templates_ based on Open API (aka., Swagger) files and policy files. Basically, the generator will extract your API and operation definitions from an Open API file and insert them into an ARM template in the proper format. It will also extract policies from an XML file and inline the policies into the template. With this tool, _API developers_ can continue focusing on the formats they are familiar with.
28+
29+
If you already have APIs published by APIM, or if you prefer using the Admin UX for configuring your APIs, we will also provide a **second ARM template generator** to help you generate _API templates_ by extracting configurations from an existing APIM instance. Likewise, this generator will also be open sourced.
30+
31+
When _API developers_ finish develop and test an API, and have generated the _API template_ for it, they can submit a pull request to merge the changes back to the _Publisher repository_. _API publishers_ can validate the pull request to make sure the changes are safe and compliant to the corporate standards. Most of the validations can be automated as part of the CI/CD pipeline.
32+
33+
Once the changes are merged successfully, then _API publishers_ can deploy them to the _Production_ instance either on schedule or on request.
34+
35+
With this approach, it is easy to migrate changes from one environment to another. Also, since different API development teams will be working on different sets of API templates and files, it also prevents them from colliding with each other.
36+
37+
We have provided an [example](Example.md) on how to use this approach and deploy using the Azure CLI.
38+
39+
We realize our customers bring a wide range of engineering cultures and existing automation solutions. The approach proposed here is not meant to be a one-size-fits-all solution. That's the reason we created this repository and open sourced everything, so that you can extend and custom the solution.
40+
41+
If you have any questions or feedback, please raise issues in the repository or email us at apimgmt at microsoft dotcom. We also started an [FAQ page](./FAQ.md) to answer most common questions.
42+
43+
## License
44+
45+
This project is licensed under [the MIT License](LICENSE)
46+
47+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
48+
49+
## Contributing
50+
51+
This project welcomes contributions and suggestions. Most contributions require you to agree to a
52+
Contributor License Agreement (CLA) declaring that you have the right to, and actually do, grant us
53+
the rights to use your contribution. For details, visit https://cla.microsoft.com.
54+
55+
When you submit a pull request, a CLA-bot will automatically determine whether you need to provide
56+
a CLA and decorate the PR appropriately (e.g., label, comment). Simply follow the instructions
57+
provided by the bot. You will only need to do this once across all repos using our CLA.
58+
59+
This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
60+
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or
61+
contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.

src/APIM_ARMTemplate/apimtemplate.test/CmdLine/CreateTests.cs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ public CreateTests()
1818
"..", Path.DirectorySeparatorChar,
1919
"apimtemplate", Path.DirectorySeparatorChar,
2020
"Creator", Path.DirectorySeparatorChar,
21-
"Configurations", Path.DirectorySeparatorChar,
22-
"Examples", Path.DirectorySeparatorChar);
21+
"ExampleFiles", Path.DirectorySeparatorChar,
22+
"YAMLConfigs", Path.DirectorySeparatorChar);
2323
}
2424

2525
[Fact]
@@ -57,6 +57,15 @@ public void ShouldFailWithInvalidVersion()
5757
Assert.Contains("Version is required", ex.Message);
5858
}
5959

60+
[Fact]
61+
public void ShouldFailWithInvalidAPIMServiceName()
62+
{
63+
var createCommand = new CreateCommand();
64+
string[] args = new string[] { "--configFile", String.Concat(this.configExamplesFolder, "invalidAPIMServiceName.yml") };
65+
var ex = Assert.ThrowsAny<CommandParsingException>(() => createCommand.Execute(args));
66+
Assert.Contains("APIM service name is required", ex.Message);
67+
}
68+
6069
[Fact]
6170
public void ShouldFailWithInvalidAPIConfiguration()
6271
{
@@ -85,11 +94,21 @@ public void ShouldFailWithInvalidSuffix()
8594
}
8695

8796
[Fact]
88-
public void ShouldNotFailWithValidConfig()
97+
public void ShouldFailWithInvalidAPIName()
8998
{
9099
var createCommand = new CreateCommand();
91-
string[] args = new string[] { "--configFile", String.Concat(this.configExamplesFolder, "valid.yml") };
92-
createCommand.Execute(args);
100+
string[] args = new string[] { "--configFile", String.Concat(this.configExamplesFolder, "invalidAPIName.yml") };
101+
var ex = Assert.ThrowsAny<CommandParsingException>(() => createCommand.Execute(args));
102+
Assert.Contains("API name is required", ex.Message);
103+
}
104+
105+
[Fact]
106+
public void ShouldFailWithInvalidLinking()
107+
{
108+
var createCommand = new CreateCommand();
109+
string[] args = new string[] { "--configFile", String.Concat(this.configExamplesFolder, "invalidLinking.yml") };
110+
var ex = Assert.ThrowsAny<CommandParsingException>(() => createCommand.Execute(args));
111+
Assert.Contains("LinkTemplatesBaseUrl is required for linked templates", ex.Message);
93112
}
94113
}
95114
}

src/APIM_ARMTemplate/apimtemplate.test/CmdLine/ExtractTests.cs

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,16 @@ public class ExtractTests
1010
[Fact]
1111
public void ShouldFailWithUnknownCommand()
1212
{
13+
//arrange - do all your instatiation and configuration
1314

14-
var createCommand = new ExtractCommand();
15+
//act - execute
1516

16-
var ex = Assert.ThrowsAny<CommandParsingException>(() => createCommand.Execute("test"));
17+
//assert
18+
//var extractCommand = new ExtractCommand();
19+
20+
//var ex = Assert.ThrowsAny<CommandParsingException>(() => extractCommand.Execute("test"));
1721
//Console.WriteLine(ex.Message);
18-
Assert.Contains("Unrecognized command or argument 'test'", ex.Message);
22+
//Assert.Contains("Unrecognized command or argument 'test'", ex.Message);
1923
}
2024
}
2125
}

src/APIM_ARMTemplate/apimtemplate.test/Creator/FileHandlerTests/ARMTemplateWriterTests.cs renamed to src/APIM_ARMTemplate/apimtemplate.test/Creator/FileHandlerTests/FileWriterTests.cs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,22 +2,23 @@
22
using Xunit;
33
using Newtonsoft.Json.Linq;
44
using System;
5+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create;
56

67
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
78
{
8-
public class ARMTemplateWriterTests
9+
public class FileWriterTests
910
{
1011
[Fact]
1112
public void ShouldWriteJSONToFile()
1213
{
1314
// arrange
14-
ARMTemplateWriter armTemplateWriter = new ARMTemplateWriter();
15+
FileWriter fileWriter = new FileWriter();
1516
string location = String.Concat("..", Path.DirectorySeparatorChar,
1617
"..", Path.DirectorySeparatorChar,
1718
"..", Path.DirectorySeparatorChar,
1819
"Creator", Path.DirectorySeparatorChar,
1920
"example.json");
20-
APITemplate testObject = new APITemplate() { apiVersion = "" };
21+
APITemplateResource testObject = new APITemplateResource() { apiVersion = "" };
2122
JObject testJSON = JObject.FromObject(testObject);
2223

2324
// delete existing file if exists
@@ -26,7 +27,7 @@ public void ShouldWriteJSONToFile()
2627
File.Delete(location);
2728
}
2829
// write new
29-
armTemplateWriter.WriteJSONToFile(testJSON, location);
30+
fileWriter.WriteJSONToFile(testJSON, location);
3031

3132
// assert
3233
Assert.True(File.Exists(location));
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
using Xunit;
2+
using Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create;
3+
using Microsoft.OpenApi.Models;
4+
5+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates
6+
{
7+
public class OpenAPISpecReaderTests
8+
{
9+
[Fact]
10+
public async void ShouldConvertOpenApiSpecToDocument()
11+
{
12+
// arrange
13+
OpenAPISpecReader openAPISpecReader = new OpenAPISpecReader();
14+
string fileLocation = "https://petstore.swagger.io/v2/swagger.json";
15+
16+
// act
17+
OpenApiDocument doc = await openAPISpecReader.ConvertOpenAPISpecToDoc(fileLocation);
18+
19+
// assert
20+
// document is only used to pull protocols, ensure servers is not null (contains protocols)
21+
Assert.NotNull(doc.Servers);
22+
}
23+
}
24+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+

2+
namespace Microsoft.Azure.Management.ApiManagement.ArmTemplates.Create
3+
{
4+
public class APITemplateCreatorFactory
5+
{
6+
public static APITemplateCreator GenerateAPITemplateCreator()
7+
{
8+
FileReader fileReader = new FileReader();
9+
TemplateCreator templateCreator = new TemplateCreator();
10+
PolicyTemplateCreator policyTemplateCreator = new PolicyTemplateCreator(fileReader);
11+
ProductAPITemplateCreator productAPITemplateCreator = new ProductAPITemplateCreator();
12+
DiagnosticTemplateCreator diagnosticTemplateCreator = new DiagnosticTemplateCreator();
13+
APITemplateCreator apiTemplateCreator = new APITemplateCreator(fileReader, templateCreator, policyTemplateCreator, productAPITemplateCreator, diagnosticTemplateCreator);
14+
return apiTemplateCreator;
15+
}
16+
}
17+
}

0 commit comments

Comments
 (0)