Free cookie consent management tool by TermsFeed Policy Generator

source: branches/HeuristicLab.Hive.Azure/HeuristicLab.Clients.Hive.CloudManager/3.3/Views/AddAzureServiceDialog.cs @ 7661

Last change on this file since 7661 was 7661, checked in by spimming, 12 years ago

#1680: Show error dialog (from PluginInfrastructure) instead of message box on exception

File size: 21.8 KB
Line 
1using System;
2using System.Collections.Generic;
3using System.ComponentModel;
4using System.IO;
5using System.Net;
6using System.Text.RegularExpressions;
7using System.Windows.Forms;
8using HeuristicLab.Clients.Hive.CloudManager.Azure;
9using HeuristicLab.Clients.Hive.CloudManager.Model;
10using HeuristicLab.Core;
11using Microsoft.WindowsAzure;
12using Microsoft.WindowsAzure.StorageClient;
13
14namespace HeuristicLab.Clients.Hive.CloudManager.Views {
15  public partial class AddAzureServiceDialog : Form {
16    private BindingList<Subscription> subscriptions;
17    private BindingList<HostedService> hostedServices;
18    private BindingList<string> locations;
19    private BindingList<AffinityGroup> affinityGroups;
20    private BindingList<StorageService> storageServices;
21
22    private BackgroundWorker workerUpdate;
23    private BackgroundWorker workerCreate;
24
25    private bool isInitializing;
26    private bool bwCompleted;
27    private bool closePending;
28
29    private string certificateFile;
30    private string certificatePassword;
31
32    public AddAzureServiceDialog(IItemList<Subscription> subs) {
33      InitializeComponent();
34      isInitializing = true;
35      bwCompleted = true;
36
37      this.subscriptions = new BindingList<Subscription>(subs);
38      this.hostedServices = new BindingList<HostedService>();
39      this.locations = new BindingList<string>();
40      this.affinityGroups = new BindingList<AffinityGroup>();
41      this.storageServices = new BindingList<StorageService>();
42
43      SetLookupBinding(cmbLocation, locations, "", "");
44      SetLookupBinding(cmbAffinityGroup, affinityGroups, "Label", "Name");
45      SetLookupBinding(cmbChooseHostedService, hostedServices, "ServiceName", "ServiceName");
46      SetLookupBinding(cmbChooseSubscription, subscriptions, "SubscriptionName", "SubscriptionID");
47      SetLookupBinding(cmbStorageServices, storageServices, "ServiceName", "Url");
48
49      if (!cbNewHostedService.Checked) {
50        SetGroupBoxControlsEnabled(gbNewHostedService, cbNewHostedService.Checked);
51      }
52
53      certificateFile = string.Empty;
54      certificatePassword = string.Empty;
55
56      workerUpdate = new BackgroundWorker();
57      workerUpdate.DoWork += new DoWorkEventHandler(UpdateTask);
58      workerUpdate.RunWorkerCompleted += new RunWorkerCompletedEventHandler(WorkerCompleted);
59
60      workerCreate = new BackgroundWorker();
61      workerCreate.DoWork += new DoWorkEventHandler(CreateDeploymentTask);
62      workerCreate.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CreateDeploymentCompleted);
63
64      isInitializing = false;
65      cmbChooseSubscription_SelectedValueChanged(this, EventArgs.Empty);
66    }
67
68    protected override void OnFormClosing(FormClosingEventArgs e) {
69      if (!bwCompleted) {
70        SetAllControlsEnabled(this, false);
71        e.Cancel = true;
72        closePending = true;
73      }
74    }
75
76    private void SetLookupBinding(ListControl toBind, object dataSource, string displayMember, string valueMember) {
77      toBind.DisplayMember = displayMember;
78      toBind.ValueMember = valueMember;
79      toBind.DataSource = dataSource;
80    }
81
82    private void SetGroupBoxControlsEnabled(GroupBox gb, bool isEnabled) {
83      foreach (Control ctrl in gb.Controls) {
84        ctrl.Enabled = isEnabled;
85      }
86    }
87
88    private void SetAllControlsEnabled(Form frm, bool isEnabled) {
89      foreach (Control ctrl in frm.Controls) {
90        if (!(ctrl is ProgressBar)) {
91          ctrl.Enabled = isEnabled;
92        }
93      }
94    }
95
96    private void SetBindingList<T>(ref BindingList<T> bindinglist, List<T> list) {
97      if (list != null) {
98        BindingList<T> newList = new BindingList<T>(list);
99        bindinglist = newList;
100      }
101    }
102
103    private void UpdateBindingList<T>(BindingList<T> bindinglist, List<T> list) {
104      if (list != null) {
105        bindinglist.Clear();
106        foreach (T item in list)
107          bindinglist.Add(item);
108      }
109    }
110
111    private void UpdateSubscriptionItem(BindingList<Subscription> bindinglist, Subscription item) {
112      if (item != null) {
113        foreach (Subscription blItem in bindinglist)
114          if (blItem.Equals(item)) {
115            blItem.Merge(item);
116          }
117      }
118    }
119
120    private void cbNewHostedService_CheckedChanged(object sender, EventArgs e) {
121      if (cbNewHostedService.Checked) {
122        Subscription subscription = (Subscription)cmbChooseSubscription.SelectedItem;
123        if (subscription.CurrentHostedServices == subscription.MaxHostedServices) {
124          PluginInfrastructure.ErrorHandling.ShowErrorDialog(new Exception("You have already created the maximum number of hosted services"));
125          cbNewHostedService.Checked = false;
126        } else {
127          SetGroupBoxControlsEnabled(gbNewHostedService, cbNewHostedService.Checked);
128          cmbChooseHostedService.Enabled = false;
129        }
130      } else {
131        // checked == false
132        SetGroupBoxControlsEnabled(gbNewHostedService, false);
133        if (hostedServices.Count == 0) {
134          cbNewHostedService.Checked = true;
135        }
136      }
137    }
138
139    private void cmbChooseSubscription_SelectedValueChanged(object sender, EventArgs e) {
140      if (!isInitializing) {
141        Subscription item = (Subscription)cmbChooseSubscription.SelectedItem;
142        if (item != null) {
143          bwCompleted = false;
144          progressBar.Visible = true;
145          SetAllControlsEnabled(this, false);
146          workerUpdate.RunWorkerAsync(item);
147        }
148      }
149    }
150
151    private void btnAddCertificate_Click(object sender, EventArgs e) {
152      using (var form = new AddCertificate()) {
153        form.ShowDialog();
154        if (!form.ErrorOccured) {
155          certificateFile = form.CertificateFile;
156          certificatePassword = form.CertificatePassword;
157          lblCertificateFile.Text = certificateFile;
158        }
159      }
160    }
161
162    private void btnCancel_Click(object sender, EventArgs e) {
163      this.Close();
164    }
165
166    private void btnOk_Click(object sender, EventArgs e) {
167      if (cmbChooseSubscription.SelectedItem != null) {
168        Subscription sub = (Subscription)cmbChooseSubscription.SelectedItem;
169        // the controls collection can be the whole form or just a panel or group
170        if (Validation.hasValidationErrors(this.Controls)) {
171          return;
172        } else {
173          bool newHostedServiceChecked = cbNewHostedService.Checked;
174          bool regionChecked = rbRegion.Checked;
175          HostedService hostedService = null;
176          if (cbNewHostedService.Checked) {
177            hostedService = new HostedService();
178            hostedService.ServiceName = tbServiceName.Text;
179            HostedServiceProperties properties = new HostedServiceProperties();
180
181            if (regionChecked) {
182              properties.AffinityGroup = string.Empty;
183              properties.Location = (string)cmbLocation.SelectedItem;
184            } else {
185              properties.AffinityGroup = ((AffinityGroup)cmbAffinityGroup.SelectedItem).Name;
186              properties.Location = string.Empty;
187            }
188
189            if (cmbAffinityGroup.SelectedItem != null) {
190              properties.AffinityGroup = ((AffinityGroup)cmbAffinityGroup.SelectedItem).Name;
191            }
192            properties.Label = tbLabel.Text;
193            properties.Location = (string)cmbLocation.SelectedItem;
194            hostedService.HostedServiceProperties = properties;
195          } else {
196            hostedService = (HostedService)cmbChooseHostedService.SelectedItem;
197          }
198
199
200          string certFile = certificateFile;
201          string certPw = certificatePassword;
202          int instanceCount = Convert.ToInt32(tbInstanceCount.Text);
203
204
205
206          string packagefilepath = string.Empty;
207          if (rbVMSizeSmall.Checked) {
208            packagefilepath = Constants.DeploymentPackagePathSmall;
209          } else if (rbVMSizeMedium.Checked) {
210            packagefilepath = Constants.DeploymentPackagePathMedium;
211          } else if (rbVMSizeLarge.Checked) {
212            packagefilepath = Constants.DeploymentPackagePathLarge;
213          } else if (rbVMSizeExtraLarge.Checked) {
214            packagefilepath = Constants.DeploymentPackagePathExtraLarge;
215          }
216
217          string deploymentSlot = string.Empty;
218          if (rbDeployToProduction.Checked) {
219            deploymentSlot = Constants.DeploymentSlotProduction;
220          } else if (rbDeployToStaging.Checked) {
221            deploymentSlot = Constants.DeploymentSlotStaging;
222          }
223
224          //var parameters1 = Tuple.Create<Subscription, bool, bool, string, string, HostedService, int>
225          //  (sub, newHostedServiceChecked, regionChecked, certificateFile, certificatePassword, hostedService, instanceCount);
226          CreateDeploymentData parameters = new CreateDeploymentData();
227          parameters.Subscription = sub;
228          parameters.CreateNewHosteService = newHostedServiceChecked;
229          parameters.UseRegion = regionChecked;
230          parameters.CertificateFilePath = certificateFile;
231          parameters.CertificatePassword = certificatePassword;
232          parameters.HostedService = hostedService;
233          parameters.InstanceCount = instanceCount;
234          parameters.StorageService = (StorageService)cmbStorageServices.SelectedItem;
235          parameters.CreateContainerIfNotExists = cbCreateBlobIfNotExists.Checked;
236          parameters.BlobContainerName = tbBlobContainer.Text;
237          parameters.DeploymentPackageFilePath = packagefilepath;
238          parameters.DeploymentSlot = deploymentSlot;
239
240          bwCompleted = false;
241          progressBar.Visible = true;
242          SetAllControlsEnabled(this, false);
243          workerCreate.RunWorkerAsync(parameters);
244        }
245      }
246    }
247
248    private void UpdateTask(object sender, DoWorkEventArgs e) {
249      try {
250        Subscription item = (Subscription)e.Argument;
251        item = CloudManagerClient.Instance.AzureProvider.GetSubscriptionInfo(item.SubscriptionID, item.CertificateThumbprint);
252        this.Invoke((MethodInvoker)delegate { lblCores.Text = item.CurrentCoreCount + " / " + item.MaxCoreCount; });
253
254        List<HostedService> services = CloudManagerClient.Instance.AzureProvider.ListHostedServices(item);
255        List<string> locs = CloudManagerClient.Instance.AzureProvider.ListLocations(item);
256        List<AffinityGroup> groups = CloudManagerClient.Instance.AzureProvider.ListAffinityGroups(item);
257        List<StorageService> storage = CloudManagerClient.Instance.AzureProvider.ListStorageServices(item);
258
259        this.Invoke((MethodInvoker)delegate { UpdateSubscriptionItem(subscriptions, item); });
260        this.Invoke((MethodInvoker)delegate { UpdateBindingList<HostedService>(hostedServices, services); });
261        this.Invoke((MethodInvoker)delegate { UpdateBindingList<string>(locations, locs); });
262        this.Invoke((MethodInvoker)delegate { UpdateBindingList<AffinityGroup>(affinityGroups, groups); });
263        this.Invoke((MethodInvoker)delegate { UpdateBindingList<StorageService>(storageServices, storage); });
264      }
265      catch (Exception ex) {
266        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
267      }
268    }
269
270    private void WorkerCompleted(object sender, RunWorkerCompletedEventArgs e) {
271      SetAllControlsEnabled(this, true);
272      progressBar.Visible = false;
273      bwCompleted = true;
274      if (closePending) {
275        this.Close();
276      }
277    }
278
279    private void CreateDeploymentTask(object sender, DoWorkEventArgs e) {
280      bool errorOccured = false;
281      CreateDeploymentData parameters = (CreateDeploymentData)e.Argument;
282
283      Subscription sub = parameters.Subscription;
284      bool newHostedServiceChecked = parameters.CreateNewHosteService;
285      bool regionChecked = parameters.UseRegion;
286      string certFile = parameters.CertificateFilePath;
287      string certPw = parameters.CertificatePassword;
288      HostedService hostedService = parameters.HostedService;
289      int instanceCount = parameters.InstanceCount;
290      StorageService storageService = parameters.StorageService;
291      string blobContainerName = parameters.BlobContainerName;
292      bool createContainerIfNotExists = parameters.CreateContainerIfNotExists;
293      string packageFilePath = parameters.DeploymentPackageFilePath;
294      FileInfo packageFile = new FileInfo(packageFilePath);
295      string deploymentSlot = parameters.DeploymentSlot;
296
297      int defaultCollectionLimit = ServicePointManager.DefaultConnectionLimit;
298
299      CloudStorageAccount storageAccount = null; ;
300      CloudBlobClient blobClient = null;
301      CloudBlobContainer blobContainer = null;
302
303      // STEP 1 - Initialize storage account
304      try {
305        StorageServiceKeys keys = CloudManagerClient.Instance.AzureProvider.GetStorageKeys(sub, storageService.ServiceName);
306        storageAccount = CloudStorageAccount.Parse(string.Format(Constants.StorageServiceConnectionFormat, storageService.ServiceName, keys.Primary));
307        blobClient = storageAccount.CreateCloudBlobClient();
308        blobContainer = blobClient.GetContainerReference(blobContainerName);
309        if (createContainerIfNotExists) {
310          blobContainer.CreateIfNotExist();
311        } else {
312          if (!blobContainer.Exists()) {
313            throw new ApplicationException("Specified blob container doesn't exist.");
314          }
315        }
316      }
317      catch (Exception ex) {
318        errorOccured = true;
319        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
320      }
321
322      // STEP 2 - Copy service package file to storage account
323      CloudBlockBlob blobPackage = null;
324      try {
325        blobPackage = blobContainer.GetBlockBlobReference(packageFile.Name);
326        if (!blobPackage.Exists()) {
327          ServicePointManager.DefaultConnectionLimit = 64;
328          blobPackage.UploadParallel(packageFile.FullName);
329        }
330
331      }
332      catch (Exception ex) {
333        errorOccured = true;
334        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
335      }
336
337
338      // STEP 1 - Create Hosted Service
339      try {
340        if ((!errorOccured) && (newHostedServiceChecked)) {
341          if (regionChecked) {
342            CloudManagerClient.Instance.AzureProvider.CreateHostedService(sub, hostedService.ServiceName, hostedService.HostedServiceProperties.Label, hostedService.HostedServiceProperties.Description, hostedService.HostedServiceProperties.Location);
343          } else {
344            CloudManagerClient.Instance.AzureProvider.CreateHostedService(sub, hostedService.ServiceName, hostedService.HostedServiceProperties.Label, hostedService.HostedServiceProperties.Description, new AffinityGroup() { Name = hostedService.HostedServiceProperties.AffinityGroup });
345          }
346        }
347      }
348      catch (Exception ex) {
349        errorOccured = true;
350        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
351      }
352
353      // STEP 2 - Add Certificate
354      try {
355        if ((!errorOccured) && (certFile != string.Empty)) {
356          CloudManagerClient.Instance.AzureProvider.AddCertificate(sub, hostedService, certFile, certPw);
357        }
358      }
359      catch (Exception ex) {
360        errorOccured = true;
361        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
362        if (newHostedServiceChecked) {
363          CloudManagerClient.Instance.AzureProvider.DeleteHostedService(sub, hostedService.ServiceName);
364        }
365
366      }
367
368      // STEP 3 - Create Deployment
369      try {
370        if (!errorOccured) {
371          //CloudManagerClient.Instance.AzureProvider.CreateDeployment(sub, hostedService.ServiceName, Guid.NewGuid().ToString(), Constants.DeploymentSlotStaging, Constants.DeploymentPackageUrl, Constants.DeploymentConfigurationUrl, Constants.DeploymentLabel, instanceCount);
372          CloudManagerClient.Instance.AzureProvider.CreateDeployment(sub, hostedService.ServiceName, Guid.NewGuid().ToString(), deploymentSlot, blobPackage.Uri.ToString(), new FileInfo(Constants.DeploymentConfigurationPath), Constants.DeploymentLabel, instanceCount);
373        }
374      }
375      catch (Exception ex) {
376        errorOccured = true;
377        PluginInfrastructure.ErrorHandling.ShowErrorDialog(ex);
378        if (newHostedServiceChecked) {
379          CloudManagerClient.Instance.AzureProvider.DeleteHostedService(sub, hostedService.ServiceName);
380        }
381      }
382
383      ServicePointManager.DefaultConnectionLimit = defaultCollectionLimit;
384      e.Result = errorOccured;
385    }
386
387    private void CreateDeploymentCompleted(object sender, RunWorkerCompletedEventArgs e) {
388      SetAllControlsEnabled(this, true);
389      progressBar.Visible = false;
390      bwCompleted = true;
391      bool errorOccured = (bool)e.Result;
392      if (closePending) {
393        this.Close();
394      } else if (!errorOccured) {
395        this.Close();
396      } else {
397        this.Show();
398      }
399    }
400
401    private void tbServiceName_Validating(object sender, CancelEventArgs e) {
402      if (cbNewHostedService.Checked) {
403        string url = tbServiceName.Text.Trim();
404        if (url == String.Empty) {
405          errorProvider.SetError(tbServiceName, "A URL is required for the hosted service.");
406          e.Cancel = true;
407        } else if (!isValidHostedServiceUrl(url)) {
408          errorProvider.SetError(tbServiceName, "A hosted service name must be between 1 and 63 " +
409                                                "characters long, and be composed of letters, numbers " +
410                                                "and hyphens. Hyphens shouldn't be first or last letter.");
411          e.Cancel = true;
412        } else {
413          errorProvider.SetError(tbServiceName, "");
414        }
415      }
416    }
417
418    private void tbLabel_Validating(object sender, CancelEventArgs e) {
419      if (cbNewHostedService.Checked) {
420        if (tbLabel.Text.Trim() == String.Empty) {
421          errorProvider.SetError(tbLabel, "A name is required for the hosted service.");
422          e.Cancel = true;
423        } else {
424          errorProvider.SetError(tbLabel, "");
425        }
426      }
427    }
428
429    private bool isValidHostedServiceUrl(string url) {
430      string regexString = @"[a-zA-Z0-9]+[a-zA-Z0-9-]{0,61}[a-zA-Z0-9]+";  //TODO
431      Regex regex = new Regex(regexString);
432      if (regex.IsMatch(url)) {
433        return true;
434      } else {
435        return false;
436      }
437    }
438
439    private bool isValidStorageContainerName(string name) {
440      string regexString = @"[a-z0-9]+[a-z0-9-]{0,61}[a-z0-9]+";  //TODO
441      Regex regex = new Regex(regexString);
442      if (regex.IsMatch(name)) {
443        return true;
444      } else {
445        return false;
446      }
447    }
448
449    private void tbInstanceCount_Validating(object sender, CancelEventArgs e) {
450      if (!isValidInstanceCount(tbInstanceCount.Text)) {
451        errorProvider.SetError(tbInstanceCount, "Instance count must be a number greater than 0 and " +
452                                                 "less or equal than the difference between maximum and available cores.");
453        e.Cancel = true;
454      } else {
455        int instanceCount = Convert.ToInt32(tbInstanceCount.Text);
456        Subscription subscription = (Subscription)cmbChooseSubscription.SelectedItem;
457        if (instanceCount > subscription.MaxCoreCount - subscription.CurrentCoreCount) {
458          errorProvider.SetError(tbInstanceCount, "Instance count must be less or equal than the difference between maximum and available cores.");
459          e.Cancel = true;
460        } else {
461          errorProvider.SetError(tbInstanceCount, "");
462        }
463      }
464    }
465
466    private bool isValidInstanceCount(string text) {
467      string regexString = @"[1-9]+[0-9-]*";  //TODO
468      Regex regex = new Regex(regexString);
469      if (regex.IsMatch(text)) {
470        return true;
471      } else {
472        return false;
473      }
474    }
475
476    private void tbBlobContainer_Validating(object sender, CancelEventArgs e) {
477      string name = tbBlobContainer.Text.Trim();
478      if (name == string.Empty) {
479        errorProvider.SetError(tbBlobContainer, "A name is required for the blob container.");
480        e.Cancel = true;
481      } else if (!isValidStorageContainerName(name)) {
482        errorProvider.SetError(tbBlobContainer, "A blob container name must be between 1 and 63 " +
483                                              "characters long, and be composed of lowercase letters, numbers " +
484                                              "and hyphens. Hyphens shouldn't be first or last letter.");
485        e.Cancel = true;
486      } else {
487        errorProvider.SetError(tbBlobContainer, "");
488      }
489    }
490
491    private void cmbChooseHostedService_Validating(object sender, CancelEventArgs e) {
492      if ((!cbNewHostedService.Checked) && (cmbChooseHostedService.SelectedItem == null)) {
493        errorProvider.SetError(cmbChooseHostedService, "A hoste service is required.");
494        e.Cancel = true;
495      } else {
496        errorProvider.SetError(cmbChooseHostedService, "");
497      }
498    }
499
500    private void cmbStorageServices_Validating(object sender, CancelEventArgs e) {
501      if (cmbStorageServices.SelectedItem == null) {
502        errorProvider.SetError(cmbStorageServices, "A storage service is required.");
503        e.Cancel = true;
504      } else {
505        errorProvider.SetError(cmbStorageServices, "");
506      }
507    }
508
509    private class CreateDeploymentData {
510      public Subscription Subscription { get; set; }
511      public bool CreateNewHosteService { get; set; }
512      public bool UseRegion { get; set; }
513      public string CertificateFilePath { get; set; }
514      public string CertificatePassword { get; set; }
515      public HostedService HostedService { get; set; }
516      public int InstanceCount { get; set; }
517      public StorageService StorageService { get; set; }
518      public string BlobContainerName { get; set; }
519      public bool CreateContainerIfNotExists { get; set; }
520      public string DeploymentPackageFilePath { get; set; }
521      public string DeploymentSlot { get; set; }
522    }
523  }
524}
Note: See TracBrowser for help on using the repository browser.