PageRenderTime 57ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

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

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

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