Skip to content

Commit c1aa042

Browse files
committed
Taking in CR comments and also blocking generation of file whose life started in portal
1 parent d0d77ed commit c1aa042

File tree

10 files changed

+348
-243
lines changed

10 files changed

+348
-243
lines changed

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/PSRecoveryServicesClient/PSRecoveryServicesCloudServiceClient.cs

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@
1414

1515
using System;
1616
using System.Collections.Generic;
17-
using System.Net;
18-
using System.Threading.Tasks;
17+
using Microsoft.Azure.Commands.RecoveryServices.SiteRecovery;
1918
using Microsoft.WindowsAzure;
2019
using Microsoft.WindowsAzure.Management.RecoveryServices.Models;
2120

@@ -40,24 +39,23 @@ public IEnumerable<CloudService> GetCloudServices()
4039
/// <summary>
4140
/// Method to get Cloud Service object for a given vault
4241
/// </summary>
43-
/// <param name="vaultName">vault name</param>
44-
/// <param name="region">vault region</param>
42+
/// <param name="vault">vault object</param>
4543
/// <returns>cloud service object.</returns>
46-
public CloudService GetCloudServiceForVault(string vaultName, string region)
44+
public CloudService GetCloudServiceForVault(ASRVault vault)
4745
{
4846
IEnumerable<CloudService> cloudServiceList = this.GetCloudServices();
4947
CloudService cloudServiceToReturn = null;
5048

5149
foreach (var cloudService in cloudServiceList)
5250
{
5351
Vault selectedVault = null;
54-
if (cloudService.GeoRegion == region)
52+
if (cloudService.GeoRegion.Equals(vault.Location, StringComparison.InvariantCultureIgnoreCase))
5553
{
56-
foreach (var vault in cloudService.Resources)
54+
foreach (var resource in cloudService.Resources)
5755
{
58-
if (vault.Name == vaultName)
56+
if (resource.Name.Equals(vault.Name, StringComparison.InvariantCultureIgnoreCase))
5957
{
60-
selectedVault = vault;
58+
selectedVault = resource;
6159
break;
6260
}
6361
}

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/PSRecoveryServicesClient/PSRecoveryServicesVaultExtendedInfoClient.cs

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@
1212
// limitations under the License.
1313
// ----------------------------------------------------------------------------------
1414

15+
using System;
16+
using System.Security.Cryptography.X509Certificates;
1517
using System.Threading.Tasks;
18+
using Microsoft.Azure.Commands.RecoveryServices.Properties;
19+
using Microsoft.Azure.Commands.RecoveryServices.SiteRecovery;
20+
using Microsoft.Azure.Portal.HybridServicesCore;
21+
using Microsoft.Azure.Portal.RecoveryServices.Models.Common;
1622
using Microsoft.WindowsAzure;
1723
using Microsoft.WindowsAzure.Management.SiteRecovery.Models;
24+
using rpError = Microsoft.Azure.Commands.RecoveryServices.RestApiInfra;
1825

1926
namespace Microsoft.Azure.Commands.RecoveryServices
2027
{
@@ -53,5 +60,150 @@ public async Task<UploadCertificateResponse> UpdateVaultCertificate(CertificateA
5360
{
5461
return await this.GetSiteRecoveryClient().VaultExtendedInfo.UploadCertificateAsync(args, this.GetRequestHeaders(false));
5562
}
63+
64+
/// <summary>
65+
/// Gets the vault credential object
66+
/// </summary>
67+
/// <param name="managementCert">certificate to be uploaded</param>
68+
/// <param name="vault">vault object</param>
69+
/// <param name="site">site object </param>
70+
/// <returns>credential object</returns>
71+
public ASRVaultCreds GetVaultCrentials(X509Certificate2 managementCert, ASRVault vault, Site site)
72+
{
73+
Utilities.UpdateVaultSettings(new ASRVaultCreds()
74+
{
75+
CloudServiceName = vault.CloudServiceName,
76+
ResourceName = vault.Name
77+
});
78+
79+
// Get Channel Integrity key
80+
string channelIntegrityKey;
81+
Task<string> getChannelIntegrityKey = this.GetChannelIntegrityKey();
82+
83+
// Making sure we can generate the file, once the SDK and portal are inter-operable
84+
// upload certificate and fetch of ACIK can be made parallel to improvve the performace.
85+
getChannelIntegrityKey.Wait();
86+
87+
// Upload certificate
88+
UploadCertificateResponse acsDetails;
89+
Task<UploadCertificateResponse> uploadCertificate = this.UpdateVaultCertificate(managementCert);
90+
uploadCertificate.Wait();
91+
92+
acsDetails = uploadCertificate.Result;
93+
channelIntegrityKey = getChannelIntegrityKey.Result;
94+
95+
ASRVaultCreds asrVaultCreds = this.GenerateCredential(
96+
managementCert,
97+
acsDetails,
98+
channelIntegrityKey,
99+
vault,
100+
site);
101+
102+
return asrVaultCreds;
103+
}
104+
105+
/// <summary>
106+
/// Method to update vault certificate
107+
/// </summary>
108+
/// <param name="cert">certificate object </param>
109+
/// <returns>Upload Certificate Response</returns>
110+
private async Task<UploadCertificateResponse> UpdateVaultCertificate(X509Certificate2 cert)
111+
{
112+
var certificateArgs = new CertificateArgs()
113+
{
114+
Certificate = Convert.ToBase64String(cert.GetRawCertData()),
115+
ContractVersion = "V2012_12"
116+
};
117+
118+
UploadCertificateResponse response = await this.UpdateVaultCertificate(certificateArgs);
119+
120+
return response;
121+
}
122+
123+
/// <summary>
124+
/// Get the Integrity key
125+
/// </summary>
126+
/// <returns>key as string.</returns>
127+
private async Task<string> GetChannelIntegrityKey()
128+
{
129+
ResourceExtendedInformation extendedInformation = null;
130+
try
131+
{
132+
extendedInformation = await this.GetExtendedInfo();
133+
}
134+
catch (Exception exception)
135+
{
136+
CloudException cloudException = exception as CloudException;
137+
138+
if (cloudException != null && cloudException.Response != null && !string.IsNullOrEmpty(cloudException.Response.Content))
139+
{
140+
rpError.Error error = (rpError.Error)Utilities.Deserialize<rpError.Error>(cloudException.Response.Content);
141+
if (error.ErrorCode.Equals(RpErrorCode.ResourceExtendedInfoNotFound.ToString(), StringComparison.InvariantCultureIgnoreCase))
142+
{
143+
extendedInformation = new ResourceExtendedInformation();
144+
}
145+
}
146+
}
147+
148+
ResourceExtendedInfo extendedInfo = Utilities.Deserialize<ResourceExtendedInfo>(extendedInformation.ExtendedInfo);
149+
150+
if (extendedInfo == null)
151+
{
152+
extendedInfo = this.CreateVaultExtendedInformatino();
153+
}
154+
else
155+
{
156+
if (!extendedInfo.Algorithm.Equals(CryptoAlgorithm.None.ToString(), StringComparison.InvariantCultureIgnoreCase))
157+
{
158+
// In case this condition is true that means the credential was first generated in portal
159+
// and hence can not be fetched here.
160+
throw new CloudException(Resources.VaultCredentialGenerationUnSopported);
161+
}
162+
}
163+
164+
return extendedInfo.ChannelIntegrityKey;
165+
}
166+
167+
/// <summary>
168+
/// Method to create the extended info for the vault.
169+
/// </summary>
170+
/// <returns>returns the object as task</returns>
171+
private ResourceExtendedInfo CreateVaultExtendedInformatino()
172+
{
173+
ResourceExtendedInfo extendedInfo = new ResourceExtendedInfo();
174+
extendedInfo.GenerateSecurityInfo();
175+
ResourceExtendedInformationArgs extendedInfoArgs = extendedInfo.Translate();
176+
this.CreateExtendedInfo(extendedInfoArgs);
177+
178+
return extendedInfo;
179+
}
180+
181+
/// <summary>
182+
/// Method to generate the credential file content
183+
/// </summary>
184+
/// <param name="managementCert">management cert</param>
185+
/// <param name="acsDetails">ACS details</param>
186+
/// <param name="channelIntegrityKey">Integrity key</param>
187+
/// <param name="vault">vault object</param>
188+
/// <param name="site">site object</param>
189+
/// <returns>vault credential object</returns>
190+
private ASRVaultCreds GenerateCredential(X509Certificate2 managementCert, UploadCertificateResponse acsDetails, string channelIntegrityKey, ASRVault vault, Site site)
191+
{
192+
string serializedCertifivate = Convert.ToBase64String(managementCert.Export(X509ContentType.Pfx));
193+
194+
AcsNamespace acsNamespace = new AcsNamespace(acsDetails);
195+
196+
ASRVaultCreds vaultCreds = new ASRVaultCreds(
197+
vault.SubscriptionId,
198+
vault.Name,
199+
serializedCertifivate,
200+
acsNamespace,
201+
channelIntegrityKey,
202+
vault.CloudServiceName,
203+
site.ID,
204+
site.Name);
205+
206+
return vaultCreds;
207+
}
56208
}
57209
}

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/Properties/Resources.Designer.cs

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/Properties/Resources.resx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,4 +200,7 @@ ClientRequestId: {3}</value>
200200
<data name="ProtectionEntityAlreadyEnabled" xml:space="preserve">
201201
<value>Protection entity {0} is already enabled</value>
202202
</data>
203+
<data name="VaultCredentialGenerationUnSopported" xml:space="preserve">
204+
<value>Cannot generate vault credentials from powershell for this vault. Download the file from portal.</value>
205+
</data>
203206
</root>

src/ServiceManagement/RecoveryServices/Commands.RecoveryServices/Service/CreateAzureSiteRecoveryVault.cs

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,14 @@
1717
using Microsoft.Azure.Commands.RecoveryServices.SiteRecovery;
1818
using Microsoft.Azure.Portal.RecoveryServices.Models.Common;
1919
using Microsoft.WindowsAzure.Management.RecoveryServices.Models;
20-
using Microsoft.WindowsAzure.Management.SiteRecovery.Models;
2120

2221
namespace Microsoft.Azure.Commands.RecoveryServices
2322
{
2423
/// <summary>
2524
/// Used to initiate a vault create operation.
2625
/// </summary>
2726
[Cmdlet(VerbsCommon.New, "AzureSiteRecoveryVault")]
28-
[OutputType(typeof(string))]
27+
[OutputType(typeof(VaultOperationOutput))]
2928
public class CreateAzureSiteRecoveryVault : RecoveryServicesCmdletBase
3029
{
3130
#region Parameters
@@ -70,21 +69,20 @@ public override void ExecuteCmdlet()
7069
{
7170
Name = this.Name,
7271
Plan = string.Empty,
73-
ResourceProviderNamespace = "WAHyperVRecoveryManager", // TODO:devsri - do not hard code, find a good place to keep it.
74-
Type = Constants.ASRVaulType,
72+
ResourceProviderNamespace = Constants.ResourceNamespace,
73+
Type = Constants.ASRVaultType,
7574
ETag = Guid.NewGuid().ToString(),
7675
SchemaVersion = Constants.RpSchemaVersion
7776
};
7877

79-
Utilities.UpdateVaultSettings(new ASRVaultCreds()
80-
{
81-
CloudServiceName = cloudServiceName,
82-
ResourceName = this.Name
83-
});
84-
8578
VaultCreateResponse response = RecoveryServicesClient.CreateVault(cloudServiceName, this.Name, vaultCreateArgs);
8679

87-
this.WriteObject(response.RequestId, true);
80+
VaultOperationOutput output = new VaultOperationOutput()
81+
{
82+
OperationTrackingId = response.RequestId
83+
};
84+
85+
this.WriteObject(output, true);
8886
}
8987
catch (Exception exception)
9088
{

0 commit comments

Comments
 (0)