Skip to content
This repository was archived by the owner on Apr 13, 2020. It is now read-only.

Commit 8d7b245

Browse files
[FEATURE] Create resource group and ACR in spk setup command (#391)
* [FEATURE] Create resource group and ACR in spk setup command * fix lint error * fix lint error * move azure container registry and resource group services to lib/azure folder Co-authored-by: Andre Briggs <[email protected]>
1 parent 8bd0510 commit 8d7b245

13 files changed

+1180
-194
lines changed

package.json

+2
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,8 @@
6464
]
6565
},
6666
"dependencies": {
67+
"@azure/arm-containerregistry": "^7.0.0",
68+
"@azure/arm-resources": "^2.1.0",
6769
"@azure/arm-storage": "^10.1.0",
6870
"@azure/arm-subscriptions": "^2.0.0",
6971
"@azure/identity": "^1.0.0",

src/commands/setup.md

+3
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ for a few questions
2121
2. Subscription Id is automatically retrieved with the Service Principal
2222
credential. In case, there are two or more subscriptions, you will be
2323
prompt to select one of them.
24+
3. Create a resource group, `quick-start-rg` if it does not exist.
25+
4. Create a Azure Container Registry, `quickStartACR` in resource group,
26+
`quick-start-rg` if it does not exist.
2427

2528
It can also run in a non interactive mode by providing a file that contains
2629
answers to the above questions.

src/commands/setup.test.ts

+10-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ import path from "path";
22
import { readYaml } from "../config";
33
import * as config from "../config";
44
import * as azdoClient from "../lib/azdoClient";
5+
import * as azureContainerRegistryService from "../lib/azure/containerRegistryService";
6+
import * as resourceService from "../lib/azure/resourceService";
57
import { createTempDir } from "../lib/ioUtil";
68
import { IRequestContext, WORKSPACE } from "../lib/setup/constants";
79
import * as fsUtil from "../lib/setup/fsUtil";
@@ -16,10 +18,15 @@ import { IConfigYaml } from "../types";
1618
import { createSPKConfig, execute, getErrorMessage } from "./setup";
1719
import * as setup from "./setup";
1820

19-
const mockRequestContext = {
21+
const mockRequestContext: IRequestContext = {
2022
accessToken: "pat",
2123
orgName: "orgname",
2224
projectName: "project",
25+
servicePrincipalId: "1eba2d04-1506-4278-8f8c-b1eb2fc462a8",
26+
servicePrincipalPassword: "e4c19d72-96d6-4172-b195-66b3b1c36db1",
27+
servicePrincipalTenantId: "72f988bf-86f1-41af-91ab-2d7cd011db47",
28+
subscriptionId: "72f988bf-86f1-41af-91ab-2d7cd011db48",
29+
toCreateAppRepo: true,
2330
workspace: WORKSPACE
2431
};
2532

@@ -74,6 +81,8 @@ const testExecuteFunc = async (usePrompt = true, hasProject = true) => {
7481
jest
7582
.spyOn(pipelineService, "createHLDtoManifestPipeline")
7683
.mockReturnValueOnce(Promise.resolve());
84+
jest.spyOn(resourceService, "create").mockResolvedValue(true);
85+
jest.spyOn(azureContainerRegistryService, "create").mockResolvedValue(true);
7786
jest.spyOn(setupLog, "create").mockReturnValueOnce();
7887

7988
const exitFn = jest.fn();

src/commands/setup.ts

+29-1
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,16 @@ import fs from "fs";
33
import yaml from "js-yaml";
44
import { defaultConfigFile } from "../config";
55
import { getBuildApi, getWebApi } from "../lib/azdoClient";
6+
import { create as createACR } from "../lib/azure/containerRegistryService";
7+
import { create as createResourceGroup } from "../lib/azure/resourceService";
68
import { build as buildCmd, exit as exitCmd } from "../lib/commandBuilder";
7-
import { IRequestContext, WORKSPACE } from "../lib/setup/constants";
9+
import {
10+
ACR,
11+
IRequestContext,
12+
RESOURCE_GROUP,
13+
RESOURCE_GROUP_LOCATION,
14+
WORKSPACE
15+
} from "../lib/setup/constants";
816
import { createDirectory } from "../lib/setup/fsUtil";
917
import { getGitApi } from "../lib/setup/gitService";
1018
import { createHLDtoManifestPipeline } from "../lib/setup/pipelineService";
@@ -102,6 +110,26 @@ export const execute = async (
102110
await manifestRepo(gitAPI, requestContext);
103111
await createHLDtoManifestPipeline(buildAPI, requestContext);
104112

113+
if (requestContext.toCreateAppRepo) {
114+
requestContext.createdResourceGroup = await createResourceGroup(
115+
requestContext.servicePrincipalId!,
116+
requestContext.servicePrincipalPassword!,
117+
requestContext.servicePrincipalTenantId!,
118+
requestContext.subscriptionId!,
119+
RESOURCE_GROUP,
120+
RESOURCE_GROUP_LOCATION
121+
);
122+
requestContext.createdACR = await createACR(
123+
requestContext.servicePrincipalId!,
124+
requestContext.servicePrincipalPassword!,
125+
requestContext.servicePrincipalTenantId!,
126+
requestContext.subscriptionId!,
127+
RESOURCE_GROUP,
128+
ACR,
129+
RESOURCE_GROUP_LOCATION
130+
);
131+
}
132+
105133
createSetupLog(requestContext);
106134
await exitFn(0);
107135
} catch (err) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
import {
2+
ContainerRegistryManagementClientOptions,
3+
RegistriesCreateResponse,
4+
Registry
5+
} from "@azure/arm-containerregistry/src/models";
6+
import { RequestOptionsBase } from "@azure/ms-rest-js";
7+
import { ApplicationTokenCredentials } from "@azure/ms-rest-nodeauth";
8+
9+
import * as restAuth from "@azure/ms-rest-nodeauth";
10+
import {
11+
create,
12+
getContainerRegistries,
13+
isExist
14+
} from "./containerRegistryService";
15+
import * as containerRegistryService from "./containerRegistryService";
16+
17+
jest.mock("@azure/arm-containerregistry", () => {
18+
class MockClient {
19+
constructor(
20+
cred: ApplicationTokenCredentials,
21+
subId: string,
22+
options?: ContainerRegistryManagementClientOptions
23+
) {
24+
return {
25+
registries: {
26+
create: async (
27+
resourceGroupName: string,
28+
registryName: string,
29+
registry: Registry,
30+
opts?: RequestOptionsBase
31+
): Promise<RegistriesCreateResponse> => {
32+
return {} as any;
33+
},
34+
list: () => {
35+
return [
36+
{
37+
id:
38+
"/subscriptions/dd831253-787f-4dc8-8eb0-ac9d052177d9/resourceGroups/bedrockSPK/providers/Microsoft.ContainerRegistry/registries/acrWest",
39+
name: "acrWest"
40+
}
41+
];
42+
}
43+
}
44+
};
45+
}
46+
}
47+
return {
48+
ContainerRegistryManagementClient: MockClient
49+
};
50+
});
51+
52+
const accessToken = "pat";
53+
const orgName = "org";
54+
const projectName = "project";
55+
const servicePrincipalId = "1eba2d04-1506-4278-8f8c-b1eb2fc462a8";
56+
const servicePrincipalPassword = "e4c19d72-96d6-4172-b195-66b3b1c36db1";
57+
const servicePrincipalTenantId = "72f988bf-86f1-41af-91ab-2d7cd011db47";
58+
const subscriptionId = "test";
59+
const workspace = "test";
60+
const RESOURCE_GROUP = "quick-start-rg";
61+
const RESOURCE_GROUP_LOCATION = "westus2";
62+
63+
describe("test container registries function", () => {
64+
it("negative test", async () => {
65+
jest
66+
.spyOn(restAuth, "loginWithServicePrincipalSecret")
67+
.mockImplementationOnce(() => {
68+
throw Error("fake");
69+
});
70+
await expect(
71+
getContainerRegistries(
72+
servicePrincipalId,
73+
servicePrincipalPassword,
74+
servicePrincipalTenantId,
75+
subscriptionId
76+
)
77+
).rejects.toThrow();
78+
});
79+
it("positive test: one value", async () => {
80+
jest
81+
.spyOn(restAuth, "loginWithServicePrincipalSecret")
82+
.mockImplementationOnce(async () => {
83+
return {};
84+
});
85+
const result = await getContainerRegistries(
86+
servicePrincipalId,
87+
servicePrincipalPassword,
88+
servicePrincipalTenantId,
89+
subscriptionId
90+
);
91+
expect(result).toStrictEqual([
92+
{
93+
id:
94+
"/subscriptions/dd831253-787f-4dc8-8eb0-ac9d052177d9/resourceGroups/bedrockSPK/providers/Microsoft.ContainerRegistry/registries/acrWest",
95+
name: "acrWest",
96+
resourceGroup: "bedrockSPK"
97+
}
98+
]);
99+
});
100+
it("cache test", async () => {
101+
const fnAuth = jest.spyOn(restAuth, "loginWithServicePrincipalSecret");
102+
fnAuth.mockReset();
103+
await getContainerRegistries(
104+
servicePrincipalId,
105+
servicePrincipalPassword,
106+
servicePrincipalTenantId,
107+
subscriptionId
108+
);
109+
expect(fnAuth).toBeCalledTimes(0);
110+
});
111+
it("isExist: group already exist", async () => {
112+
jest
113+
.spyOn(containerRegistryService, "getContainerRegistries")
114+
.mockResolvedValueOnce([
115+
{
116+
id: "fakeId",
117+
name: "test",
118+
resourceGroup: RESOURCE_GROUP
119+
}
120+
]);
121+
const res = await isExist(
122+
servicePrincipalId,
123+
servicePrincipalPassword,
124+
servicePrincipalTenantId,
125+
subscriptionId,
126+
RESOURCE_GROUP,
127+
"test"
128+
);
129+
expect(res).toBeTruthy();
130+
});
131+
it("isExist: no groups", async () => {
132+
jest
133+
.spyOn(containerRegistryService, "getContainerRegistries")
134+
.mockResolvedValueOnce([]);
135+
const res = await isExist(
136+
servicePrincipalId,
137+
servicePrincipalPassword,
138+
servicePrincipalTenantId,
139+
subscriptionId,
140+
RESOURCE_GROUP,
141+
"test"
142+
);
143+
expect(res).toBeFalsy();
144+
});
145+
it("isExist: group does not exist", async () => {
146+
jest
147+
.spyOn(containerRegistryService, "getContainerRegistries")
148+
.mockResolvedValueOnce([
149+
{
150+
id: "fakeId",
151+
name: "test1",
152+
resourceGroup: RESOURCE_GROUP
153+
}
154+
]);
155+
const res = await isExist(
156+
servicePrincipalId,
157+
servicePrincipalPassword,
158+
servicePrincipalTenantId,
159+
subscriptionId,
160+
RESOURCE_GROUP,
161+
"test"
162+
);
163+
expect(res).toBeFalsy();
164+
});
165+
it("create: positive test: acr already exist", async () => {
166+
jest.spyOn(containerRegistryService, "isExist").mockResolvedValueOnce(true);
167+
const created = await create(
168+
servicePrincipalId,
169+
servicePrincipalPassword,
170+
servicePrincipalTenantId,
171+
subscriptionId,
172+
RESOURCE_GROUP,
173+
"test",
174+
RESOURCE_GROUP_LOCATION
175+
);
176+
expect(created).toBeFalsy();
177+
});
178+
it("create: positive test: acr did not exist", async () => {
179+
jest
180+
.spyOn(containerRegistryService, "isExist")
181+
.mockResolvedValueOnce(false);
182+
const created = await create(
183+
servicePrincipalId,
184+
servicePrincipalPassword,
185+
servicePrincipalTenantId,
186+
subscriptionId,
187+
RESOURCE_GROUP,
188+
"test",
189+
RESOURCE_GROUP_LOCATION
190+
);
191+
expect(created).toBeTruthy();
192+
});
193+
});

0 commit comments

Comments
 (0)