Free cookie consent management tool by TermsFeed Policy Generator

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

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

#1680:

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