PageRenderTime 55ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

https://github.com/1mahesh/azure-sdk-tools
C# | 1528 lines | 922 code | 166 blank | 440 comment | 74 complexity | 4a394ae1c63a1936df83bfd13203dfc6 MD5 | raw 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. private void PublishWebProjectFromPackagePath(string websiteName, string slot, string package, Hashtable connectionStrings)
  1048. {
  1049. DeploymentBaseOptions remoteBaseOptions = CreateRemoteDeploymentBaseOptions(websiteName, slot);
  1050. DeploymentBaseOptions localBaseOptions = new DeploymentBaseOptions();
  1051. using (var deployment = DeploymentManager.CreateObject(DeploymentWellKnownProvider.ContentPath, package, localBaseOptions))
  1052. {
  1053. ReplaceConnectionStrings(deployment, connectionStrings);
  1054. DeploymentSyncOptions syncOptions = new DeploymentSyncOptions();
  1055. deployment.SyncTo(DeploymentWellKnownProvider.ContentPath, SetWebsiteNameForWebDeploy(websiteName, slot), remoteBaseOptions, syncOptions);
  1056. }
  1057. }
  1058. /// <summary>
  1059. /// Parse the Web.config files to get the connection string names.
  1060. /// </summary>
  1061. /// <param name="defaultWebConfigFile">The default Web.config file.</param>
  1062. /// <param name="overwriteWebConfigFile">The additional Web.config file for the specificed configuration, like Web.Release.Config file.</param>
  1063. /// <returns>An array of connection string names from the Web.config files.</returns>
  1064. public string[] ParseConnectionStringNamesFromWebConfig(string defaultWebConfigFile, string overwriteWebConfigFile)
  1065. {
  1066. var names = new List<string>();
  1067. var webConfigFiles = new string[] { defaultWebConfigFile, overwriteWebConfigFile };
  1068. foreach (var file in webConfigFiles)
  1069. {
  1070. XDocument xdoc = XDocument.Load(file);
  1071. names.AddRange(xdoc.Descendants("connectionStrings").SelectMany(css => css.Descendants("add")).Select(add => add.Attribute("name").Value));
  1072. }
  1073. return names.Distinct().ToArray<string>();
  1074. }
  1075. /// <summary>
  1076. /// Create remote deployment base options using the web site publish profile.
  1077. /// </summary>
  1078. /// <returns>The remote deployment base options.</returns>
  1079. private DeploymentBaseOptions CreateRemoteDeploymentBaseOptions(string websiteName, string slot)
  1080. {
  1081. // Get the web site publish profile.
  1082. var publishProfile = GetWebDeployPublishProfile(websiteName, slot);
  1083. DeploymentBaseOptions remoteBaseOptions = new DeploymentBaseOptions()
  1084. {
  1085. UserName = publishProfile.UserName,
  1086. Password = publishProfile.UserPassword,
  1087. ComputerName = string.Format(Resources.WebSiteWebDeployUriTemplate, publishProfile.PublishUrl, SetWebsiteNameForWebDeploy(websiteName, slot)),
  1088. AuthenticationType = "Basic",
  1089. TempAgent = false
  1090. };
  1091. return remoteBaseOptions;
  1092. }
  1093. /// <summary>
  1094. /// Replace all the connection strings in the deployment.
  1095. /// </summary>
  1096. /// <param name="deployment">The deployment object.</param>
  1097. /// <param name="connectionStrings">Connection strings.</param>
  1098. private void ReplaceConnectionStrings(DeploymentObject deployment, Hashtable connectionStrings)
  1099. {
  1100. if (connectionStrings != null)
  1101. {
  1102. foreach (var key in connectionStrings.Keys)
  1103. {
  1104. AddConnectionString(deployment, key.ToString(), connectionStrings[key].ToString());
  1105. }
  1106. }
  1107. }
  1108. /// <summary>
  1109. /// Add a connection string parameter to the deployment.
  1110. /// </summary>
  1111. /// <param name="deployment">The deployment object.</param>
  1112. /// <param name="name">Connection string name.</param>
  1113. /// <param name="value">Connection string value.</param>
  1114. private void AddConnectionString(DeploymentObject deployment, string name, string value)
  1115. {
  1116. var deploymentSyncParameterName = string.Format("Connection String {0} Parameter", name);
  1117. DeploymentSyncParameter connectionStringParameter = new DeploymentSyncParameter(
  1118. deploymentSyncParameterName,
  1119. deploymentSyncParameterName,
  1120. value,
  1121. null);
  1122. DeploymentSyncParameterEntry connectionStringEntry = new DeploymentSyncParameterEntry(
  1123. DeploymentSyncParameterEntryKind.XmlFile,
  1124. @"\\web.config$",
  1125. string.Format(@"//connectionStrings/add[@name='{0}']/@connectionString", name),
  1126. null);
  1127. connectionStringParameter.Add(connectionStringEntry);
  1128. deployment.SyncParameters.Add(connectionStringParameter);
  1129. }
  1130. #endregion WebDeploy
  1131. #region WebJobs
  1132. /// <summary>
  1133. /// Filters the web jobs.
  1134. /// </summary>
  1135. /// <param name="options">The web job filter options</param>
  1136. /// <returns>The filtered web jobs list</returns>
  1137. public List<PSWebJob> FilterWebJobs(WebJobFilterOptions options)
  1138. {
  1139. options.Name = SetWebsiteName(options.Name, options.Slot);
  1140. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(options.Name);
  1141. List<WebJob> jobList = new List<WebJob>();
  1142. if (string.IsNullOrEmpty(options.JobName) && string.IsNullOrEmpty(options.JobType))
  1143. {
  1144. jobList = client.WebJobs.List(new WebJobListParameters()).Jobs.ToList();
  1145. }
  1146. else if (string.IsNullOrEmpty(options.JobName) && !string.IsNullOrEmpty(options.JobType))
  1147. {
  1148. if (string.Compare(options.JobType, WebJobType.Continuous.ToString(), true) == 0)
  1149. {
  1150. jobList = client.WebJobs.ListContinuous(new WebJobListParameters()).Jobs.ToList();
  1151. }
  1152. else if (string.Compare(options.JobType, WebJobType.Triggered.ToString(), true) == 0)
  1153. {
  1154. jobList = client.WebJobs.ListTriggered(new WebJobListParameters()).Jobs.ToList();
  1155. }
  1156. else
  1157. {
  1158. throw new ArgumentOutOfRangeException("JobType");
  1159. }
  1160. }
  1161. else if (!string.IsNullOrEmpty(options.JobName) && !string.IsNullOrEmpty(options.JobType))
  1162. {
  1163. if (string.Compare(options.JobType, WebJobType.Continuous.ToString(), true) == 0)
  1164. {
  1165. jobList = new List<WebJob>() { client.WebJobs.GetContinuous(options.JobName).WebJob };
  1166. }
  1167. else if (string.Compare(options.JobType, WebJobType.Triggered.ToString(), true) == 0)
  1168. {
  1169. jobList = new List<WebJob>() { client.WebJobs.GetTriggered(options.JobName).WebJob };
  1170. }
  1171. else
  1172. {
  1173. throw new ArgumentOutOfRangeException("JobType");
  1174. }
  1175. }
  1176. else
  1177. {
  1178. if (string.IsNullOrEmpty(options.JobName))
  1179. {
  1180. throw new ArgumentOutOfRangeException("JobName");
  1181. }
  1182. else if (string.IsNullOrEmpty(options.JobType))
  1183. {
  1184. throw new ArgumentOutOfRangeException("JobType");
  1185. }
  1186. else
  1187. {
  1188. throw new ArgumentOutOfRangeException("options");
  1189. }
  1190. }
  1191. List<PSWebJob> result = new List<PSWebJob>();
  1192. foreach (WebJob job in jobList)
  1193. {
  1194. result.Add(new PSWebJob(job));
  1195. }
  1196. return result;
  1197. }
  1198. /// <summary>
  1199. /// Creates new web job for a website
  1200. /// </summary>
  1201. /// <param name="name">The website name</param>
  1202. /// <param name="slot">The website slot name</param>
  1203. /// <param name="jobName">The web job name</param>
  1204. /// <param name="jobType">The web job type</param>
  1205. /// <param name="jobFile">The web job file name</param>
  1206. public PSWebJob CreateWebJob(string name, string slot, string jobName, WebJobType jobType, string jobFile)
  1207. {
  1208. WebJobFilterOptions options = new WebJobFilterOptions() { Name = name, Slot = slot, JobName = jobName, JobType = jobType.ToString() };
  1209. name = SetWebsiteName(name, slot);
  1210. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(name);
  1211. if (Path.GetExtension(jobFile).ToLower() != ".zip")
  1212. {
  1213. throw new InvalidOperationException(Resources.InvalidWebJobFile);
  1214. }
  1215. switch (jobType)
  1216. {
  1217. case WebJobType.Continuous:
  1218. client.WebJobs.UploadContinuous(jobName, File.OpenRead(jobFile));
  1219. break;
  1220. case WebJobType.Triggered:
  1221. client.WebJobs.UploadTriggered(jobName, File.OpenRead(jobFile));
  1222. break;
  1223. default:
  1224. break;
  1225. }
  1226. PSWebJob webjob = null;
  1227. Thread.Sleep(UploadJobWaitTime);
  1228. try
  1229. {
  1230. webjob = FilterWebJobs(options).FirstOrDefault();
  1231. }
  1232. catch (CloudException e)
  1233. {
  1234. if (e.Response.StatusCode == HttpStatusCode.NotFound)
  1235. {
  1236. throw new ArgumentException(Resources.InvalidJobFile);
  1237. }
  1238. }
  1239. return webjob;
  1240. }
  1241. /// <summary>
  1242. /// Deletes a web job for a website.
  1243. /// </summary>
  1244. /// <param name="name">The website name</param>
  1245. /// <param name="slot">The slot name</param>
  1246. /// <param name="jobName">The web job name</param>
  1247. /// <param name="jobType">The web job type</param>
  1248. public void DeleteWebJob(string name, string slot, string jobName, WebJobType jobType)
  1249. {
  1250. name = SetWebsiteName(name, slot);
  1251. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(name);
  1252. if (jobType == WebJobType.Continuous)
  1253. {
  1254. client.WebJobs.DeleteContinuous(jobName, true);
  1255. }
  1256. else if (jobType == WebJobType.Triggered)
  1257. {
  1258. client.WebJobs.DeleteTriggered(jobName, true);
  1259. }
  1260. else
  1261. {
  1262. throw new ArgumentException("jobType");
  1263. }
  1264. }
  1265. /// <summary>
  1266. /// Starts a web job in a website.
  1267. /// </summary>
  1268. /// <param name="name">The website name</param>
  1269. /// <param name="slot">The slot name</param>
  1270. /// <param name="jobName">The web job name</param>
  1271. /// <param name="jobType">The web job type</param>
  1272. public void StartWebJob(string name, string slot, string jobName, WebJobType jobType)
  1273. {
  1274. name = SetWebsiteName(name, slot);
  1275. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(name);
  1276. if (jobType == WebJobType.Continuous)
  1277. {
  1278. client.WebJobs.StartContinuous(jobName);
  1279. }
  1280. else
  1281. {
  1282. client.WebJobs.RunTriggered(jobName);
  1283. }
  1284. }
  1285. /// <summary>
  1286. /// Stops a web job in a website.
  1287. /// </summary>
  1288. /// <param name="name">The website name</param>
  1289. /// <param name="slot">The slot name</param>
  1290. /// <param name="jobName">The web job name</param>
  1291. /// <param name="jobType">The web job type</param>
  1292. public void StopWebJob(string name, string slot, string jobName, WebJobType jobType)
  1293. {
  1294. name = SetWebsiteName(name, slot);
  1295. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(name);
  1296. if (jobType == WebJobType.Continuous)
  1297. {
  1298. client.WebJobs.StopContinuous(jobName);
  1299. }
  1300. else
  1301. {
  1302. throw new InvalidOperationException();
  1303. }
  1304. }
  1305. /// <summary>
  1306. /// Filters a web job history.
  1307. /// </summary>
  1308. /// <param name="options">The web job filter options</param>
  1309. /// <returns>The filtered web jobs run list</returns>
  1310. public List<WebJobRun> FilterWebJobHistory(WebJobHistoryFilterOptions options)
  1311. {
  1312. options.Name = SetWebsiteName(options.Name, options.Slot);
  1313. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(options.Name);
  1314. List<WebJobRun> result = new List<WebJobRun>();
  1315. if (options.Latest)
  1316. {
  1317. result.Add(client.WebJobs.GetTriggered(options.JobName).WebJob.LatestRun);
  1318. }
  1319. else if (!string.IsNullOrEmpty(options.RunId))
  1320. {
  1321. result.Add(client.WebJobs.GetRun(options.JobName, options.RunId).JobRun);
  1322. }
  1323. else
  1324. {
  1325. result.AddRange(client.WebJobs.ListRuns(options.JobName, new WebJobRunListParameters()));
  1326. }
  1327. return result;
  1328. }
  1329. /// <summary>
  1330. /// Saves a web job logs to file.
  1331. /// </summary>
  1332. /// <param name="name">The website name</param>
  1333. /// <param name="slot">The slot name</param>
  1334. /// <param name="jobName">The web job name</param>
  1335. /// <param name="jobType">The web job type</param>
  1336. /// <param name="output">The output file name</param>
  1337. /// <param name="runId">The job run id</param>
  1338. public void SaveWebJobLog(string name, string slot, string jobName, WebJobType jobType, string output, string runId)
  1339. {
  1340. if (jobType == WebJobType.Continuous && !string.IsNullOrEmpty(runId))
  1341. {
  1342. throw new InvalidOperationException();
  1343. }
  1344. name = SetWebsiteName(name, slot);
  1345. IWebSiteExtensionsClient client = GetWebSiteExtensionsClient(name);
  1346. throw new NotImplementedException();
  1347. }
  1348. /// <summary>
  1349. /// Saves a web job logs to file.
  1350. /// </summary>
  1351. /// <param name="name">The website name</param>
  1352. /// <param name="slot">The slot name</param>
  1353. /// <param name="jobName">The web job name</param>
  1354. /// <param name="jobType">The web job type</param>
  1355. public void SaveWebJobLog(string name, string slot, string jobName, WebJobType jobType)
  1356. {
  1357. const string defaultLogFile = ".\\jobLog.zip";
  1358. SaveWebJobLog(name, slot, jobName, jobType, defaultLogFile, null);
  1359. }
  1360. #endregion WebJobs
  1361. }
  1362. }