-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added Azure Credentials Manager Singleton #18
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,140 @@ | ||
import { SubscriptionClient, ResourceManagementClient, SubscriptionModels } from 'azure-arm-resource'; | ||
import { AzureAccount } from '../typings/azure-account.api'; | ||
import { ServiceClientCredentials } from 'ms-rest'; | ||
import { AsyncPool } from '../utils/asyncpool'; | ||
import { ContainerRegistryManagementClient } from 'azure-arm-containerregistry'; | ||
import * as ContainerModels from '../node_modules/azure-arm-containerregistry/lib/models'; | ||
import { ResourceGroup, ResourceGroupListResult } from "azure-arm-resource/lib/resource/models"; | ||
import { MAX_CONCURRENT_SUBSCRIPTON_REQUESTS } from './constants'; | ||
|
||
/* Singleton for facilitating communication with Azure account services by providing extended shared | ||
functionality and extension wide access to azureAccount. Tool for internal use. | ||
Authors: Esteban Rey L, Jackson Stokes | ||
*/ | ||
|
||
export class AzureCredentialsManager { | ||
|
||
//SETUP | ||
private static _instance: AzureCredentialsManager = new AzureCredentialsManager(); | ||
private azureAccount: AzureAccount; | ||
|
||
private constructor() { | ||
AzureCredentialsManager._instance = this; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can remove this: unreachable code. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would I just maintain an empty private constructor then? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, making the constructor private ensures this class cannot be instantiated. Hence, the only way is to use static object creation |
||
} | ||
|
||
public static getInstance(): AzureCredentialsManager { | ||
if (!AzureCredentialsManager._instance) { // lazy initialization | ||
AzureCredentialsManager._instance = new AzureCredentialsManager(); | ||
} | ||
return AzureCredentialsManager._instance; | ||
} | ||
|
||
//This function has to be called explicitly before using the singleton. | ||
public setAccount(azureAccount) { | ||
this.azureAccount = azureAccount; | ||
} | ||
|
||
//GETTERS | ||
public getAccount() { | ||
if (this.azureAccount) return this.azureAccount; | ||
throw ('Azure account is not present, you may have forgotten to call setAccount'); | ||
} | ||
|
||
public getFilteredSubscriptionList(): SubscriptionModels.Subscription[] { | ||
return this.getAccount().filters.map<SubscriptionModels.Subscription>(filter => { | ||
return { | ||
id: filter.subscription.id, | ||
session: filter.session, | ||
subscriptionId: filter.subscription.subscriptionId, | ||
tenantId: filter.session.tenantId, | ||
displayName: filter.subscription.displayName, | ||
state: filter.subscription.state, | ||
subscriptionPolicies: filter.subscription.subscriptionPolicies, | ||
authorizationSource: filter.subscription.authorizationSource | ||
}; | ||
}); | ||
} | ||
|
||
public getContainerRegistryManagementClient(subscription: SubscriptionModels.Subscription): ContainerRegistryManagementClient { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like this method will be used internally and can be made There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That method is meant to be for external use, maybe providing a different name/ providing additional filtering and labeling it getSubscriptions where this particular filtering is default would be better? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You can keep it |
||
return new ContainerRegistryManagementClient(this.getCredentialByTenantId(subscription.tenantId), subscription.subscriptionId); | ||
} | ||
|
||
public getResourceManagementClient(subscription: SubscriptionModels.Subscription): ResourceManagementClient { | ||
return new ResourceManagementClient(this.getCredentialByTenantId(subscription.tenantId), subscription.subscriptionId); | ||
} | ||
|
||
public async getRegistries(subscription?: SubscriptionModels.Subscription, resourceGroup?: string, sortFunction?): Promise<ContainerModels.Registry[]> { | ||
let registries: ContainerModels.Registry[] = []; | ||
|
||
if (subscription && resourceGroup) { | ||
//Get all registries under one resourcegroup | ||
const client = this.getContainerRegistryManagementClient(subscription); | ||
registries = await client.registries.listByResourceGroup(resourceGroup); | ||
|
||
} else if (subscription) { | ||
//Get all registries under one subscription | ||
const client = this.getContainerRegistryManagementClient(subscription); | ||
registries = await client.registries.list(); | ||
|
||
} else { | ||
//Get all registries for all subscriptions | ||
const subs: SubscriptionModels.Subscription[] = this.getFilteredSubscriptionList(); | ||
const subPool = new AsyncPool(MAX_CONCURRENT_SUBSCRIPTON_REQUESTS); | ||
|
||
for (let i = 0; i < subs.length; i++) { | ||
subPool.addTask(async () => { | ||
const client = this.getContainerRegistryManagementClient(subs[i]); | ||
let subscriptionRegistries: ContainerModels.Registry[] = await client.registries.list(); | ||
registries = registries.concat(subscriptionRegistries); | ||
}); | ||
} | ||
await subPool.runAll(); | ||
} | ||
|
||
if (sortFunction && registries.length > 1) { | ||
registries.sort(sortFunction); | ||
} | ||
|
||
return registries; | ||
} | ||
|
||
public async getResourceGroups(subscription?: SubscriptionModels.Subscription): Promise<ResourceGroup[]> { | ||
if (subscription) { | ||
const resourceClient = this.getResourceManagementClient(subscription); | ||
return await resourceClient.resourceGroups.list(); | ||
} | ||
const subs = this.getFilteredSubscriptionList(); | ||
const subPool = new AsyncPool(MAX_CONCURRENT_SUBSCRIPTON_REQUESTS); | ||
let resourceGroups: ResourceGroup[] = []; | ||
//Acquire each subscription's data simultaneously | ||
for (let i = 0; i < subs.length; i++) { | ||
subPool.addTask(async () => { | ||
const resourceClient = this.getResourceManagementClient(subs[i]); | ||
const internalGroups = await resourceClient.resourceGroups.list(); | ||
resourceGroups = resourceGroups.concat(internalGroups); | ||
}); | ||
} | ||
await subPool.runAll(); | ||
return resourceGroups; | ||
} | ||
|
||
public getCredentialByTenantId(tenantId: string): ServiceClientCredentials { | ||
|
||
const session = this.getAccount().sessions.find((azureSession) => azureSession.tenantId.toLowerCase() === tenantId.toLowerCase()); | ||
|
||
if (session) { | ||
return session.credentials; | ||
} | ||
|
||
throw new Error(`Failed to get credentials, tenant ${tenantId} not found.`); | ||
} | ||
|
||
//CHECKS | ||
//Provides a unified check for login that should be called once before using the rest of the singletons capabilities | ||
public async isLoggedIn(): Promise<boolean> { | ||
if (!this.azureAccount) { | ||
return false; | ||
} | ||
return await this.azureAccount.waitForLogin(); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do no initialize here, defeats the purpose of lazy initialization.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh that's my bad, I thought Id gotten that fixed.