PageRenderTime 61ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 0ms

/src/ServiceManagement/Services/Commands.Utilities/Websites/WebsitesClient.cs

https://github.com/edumunoz/azure-sdk-tools
C# | 1658 lines | 987 code | 188 blank | 483 comment | 68 complexity | e20bf67bf4f6f211e9d45738ff63ed22 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. // ----------------------------------------------------------------------------------
  2. //
  3. // Copyright Microsoft Corporation
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. // Unless required by applicable law or agreed to in writing, software
  9. // distributed under the License is distributed on an "AS IS" BASIS,
  10. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  11. // See the License for the specific language governing permissions and
  12. // limitations under the License.
  13. // ----------------------------------------------------------------------------------
  14. using System;
  15. using System.Collections;
  16. using System.Collections.Generic;
  17. using System.Diagnostics;
  18. using System.IO;
  19. using System.Linq;
  20. using System.Net;
  21. using System.Net.Http;
  22. using System.Web;
  23. using System.Xml.Linq;
  24. using Microsoft.Build.Evaluation;
  25. using Microsoft.Build.Framework;
  26. using Microsoft.Build.Logging;
  27. using Microsoft.Web.Deployment;
  28. using Microsoft.WindowsAzure.Commands.Common;
  29. using Microsoft.WindowsAzure.Commands.Common.Models;
  30. using Microsoft.WindowsAzure.Commands.Utilities.CloudService;
  31. using Microsoft.WindowsAzure.Commands.Utilities.Common;
  32. using Microsoft.WindowsAzure.Commands.Utilities.Properties;
  33. using Microsoft.WindowsAzure.Commands.Utilities.Websites.Services;
  34. using Microsoft.WindowsAzure.Commands.Utilities.Websites.Services.DeploymentEntities;
  35. using Microsoft.WindowsAzure.Commands.Utilities.Websites.Services.WebJobs;
  36. using Microsoft.WindowsAzure.Commands.Websites.WebJobs;
  37. using Microsoft.WindowsAzure.Management.WebSites;
  38. using Microsoft.WindowsAzure.Management.WebSites.Models;
  39. using Microsoft.WindowsAzure.WebSitesExtensions;
  40. using Microsoft.WindowsAzure.WebSitesExtensions.Models;
  41. using Newtonsoft.Json.Linq;
  42. namespace Microsoft.WindowsAzure.Commands.Utilities.Websites
  43. {
  44. using Utilities = Services.WebEntities;
  45. public class WebsitesClient : IWebsitesClient
  46. {
  47. private const int UploadJobWaitTime = 2000;
  48. private readonly CloudServiceClient cloudServiceClient;
  49. private readonly AzureSubscription subscription;
  50. public static string SlotFormat = "{0}({1})";
  51. public IWebSiteManagementClient WebsiteManagementClient { get; internal set; }
  52. public Action<string> Logger { get; set; }
  53. /// <summary>
  54. /// Creates new WebsitesClient
  55. /// </summary>
  56. /// <param name="subscription">Subscription containing websites to manipulate</param>
  57. /// <param name="logger">The logger action</param>
  58. public WebsitesClient(AzureSubscription subscription, Action<string> logger)
  59. {
  60. Logger = logger;
  61. cloudServiceClient = new CloudServiceClient(subscription, debugStream: logger);
  62. WebsiteManagementClient = AzureSession.ClientFactory.CreateClient<WebSiteManagementClient>(subscription, AzureEnvironment.Endpoint.ServiceManagement);
  63. this.subscription = subscription;
  64. }
  65. /// <summary>
  66. /// Gets website name in the current directory.
  67. /// </summary>
  68. /// <returns></returns>
  69. private string GetWebsiteFromCurrentDirectory()
  70. {
  71. return GitWebsite.ReadConfiguration().Name;
  72. }
  73. private Repository GetRepository(string websiteName)
  74. {
  75. Utilities.Site site = WebsiteManagementClient.GetSiteWithCache(websiteName);
  76. if (site != null)
  77. {
  78. return new Repository(site);
  79. }
  80. throw new Exception(Resources.RepositoryNotSetup);
  81. }
  82. private HttpClient CreateDeploymentHttpClient(string websiteName)
  83. {
  84. Repository repository;
  85. ICredentials credentials;
  86. GetWebsiteDeploymentHttpConfiguration(websiteName, out repository, out credentials);
  87. return AzureSession.ClientFactory.CreateHttpClient(repository.RepositoryUri, credentials);
  88. }
  89. private string GetWebsiteDeploymentHttpConfiguration(
  90. string name,
  91. out Repository repository,
  92. out ICredentials credentials)
  93. {
  94. name = SetWebsiteName(name, null);
  95. repository = GetRepository(name);
  96. credentials = new NetworkCredential(
  97. repository.PublishingUsername,
  98. repository.PublishingPassword);
  99. return name;
  100. }
  101. private string GetWebsiteName(string name)
  102. {
  103. return string.IsNullOrEmpty(name) ? GetWebsiteFromCurrentDirectory() : name;
  104. }
  105. private void ChangeWebsiteState(string name, string webspace, WebsiteState state)
  106. {
  107. WebsiteManagementClient.WebSites.Update(webspace, name, new WebSiteUpdateParameters
  108. {
  109. State = state.ToString(),
  110. // Set the following 3 collection properties to null since by default they are empty lists,
  111. // which will clear the corresponding settings of the web site, thus results in a 404 when browsing the web site.
  112. HostNames = null,
  113. HostNameSslStates = null,
  114. SslCertificates = null
  115. });
  116. }
  117. private void SetApplicationDiagnosticsSettings(
  118. string name,
  119. WebsiteDiagnosticOutput output,
  120. bool setFlag,
  121. Dictionary<DiagnosticProperties, object> properties = null)
  122. {
  123. Utilities.Site website = GetWebsite(name);
  124. using (HttpClient client = CreateDeploymentHttpClient(website.Name))
  125. {
  126. DiagnosticsSettings diagnosticsSettings = GetApplicationDiagnosticsSettings(website.Name);
  127. switch (output)
  128. {
  129. case WebsiteDiagnosticOutput.FileSystem:
  130. diagnosticsSettings.AzureDriveTraceEnabled = setFlag;
  131. diagnosticsSettings.AzureDriveTraceLevel = setFlag ?
  132. (Services.DeploymentEntities.LogEntryType)properties[DiagnosticProperties.LogLevel] :
  133. diagnosticsSettings.AzureDriveTraceLevel;
  134. break;
  135. case WebsiteDiagnosticOutput.StorageTable:
  136. diagnosticsSettings.AzureTableTraceEnabled = setFlag;
  137. if (setFlag)
  138. {
  139. const string storageTableName = "CLOUD_STORAGE_ACCOUNT";
  140. string storageAccountName = (string)properties[DiagnosticProperties.StorageAccountName];
  141. string connectionString = cloudServiceClient.GetStorageServiceConnectionString(
  142. storageAccountName);
  143. SetConnectionString(website.Name, storageTableName, connectionString, Utilities.DatabaseType.Custom);
  144. diagnosticsSettings.AzureTableTraceLevel = setFlag ?
  145. (Services.DeploymentEntities.LogEntryType)properties[DiagnosticProperties.LogLevel] :
  146. diagnosticsSettings.AzureTableTraceLevel;
  147. }
  148. break;
  149. default:
  150. throw new ArgumentException();
  151. }
  152. // Check if there is null fields for diagnostics settings. If there is, default to false. (Same as defaulted on portal)
  153. diagnosticsSettings.AzureDriveTraceEnabled = diagnosticsSettings.AzureDriveTraceEnabled ?? false;
  154. diagnosticsSettings.AzureTableTraceEnabled = diagnosticsSettings.AzureTableTraceEnabled ?? false;
  155. JObject json = new JObject(
  156. new JProperty(UriElements.AzureDriveTraceEnabled, diagnosticsSettings.AzureDriveTraceEnabled),
  157. new JProperty(UriElements.AzureDriveTraceLevel, diagnosticsSettings.AzureDriveTraceLevel.ToString()),
  158. new JProperty(UriElements.AzureTableTraceEnabled, diagnosticsSettings.AzureTableTraceEnabled),
  159. new JProperty(UriElements.AzureTableTraceLevel, diagnosticsSettings.AzureTableTraceLevel.ToString()));
  160. client.PostJson(UriElements.DiagnosticsSettings, json, Logger);
  161. }
  162. }
  163. private void SetSiteDiagnosticsSettings(
  164. string name,
  165. bool webServerLogging,
  166. bool detailedErrorMessages,
  167. bool failedRequestTracing,
  168. bool setFlag)
  169. {
  170. Utilities.Site website = GetWebsite(name);
  171. var update = WebsiteManagementClient.WebSites.GetConfiguration(website.WebSpace, website.Name).ToUpdate();
  172. update.HttpLoggingEnabled = webServerLogging ? setFlag : update.HttpLoggingEnabled;
  173. update.DetailedErrorLoggingEnabled = detailedErrorMessages ? setFlag : update.DetailedErrorLoggingEnabled;
  174. update.RequestTracingEnabled = failedRequestTracing ? setFlag : update.RequestTracingEnabled;
  175. WebsiteManagementClient.WebSites.UpdateConfiguration(website.WebSpace, website.Name, update);
  176. }
  177. private bool IsProductionSlot(string slot)
  178. {
  179. return (!string.IsNullOrEmpty(slot)) &&
  180. (slot.Equals(WebsiteSlotName.Production.ToString(), StringComparison.OrdinalIgnoreCase));
  181. }
  182. private IWebSiteExtensionsClient GetWebSiteExtensionsClient(string websiteName)
  183. {
  184. Utilities.Site website = GetWebsite(websiteName);
  185. Uri endpointUrl = new Uri("https://" + website.EnabledHostNames.First(url => url.Contains(".scm.")));
  186. return AzureSession.ClientFactory.CreateCustomClient<WebSiteExtensionsClient>(new object[] { websiteName,
  187. GetWebSiteExtensionsCredentials(websiteName), endpointUrl });
  188. }
  189. private BasicAuthenticationCloudCredentials GetWebSiteExtensionsCredentials(string name)
  190. {
  191. name = SetWebsiteName(name, null);
  192. Repository repository = GetRepository(name);
  193. return new BasicAuthenticationCloudCredentials()
  194. {
  195. Username = repository.PublishingUsername,
  196. Password = repository.PublishingPassword
  197. };
  198. }
  199. /// <summary>
  200. /// Starts log streaming for the given website.
  201. /// </summary>
  202. /// <param name="name">The website name</param>
  203. /// <param name="slot">The website slot name</param>
  204. /// <param name="path">The log path, by default root</param>
  205. /// <param name="message">The substring message</param>
  206. /// <param name="endStreaming">Predicate to end streaming</param>
  207. /// <param name="waitInternal">The fetch wait interval</param>
  208. /// <returns>The log line</returns>
  209. public IEnumerable<string> StartLogStreaming(
  210. string name,
  211. string slot,
  212. string path,
  213. string message,
  214. Predicate<string> endStreaming,
  215. int waitInternal)
  216. {
  217. name = SetWebsiteName(name, slot);
  218. return StartLogStreaming(name, path, message, endStreaming, waitInternal);
  219. }
  220. /// <summary>
  221. /// List log paths for a given website.
  222. /// </summary>
  223. /// <param name="name">The website name</param>
  224. /// <param name="slot">The website slot name</param>
  225. /// <returns>The list of log paths</returns>
  226. public List<LogPath> ListLogPaths(string name, string slot)
  227. {
  228. name = SetWebsiteName(name, slot);
  229. return ListLogPaths(name);
  230. }
  231. /// <summary>
  232. /// Starts log streaming for the given website.
  233. /// </summary>
  234. /// <param name="name">The website name</param>
  235. /// <param name="path">The log path, by default root</param>
  236. /// <param name="message">The substring message</param>
  237. /// <param name="endStreaming">Predicate to end streaming</param>
  238. /// <param name="waitInterval">The fetch wait interval</param>
  239. /// <returns>The log line</returns>
  240. public IEnumerable<string> StartLogStreaming(
  241. string name,
  242. string path,
  243. string message,
  244. Predicate<string> endStreaming,
  245. int waitInterval)
  246. {
  247. Repository repository;
  248. ICredentials credentials;
  249. name = GetWebsiteDeploymentHttpConfiguration(name, out repository, out credentials);
  250. path = HttpUtility.UrlEncode(path);
  251. message = HttpUtility.UrlEncode(message);
  252. RemoteLogStreamManager manager = new RemoteLogStreamManager(
  253. repository.RepositoryUri,
  254. path,
  255. message,
  256. credentials,
  257. Logger);
  258. using (LogStreamWaitHandle logHandler = new LogStreamWaitHandle(manager.GetStream().Result))
  259. {
  260. bool doStreaming = true;
  261. while (doStreaming)
  262. {
  263. string line = logHandler.WaitNextLine(waitInterval);
  264. if (line != null)
  265. {
  266. yield return line;
  267. }
  268. doStreaming = endStreaming == null || endStreaming(line);
  269. }
  270. }
  271. }
  272. /// <summary>
  273. /// List log paths for a given website.
  274. /// </summary>
  275. /// <param name="name"></param>
  276. /// <returns></returns>
  277. public List<LogPath> ListLogPaths(string name)
  278. {
  279. using (HttpClient client = CreateDeploymentHttpClient(name))
  280. {
  281. return client.GetJson<List<LogPath>>(UriElements.LogPaths, Logger);
  282. }
  283. }
  284. /// <summary>
  285. /// Gets the application diagnostics settings
  286. /// </summary>
  287. /// <param name="name">The website name</param>
  288. /// <returns>The website application diagnostics settings</returns>
  289. public DiagnosticsSettings GetApplicationDiagnosticsSettings(string name)
  290. {
  291. using (HttpClient client = CreateDeploymentHttpClient(name))
  292. {
  293. return client.GetJson<DiagnosticsSettings>(UriElements.DiagnosticsSettings, Logger);
  294. }
  295. }
  296. /// <summary>
  297. /// Gets the application diagnostics settings
  298. /// </summary>
  299. /// <param name="name">The website name</param>
  300. /// <param name="slot">The website slot name</param>
  301. /// <returns>The website application diagnostics settings</returns>
  302. public DiagnosticsSettings GetApplicationDiagnosticsSettings(string name, string slot)
  303. {
  304. name = SetWebsiteName(name, slot);
  305. return GetApplicationDiagnosticsSettings(name);
  306. }
  307. /// <summary>
  308. /// Restarts a website.
  309. /// </summary>
  310. /// <param name="name">The website name</param>
  311. public void RestartWebsite(string name)
  312. {
  313. Utilities.Site website = GetWebsite(name);
  314. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Stopped);
  315. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Running);
  316. }
  317. /// <summary>
  318. /// Starts a website.
  319. /// </summary>
  320. /// <param name="name">The website name</param>
  321. public void StartWebsite(string name)
  322. {
  323. Utilities.Site website = GetWebsite(name);
  324. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Running);
  325. }
  326. /// <summary>
  327. /// Stops a website.
  328. /// </summary>
  329. /// <param name="name">The website name</param>
  330. public void StopWebsite(string name)
  331. {
  332. Utilities.Site website = GetWebsite(name);
  333. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Stopped);
  334. }
  335. /// <summary>
  336. /// Restarts a website.
  337. /// </summary>
  338. /// <param name="name">The website name</param>
  339. /// <param name="slot">The website slot name</param>
  340. public void RestartWebsite(string name, string slot)
  341. {
  342. Utilities.Site website = GetWebsite(name, slot);
  343. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Stopped);
  344. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Running);
  345. }
  346. /// <summary>
  347. /// Starts a website.
  348. /// </summary>
  349. /// <param name="name">The website name</param>
  350. /// <param name="slot">The website slot name</param>
  351. public void StartWebsite(string name, string slot)
  352. {
  353. Utilities.Site website = GetWebsite(name, slot);
  354. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Running);
  355. }
  356. /// <summary>
  357. /// Stops a website.
  358. /// </summary>
  359. /// <param name="name">The website name</param>
  360. /// <param name="slot">The website slot name</param>
  361. public void StopWebsite(string name, string slot)
  362. {
  363. Utilities.Site website = GetWebsite(name, slot);
  364. ChangeWebsiteState(website.Name, website.WebSpace, WebsiteState.Stopped);
  365. }
  366. public WebsiteInstance[] ListWebsiteInstances(string webSpace, string fullName)
  367. {
  368. IList<string> instanceIds = WebsiteManagementClient.WebSites.GetInstanceIds(webSpace, fullName).InstanceIds;
  369. return instanceIds.Select(s => new WebsiteInstance { InstanceId = s }).ToArray();
  370. }
  371. /// <summary>
  372. /// Gets a website slot instance.
  373. /// </summary>
  374. /// <param name="name">The website name</param>
  375. /// <param name="slot">The slot name</param>
  376. /// <returns>The website instance</returns>
  377. public Utilities.Site GetWebsite(string name, string slot)
  378. {
  379. name = SetWebsiteName(name, slot);
  380. return GetWebsite(name);
  381. }
  382. /// <summary>
  383. /// Gets a website instance.
  384. /// </summary>
  385. /// <param name="name">The website name</param>
  386. /// <returns>The website instance</returns>
  387. public Utilities.Site GetWebsite(string name)
  388. {
  389. name = SetWebsiteName(name, null);
  390. Utilities.Site website = WebsiteManagementClient.GetSiteWithCache(name);
  391. if (website == null)
  392. {
  393. throw new CloudException(string.Format(Resources.InvalidWebsite, name));
  394. }
  395. return website;
  396. }
  397. /// <summary>
  398. /// Gets all slots for a website
  399. /// </summary>
  400. /// <param name="name">The website name</param>
  401. /// <returns>The website slots list</returns>
  402. public List<Utilities.Site> GetWebsiteSlots(string name)
  403. {
  404. name = SetWebsiteName(name, null);
  405. return ListWebsites()
  406. .Where(s =>
  407. s.Name.IndexOf(string.Format("{0}(", name), StringComparison.OrdinalIgnoreCase) >= 0 ||
  408. s.Name.Equals(name, StringComparison.OrdinalIgnoreCase))
  409. .ToList();
  410. }
  411. /// <summary>
  412. /// Lists all websites under the current subscription
  413. /// </summary>
  414. /// <returns>List of websites</returns>
  415. public List<Utilities.Site> ListWebsites()
  416. {
  417. return ListWebSpaces().SelectMany(space => ListSitesInWebSpace(space.Name)).ToList();
  418. }
  419. /// <summary>
  420. /// Lists all websites with the provided slot name.
  421. /// </summary>
  422. /// <param name="slot">The slot name</param>
  423. /// <returns>The list if websites</returns>
  424. public List<Utilities.Site> ListWebsites(string slot)
  425. {
  426. return ListWebsites().Where(s => s.Name.Contains(string.Format("({0})", slot))).ToList();
  427. }
  428. /// <summary>
  429. /// Gets the hostname of the website
  430. /// </summary>
  431. /// <param name="name">The website name</param>
  432. /// <param name="slot">The website slot name</param>
  433. /// <returns>The hostname</returns>
  434. public string GetHostName(string name, string slot)
  435. {
  436. slot = string.IsNullOrEmpty(slot) ? GetSlotName(name) : slot;
  437. name = SetWebsiteName(name, slot);
  438. string hostname = null;
  439. string dnsSuffix = GetWebsiteDnsSuffix();
  440. if (!string.IsNullOrEmpty(slot) &&
  441. !slot.Equals(WebsiteSlotName.Production.ToString(), StringComparison.OrdinalIgnoreCase))
  442. {
  443. hostname = string.Format("{0}-{1}.{2}", GetWebsiteNameFromFullName(name), slot, dnsSuffix);
  444. }
  445. else
  446. {
  447. hostname = string.Format("{0}.{1}", name, dnsSuffix);
  448. }
  449. return hostname;
  450. }
  451. /// <summary>
  452. /// Create a new website.
  453. /// </summary>
  454. /// <param name="webspaceName">Web space to create site in.</param>
  455. /// <param name="siteToCreate">Details about the site to create.</param>
  456. /// <param name="slot">The slot name.</param>
  457. /// <returns>The created site object</returns>
  458. public Utilities.Site CreateWebsite(string webspaceName, Utilities.SiteWithWebSpace siteToCreate, string slot)
  459. {
  460. siteToCreate.Name = SetWebsiteName(siteToCreate.Name, slot);
  461. string[] hostNames = { GetHostName(siteToCreate.Name, slot) };
  462. siteToCreate.HostNames = hostNames;
  463. return CreateWebsite(webspaceName, siteToCreate);
  464. }
  465. /// <summary>
  466. /// Create a new website in production.
  467. /// </summary>
  468. /// <param name="webspaceName">Web space to create site in.</param>
  469. /// <param name="siteToCreate">Details about the site to create.</param>
  470. /// <returns>The created site object</returns>
  471. private Utilities.Site CreateWebsite(string webspaceName, Utilities.SiteWithWebSpace siteToCreate)
  472. {
  473. var options = new WebSiteCreateParameters
  474. {
  475. Name = siteToCreate.Name,
  476. WebSpaceName = siteToCreate.WebSpaceToCreate.Name,
  477. WebSpace = new WebSiteCreateParameters.WebSpaceDetails
  478. {
  479. GeoRegion = siteToCreate.WebSpaceToCreate.GeoRegion,
  480. Name = siteToCreate.WebSpaceToCreate.Name,
  481. Plan = siteToCreate.WebSpaceToCreate.Plan
  482. }
  483. };
  484. siteToCreate.HostNames.ForEach(s => options.HostNames.Add(s));
  485. var response = WebsiteManagementClient.WebSites.Create(webspaceName, options);
  486. return response.WebSite.ToSite();
  487. }
  488. /// <summary>
  489. /// Update the set of host names for a website.
  490. /// </summary>
  491. /// <param name="site">The site name.</param>
  492. /// <param name="hostNames">The new host names.</param>
  493. public void UpdateWebsiteHostNames(Utilities.Site site, IEnumerable<string> hostNames)
  494. {
  495. var update = new WebSiteUpdateParameters();
  496. foreach (var name in hostNames)
  497. {
  498. update.HostNames.Add(name);
  499. }
  500. WebsiteManagementClient.WebSites.Update(site.WebSpace, site.Name, update);
  501. }
  502. /// <summary>
  503. /// Update the set of host names for a website slot.
  504. /// </summary>
  505. /// <param name="site">The website name.</param>
  506. /// <param name="hostNames">The new host names.</param>
  507. /// <param name="slot">The website slot name.</param>
  508. public void UpdateWebsiteHostNames(Utilities.Site site, IEnumerable<string> hostNames, string slot)
  509. {
  510. site.Name = SetWebsiteName(site.Name, slot);
  511. UpdateWebsiteHostNames(site, hostNames);
  512. }
  513. /// <summary>
  514. /// Gets the website configuration.
  515. /// </summary>
  516. /// <param name="name">The website name</param>
  517. /// <returns>The website configuration object</returns>
  518. public Utilities.SiteConfig GetWebsiteConfiguration(string name)
  519. {
  520. Utilities.Site website = GetWebsite(name);
  521. Utilities.SiteConfig configuration =
  522. WebsiteManagementClient.WebSites.GetConfiguration(website.WebSpace, website.Name).ToSiteConfig();
  523. return configuration;
  524. }
  525. /// <summary>
  526. /// Gets a website slot configuration
  527. /// </summary>
  528. /// <param name="name">The website name</param>
  529. /// <param name="slot">The website slot name</param>
  530. /// <returns>The website cobfiguration object</returns>
  531. public Utilities.SiteConfig GetWebsiteConfiguration(string name, string slot)
  532. {
  533. Utilities.Site website = GetWebsite(name);
  534. website.Name = SetWebsiteName(website.Name, slot);
  535. return GetWebsiteConfiguration(website.Name);
  536. }
  537. /// <summary>
  538. /// Get the real website name.
  539. /// </summary>
  540. /// <param name="name">The website name from the -Name parameter.</param>
  541. /// <param name="slot">The website name from the -Slot parameter.</param>
  542. /// <returns>The real website name.</returns>
  543. private string SetWebsiteName(string name, string slot)
  544. {
  545. name = GetWebsiteName(name);
  546. slot = slot ?? GetSlotName(name);
  547. if (string.IsNullOrEmpty(slot) ||
  548. slot.Equals(WebsiteSlotName.Production.ToString(), StringComparison.OrdinalIgnoreCase))
  549. {
  550. return GetWebsiteNameFromFullName(name);
  551. }
  552. else if (name.Contains('(') && name.Contains(')'))
  553. {
  554. string currentSlot = GetSlotName(name);
  555. if (currentSlot.Equals(WebsiteSlotName.Production.ToString(), StringComparison.OrdinalIgnoreCase))
  556. {
  557. return GetWebsiteNameFromFullName(name);
  558. }
  559. return name;
  560. }
  561. else
  562. {
  563. return GetSlotDnsName(name, slot);
  564. }
  565. }
  566. private string SetWebsiteNameForWebDeploy(string name, string slot)
  567. {
  568. return SetWebsiteName(name, slot).Replace("(", "__").Replace(")", string.Empty);
  569. }
  570. /// <summary>
  571. /// Gets the website name without slot part
  572. /// </summary>
  573. /// <param name="name">The website full name which may include slot name</param>
  574. /// <returns>The website name</returns>
  575. public string GetWebsiteNameFromFullName(string name)
  576. {
  577. if (!string.IsNullOrEmpty(GetSlotName(name)))
  578. {
  579. name = name.Split('(')[0];
  580. }
  581. return name;
  582. }
  583. /// <summary>
  584. /// Update the website configuration
  585. /// </summary>
  586. /// <param name="name">The website name</param>
  587. /// <param name="newConfiguration">The website configuration object containing updates.</param>
  588. public void UpdateWebsiteConfiguration(string name, Utilities.SiteConfig newConfiguration)
  589. {
  590. Utilities.Site website = GetWebsite(name);
  591. WebsiteManagementClient.WebSites.UpdateConfiguration(website.WebSpace, name,
  592. newConfiguration.ToConfigUpdateParameters());
  593. }
  594. /// <summary>
  595. /// Update the website slot configuration
  596. /// </summary>
  597. /// <param name="name">The website name</param>
  598. /// <param name="newConfiguration">The website configuration object containing updates.</param>
  599. /// <param name="slot">The website slot name</param>
  600. public void UpdateWebsiteConfiguration(string name, Utilities.SiteConfig newConfiguration, string slot)
  601. {
  602. name = SetWebsiteName(name, slot);
  603. UpdateWebsiteConfiguration(name, newConfiguration);
  604. }
  605. /// <summary>
  606. /// Create a git repository for the web site.
  607. /// </summary>
  608. /// <param name="webspaceName">Webspace that site is in.</param>
  609. /// <param name="websiteName">The site name.</param>
  610. public void CreateWebsiteRepository(string webspaceName, string websiteName)
  611. {
  612. WebsiteManagementClient.WebSites.CreateRepository(webspaceName, websiteName);
  613. }
  614. /// <summary>
  615. /// Delete a website.
  616. /// </summary>
  617. /// <param name="webspaceName">webspace the site is in.</param>
  618. /// <param name="websiteName">website name.</param>
  619. /// <param name="deleteMetrics">pass true to delete stored metrics as part of removing site.</param>
  620. /// <param name="deleteEmptyServerFarm">Pass true to delete server farm is this was the last website in it.</param>
  621. public void DeleteWebsite(string webspaceName, string websiteName, bool deleteMetrics = false, bool deleteEmptyServerFarm = false)
  622. {
  623. WebSiteDeleteParameters input = new WebSiteDeleteParameters()
  624. {
  625. DeleteAllSlots = true,
  626. DeleteEmptyServerFarm = deleteEmptyServerFarm,
  627. DeleteMetrics = deleteMetrics
  628. };
  629. WebsiteManagementClient.WebSites.Delete(webspaceName, websiteName, input);
  630. }
  631. /// <summary>
  632. /// Delete a website slot.
  633. /// </summary>
  634. /// <param name="webspaceName">webspace the site is in.</param>
  635. /// <param name="websiteName">website name.</param>
  636. /// <param name="slot">The website slot name</param>
  637. public void DeleteWebsite(string webspaceName, string websiteName, string slot)
  638. {
  639. slot = slot ?? GetSlotName(websiteName) ?? WebsiteSlotName.Production.ToString();
  640. websiteName = SetWebsiteName(websiteName, slot);
  641. WebSiteDeleteParameters input = new WebSiteDeleteParameters()
  642. {
  643. /**
  644. * DeleteAllSlots is set to true in case that:
  645. * 1) We are trying to delete a production slot and,
  646. * 2) The website has more than one slot.
  647. */
  648. DeleteAllSlots = IsProductionSlot(slot) && GetWebsiteSlots(websiteName).Count != 1,
  649. DeleteEmptyServerFarm = false,
  650. DeleteMetrics = false
  651. };
  652. WebsiteManagementClient.WebSites.Delete(webspaceName, websiteName, input);
  653. }
  654. /// <summary>
  655. /// Get the WebSpaces.
  656. /// </summary>
  657. /// <returns>Collection of WebSpace objects</returns>
  658. public IList<Utilities.WebSpace> ListWebSpaces()
  659. {
  660. return WebsiteManagementClient.WebSpaces.List().WebSpaces.Select(ws => ws.ToWebSpace()).ToList();
  661. }
  662. /// <summary>
  663. /// Get the sites in the given webspace
  664. /// </summary>
  665. /// <param name="spaceName">Name of webspace</param>
  666. /// <returns>The sites</returns>
  667. public IList<Utilities.Site> ListSitesInWebSpace(string spaceName)
  668. {
  669. WebSiteListParameters input = new WebSiteListParameters();
  670. input.PropertiesToInclude.Add("repositoryuri");
  671. input.PropertiesToInclude.Add("publishingpassword");
  672. input.PropertiesToInclude.Add("publishingusername");
  673. return WebsiteManagementClient.WebSpaces.ListWebSites(spaceName, input).WebSites.Select(s => s.ToSite()).ToList();
  674. }
  675. /// <summary>
  676. /// Sets an AppSetting of a website.
  677. /// </summary>
  678. /// <param name="name">The website name</param>
  679. /// <param name="key">The app setting name</param>
  680. /// <param name="value">The app setting value</param>
  681. public void SetAppSetting(string name, string key, string value)
  682. {
  683. Utilities.Site website = GetWebsite(name);
  684. var update = WebsiteManagementClient.WebSites.GetConfiguration(website.WebSpace, website.Name).ToUpdate();
  685. update.AppSettings[name] = key;
  686. WebsiteManagementClient.WebSites.UpdateConfiguration(website.WebSpace, website.Name, update);
  687. }
  688. /// <summary>
  689. /// Sets a connection string for a website.
  690. /// </summary>
  691. /// <param name="name">Name of the website.</param>
  692. /// <param name="key">Connection string key.</param>
  693. /// <param name="value">Value for the connection string.</param>
  694. /// <param name="connectionStringType">Type of connection string.</param>
  695. public void SetConnectionString(string name, string key, string value, Utilities.DatabaseType connectionStringType)
  696. {
  697. Utilities.Site website = GetWebsite(name);
  698. var update = WebsiteManagementClient.WebSites.GetConfiguration(website.WebSpace, website.Name).ToUpdate();
  699. var csToUpdate = update.ConnectionStrings.FirstOrDefault(cs => cs.Name.Equals(key, StringComparison.OrdinalIgnoreCase));
  700. if (csToUpdate == null)
  701. {
  702. csToUpdate = new WebSiteUpdateConfigurationParameters.ConnectionStringInfo
  703. {
  704. ConnectionString = value,
  705. Name = key,
  706. Type = (ConnectionStringType)Enum.Parse(typeof(ConnectionStringType), connectionStringType.ToString(), ignoreCase: true),
  707. };
  708. update.ConnectionStrings.Add(csToUpdate);
  709. }
  710. else
  711. {
  712. csToUpdate.ConnectionString = value;
  713. csToUpdate.Type = (ConnectionStringType)Enum.Parse(typeof(ConnectionStringType), connectionStringType.ToString(), ignoreCase: true);
  714. }
  715. WebsiteManagementClient.WebSites.UpdateConfiguration(website.WebSpace, website.Name, update);
  716. }
  717. /// <summary>
  718. /// Enables website diagnostic.
  719. /// </summary>
  720. /// <param name="name">The website name</param>
  721. /// <param name="webServerLogging">Flag for webServerLogging</param>
  722. /// <param name="detailedErrorMessages">Flag for detailedErrorMessages</param>
  723. /// <param name="failedRequestTracing">Flag for failedRequestTracing</param>
  724. public void EnableSiteDiagnostic(
  725. string name,
  726. bool webServerLogging,
  727. bool detailedErrorMessages,
  728. bool failedRequestTracing)
  729. {
  730. SetSiteDiagnosticsSettings(name, webServerLogging, detailedErrorMessages, failedRequestTracing, true);
  731. }
  732. /// <summary>
  733. /// Disables site diagnostic.
  734. /// </summary>
  735. /// <param name="name">The website name</param>
  736. /// <param name="webServerLogging">Flag for webServerLogging</param>
  737. /// <param name="detailedErrorMessages">Flag for detailedErrorMessages</param>
  738. /// <param name="failedRequestTracing">Flag for failedRequestTracing</param>
  739. public void DisableSiteDiagnostic(
  740. string name,
  741. bool webServerLogging,
  742. bool detailedErrorMessages,
  743. bool failedRequestTracing)
  744. {
  745. SetSiteDiagnosticsSettings(name, webServerLogging, detailedErrorMessages, failedRequestTracing, false);
  746. }
  747. /// <summary>
  748. /// Enables application diagnostic on website slot.
  749. /// </summary>
  750. /// <param name="name">The website name</param>
  751. /// <param name="output">The application log output, FileSystem or StorageTable</param>
  752. /// <param name="properties">The diagnostic setting properties</param>
  753. /// <param name="slot">The website slot name</param>
  754. public void EnableApplicationDiagnostic(
  755. string name,
  756. WebsiteDiagnosticOutput output,
  757. Dictionary<DiagnosticProperties, object> properties,
  758. string slot)
  759. {
  760. SetApplicationDiagnosticsSettings(SetWebsiteName(name, slot), output, true, properties);
  761. }
  762. /// <summary>
  763. /// Disables application diagnostic.
  764. /// </summary>
  765. /// <param name="name">The website name</param>
  766. /// <param name="output">The application log output, FileSystem or StorageTable</param>
  767. /// <param name="slot">The website slot name</param>
  768. public void DisableApplicationDiagnostic(string name, WebsiteDiagnosticOutput output, string slot)
  769. {
  770. SetApplicationDiagnosticsSettings(SetWebsiteName(name, slot), output, false);
  771. }
  772. /// <summary>
  773. /// Enables application diagnostic on website slot.
  774. /// </summary>
  775. /// <param name="name">The website name</param>
  776. /// <param name="output">The application log output, FileSystem or StorageTable</param>
  777. /// <param name="properties">The diagnostic setting properties</param>
  778. public void EnableApplicationDiagnostic(
  779. string name,
  780. WebsiteDiagnosticOutput output,
  781. Dictionary<DiagnosticProperties, object> properties)
  782. {
  783. SetApplicationDiagnosticsSettings(name, output, true, properties);
  784. }
  785. /// <summary>
  786. /// Disables application diagnostic.
  787. /// </summary>
  788. /// <param name="name">The website name</param>
  789. /// <param name="output">The application log output, FileSystem or StorageTable</param>
  790. public void DisableApplicationDiagnostic(string name, WebsiteDiagnosticOutput output)
  791. {
  792. SetApplicationDiagnosticsSettings(name, output, false);
  793. }
  794. /// <summary>
  795. /// Lists available website locations.
  796. /// </summary>
  797. /// <returns>List of location names</returns>
  798. public List<string> ListAvailableLocations()
  799. {
  800. var webspacesGeoRegions = WebsiteManagementClient.WebSpaces.List()
  801. .WebSpaces.Select(w => w.GeoRegion);
  802. var availableRegionsResponse = WebsiteManagementClient.WebSpaces.ListGeoRegions();
  803. return availableRegionsResponse.GeoRegions.Select(r => r.Name).Union(webspacesGeoRegions).ToList();
  804. }
  805. /// <summary>
  806. /// Gets the default website DNS suffix for the current environment.
  807. /// </summary>
  808. /// <returns>The website DNS suffix</returns>
  809. public string GetWebsiteDnsSuffix()
  810. {
  811. return WebsiteManagementClient.WebSpaces.GetDnsSuffix().DnsSuffix;
  812. }
  813. /// <summary>
  814. /// Gets the default location for websites.
  815. /// </summary>
  816. /// <returns>The default location name.</returns>
  817. public string GetDefaultLocation()
  818. {
  819. return ListAvailableLocations().First();
  820. }
  821. /// <summary>
  822. /// Get a list of the user names configured to publish to the space.
  823. /// </summary>
  824. /// <returns>The list of user names.</returns>
  825. public IList<string> ListPublishingUserNames()
  826. {
  827. return WebsiteManagementClient.WebSpaces.ListPublishingUsers()
  828. .Users.Select(u => u.Name).Where(n => !string.IsNullOrEmpty(n)).ToList();
  829. }
  830. /// <summary>
  831. /// Get a list of historic metrics for the site.
  832. /// </summary>
  833. /// <param name="siteName">The website name</param>
  834. /// <param name="metricNames">List of metrics names to retrieve. See metric definitions for supported names</param>
  835. /// <param name="slot">Slot name</param>
  836. /// <param name="starTime">Start date of the requested period</param>
  837. /// <param name="endTime">End date of the requested period</param>
  838. /// <param name="timeGrain">Time grains for the metrics.</param>
  839. /// <param name="instanceDetails">Include details for the server instances in which the site is running.</param>
  840. /// <param name="slotView">Represent the metrics for the hostnames that receive the traffic at the current slot.
  841. /// If swap occured in the middle of the period mereics will be merged</param>
  842. /// <returns>The list of site metrics for the specified period.</returns>
  843. public IList<Utilities.MetricResponse> GetHistoricalUsageMetrics(string siteName, string slot, IList<string> metricNames,
  844. DateTime? starTime, DateTime? endTime, string timeGrain, bool instanceDetails, bool slotView)
  845. {
  846. Utilities.Site website = null;
  847. if (!string.IsNullOrEmpty(slot))
  848. {
  849. website = GetWebsite(siteName, slot);
  850. }
  851. else
  852. {
  853. website = GetWebsite(siteName);
  854. }
  855. return WebsiteManagementClient.WebSites.GetHistoricalUsageMetrics(website.WebSpace, website.Name,
  856. new WebSiteGetHistoricalUsageMetricsParameters()
  857. {
  858. StartTime = starTime,
  859. EndTime = endTime,
  860. MetricNames = metricNames,
  861. TimeGrain = timeGrain,
  862. IncludeInstanceBreakdown = instanceDetails,
  863. SlotView = slotView
  864. }).ToMetricResponses();
  865. }
  866. /// <summary>
  867. /// Checks if a website exists or not.
  868. /// </summary>
  869. /// <param name="name">The website name</param>
  870. /// <returns>True if exists, false otherwise</returns>
  871. public bool WebsiteExists(string name)
  872. {
  873. Utilities.Site website = null;
  874. try
  875. {
  876. website = GetWebsite(name);
  877. }
  878. catch
  879. {
  880. // Ignore exception.
  881. }
  882. return website != null;
  883. }
  884. /// <summary>
  885. /// Checks if a website slot exists or not.
  886. /// </summary>
  887. /// <param name="name">The website name</param>
  888. /// <param name="slot">The website slot name</param>
  889. /// <returns>True if exists, false otherwise</returns>
  890. public bool WebsiteExists(string name, string slot)
  891. {
  892. Utilities.Site website = null;
  893. try
  894. {
  895. website = GetWebsite(name, slot);
  896. }
  897. catch
  898. {
  899. // Ignore exception.
  900. }
  901. return website != null;
  902. }
  903. /// <summary>
  904. /// Updates a website compute mode.
  905. /// </summary>
  906. /// <param name="websiteToUpdate">The website to update</param>
  907. public void UpdateWebsiteComputeMode(Utilities.Site websiteToUpdate)
  908. {
  909. WebsiteManagementClient.WebSites.Update(
  910. websiteToUpdate.WebSpace,
  911. websiteToUpdate.Name,
  912. new WebSiteUpdateParameters
  913. {
  914. ComputeMode = websiteToUpdate.ComputeMode,
  915. // Set the following 3 collection properties to null since by default they are empty lists,
  916. // which will clear the corresponding settings of the web site, thus results in a 404 when browsing the web site.
  917. HostNames = null,
  918. HostNameSslStates = null,
  919. SslCertificates = null
  920. });
  921. }
  922. /// <summary>
  923. /// Gets a website slot DNS name.
  924. /// </summary>
  925. /// <param name="name">The website name</param>
  926. /// <param name="slot">The slot name</param>
  927. /// <returns>the slot DNS name</returns>
  928. public string GetSlotDnsName(string name, string slot)
  929. {
  930. return string.Format(SlotFormat, name, slot);
  931. }
  932. /// <summary>
  933. /// Switches the given website slot with the production slot
  934. /// </summary>
  935. /// <param name="webspaceName">The webspace name</param>
  936. /// <param name="websiteName">The website name</param>
  937. /// <param name="slot1">The website's first slot name</param>
  938. /// <param name="slot2">The website's second slot name</param>
  939. public void SwitchSlots(string webspaceName, string websiteName, string slot1, string slot2)
  940. {
  941. Debug.Assert(!string.IsNullOrEmpty(slot1));
  942. Debug.Assert(!string.IsNullOrEmpty(slot2));
  943. WebsiteManagementClient.WebSites.SwapSlots(webspaceName, websiteName, slot1, slot2);
  944. }
  945. /// <summary>
  946. /// Gets the slot name from the website name.
  947. /// </summary>
  948. /// <param name="name">The website name</param>
  949. /// <returns>The slot name</returns>
  950. public string GetSlotName(string name)
  951. {
  952. string slotName = null;
  953. if (!string.IsNullOrEmpty(name))
  954. {
  955. if (name.Contains('(') && name.Contains(')'))
  956. {
  957. string[] split = name.Split('(');
  958. slotName = split[1].TrimEnd(')').ToLower();
  959. }
  960. }
  961. return slotName;
  962. }
  963. /// <summary>
  964. /// Checks whether a website name is available or not.
  965. /// </summary>
  966. /// <param name="name">The website name</param>
  967. /// <returns>True means available, false otherwise</returns>
  968. public bool CheckWebsiteNameAvailability(string name)
  969. {
  970. return WebsiteManagementClient.WebSites.IsHostnameAvailable(name).IsAvailable;
  971. }
  972. #region WebDeploy
  973. /// <summary>
  974. /// Build a Visual Studio web project and generate a WebDeploy package.
  975. /// </summary>
  976. /// <param name="projectFile">The project file.</param>
  977. /// <param name="configuration">The configuration of the build, like Release or Debug.</param>
  978. /// <param name="logFile">The build log file if there is any error.</param>
  979. /// <returns>The full path of the generated WebDeploy package.</returns>
  980. public string BuildWebProject(string projectFile, string configuration, string logFile)
  981. {
  982. ProjectCollection pc = new ProjectCollection();
  983. Project project = pc.LoadProject(projectFile);
  984. // Use a file logger to store detailed build info.
  985. FileLogger fileLogger = new FileLogger();
  986. fileLogger.Parameters = string.Format("logfile={0}", logFile);
  987. fileLogger.Verbosity = LoggerVerbosity.Diagnostic;
  988. // Set the configuration used by MSBuild.
  989. project.SetProperty("Configuration", configuration);
  990. // Set this property use "managedRuntimeVersion=v4.0".
  991. // Otherwise, WebDeploy will fail becasue Azure Web Site is expecting v4.0.
  992. project.SetProperty("VisualStudioVersion", "11.0");
  993. // Build the project.
  994. var buildSucceed = project.Build("Package", new ILogger[] { fileLogger });
  995. if (buildSucceed)
  996. {
  997. // If build succeeds, delete the build.log file since there is no use of it.
  998. File.Delete(logFile);
  999. return Path.Combine(Path.GetDirectoryName(projectFile), "obj", configuration, "Package", Path.GetFileNameWithoutExtension(projectFile) + ".zip");
  1000. }
  1001. else
  1002. {
  1003. // If build fails, tell the user to look at the build.log file.
  1004. throw new Exception(string.Format(Resources.WebProjectBuildFailTemplate, logFile));
  1005. }
  1006. }
  1007. /// <summary>
  1008. /// Gets the website WebDeploy publish profile.
  1009. /// </summary>
  1010. /// <param name="websiteName">Website name.</param>
  1011. /// <param name="slot">Slot name. By default is null.</param>
  1012. /// <returns>The publish profile.</returns>
  1013. public WebSiteGetPublishProfileResponse.PublishProfile GetWebDeployPublishProfile(string websiteName, string slot = null)
  1014. {
  1015. var site = this.GetWebsite(websiteName);
  1016. var response = WebsiteManagementClient.WebSites.GetPublishProfile(site.WebSpace, SetWebsiteName(websiteName, slot));
  1017. foreach (var profile in response)
  1018. {
  1019. if (string.Compare(profile.PublishMethod, Resources.WebDeployKeywordInWebSitePublishProfile) == 0)
  1020. {
  1021. return profile;
  1022. }
  1023. }
  1024. return null;
  1025. }
  1026. /// <summary>
  1027. /// Publish a WebDeploy package folder to a web site.
  1028. /// </summary>
  1029. /// <param name="websiteName">The name of the web site.</param>
  1030. /// <param name="slot">The name of the slot.</param>
  1031. /// <param name="package">The WebDeploy package.</param>
  1032. /// <param name="connectionStrings">The connection strings to overwrite the ones in the Web.config file.</param>
  1033. public

Large files files are truncated, but you can click here to view the full file