private async Task UpdateInstancePortsAsyncImpl( GceOperation pendingOperation, Instance instance, IList <FirewallPort> portsToEnable, IList <FirewallPort> portsToDisable) { try { s_pendingOperations.Add(pendingOperation); // 1) Ensure that the firewall rules for the ports to be enabled are present. await EnsureFirewallRules(portsToEnable); // 2) Update the tags for the instance. var tagsToAdd = portsToEnable.Select(x => x.Name); var tagsToRemove = portsToDisable.Select(x => x.Name); var instanceTags = instance.Tags?.Items ?? Enumerable.Empty <string>(); var tagsOperation = SetInstanceTags( instance, instanceTags.Except(tagsToRemove).Union(tagsToAdd).ToList()); await tagsOperation.OperationTask; } finally { s_pendingOperations.Remove(pendingOperation); } }
private Task SetInstanceTagsAsyncImpl(GceOperation pendingOperation, Instance instance, IList <string> tags) => RegisterPendingOperation(pendingOperation, () => { var newTags = new Tags { Items = tags, Fingerprint = instance.Tags.Fingerprint, }; return(Service.Instances.SetTags(newTags, ProjectId, instance.GetZoneName(), instance.Name).ExecuteAsync()); });
/// <summary> /// Sets the tags for a GCE instance to <paramref name="tags"/>. The task wrapped by the operation will throw /// if the list of tags was modified already, and the fingerprint for the tags doesn't match. /// </summary> /// <param name="instance">The instance to modify.</param> /// <param name="tags">The tags to set.</param> /// <returns>The operation.</returns> public GceOperation SetInstanceTags(Instance instance, IList <string> tags) { var operation = new GceOperation( operationType: OperationType.SettingTags, projectId: ProjectId, zoneName: instance.GetZoneName(), name: instance.Name); operation.OperationTask = SetInstanceTagsAsyncImpl(operation, instance, tags); return(operation); }
/// <summary> /// Starts an instance in the current project, given its <paramref name="zoneName"/> and <paramref name="name"/>. /// </summary> /// <param name="zoneName">The zone where the instance is located.</param> /// <param name="name">The name of the instance.</param> /// <returns>The new pending operation.</returns> public GceOperation StartInstance(string zoneName, string name) { var operation = new GceOperation( operationType: OperationType.StartInstance, projectId: ProjectId, zoneName: zoneName, name: name); operation.OperationTask = StartInstanceImplAsync(operation, zoneName, name); return(operation); }
/// <summary> /// Updates the instance ports, enables the <paramref name="portsToEnable"/> and disables the /// ports in <paramref name="portsToDisable"/>. /// </summary> /// <param name="instance">The instance to modify.</param> /// <param name="portsToEnable">The list of ports to enable.</param> /// <param name="portsToDisable">The list of ports to disable.</param> /// <returns>The operation.</returns> public GceOperation UpdateInstancePorts( Instance instance, IList <FirewallPort> portsToEnable, IList <FirewallPort> portsToDisable) { var operation = new GceOperation( OperationType.ModifyingFirewall, ProjectId, instance.GetZoneName(), instance.Name); operation.OperationTask = UpdateInstancePortsAsyncImpl(operation, instance, portsToEnable, portsToDisable); return(operation); }
private async Task RegisterPendingOperation(GceOperation pendingOperation, Func <Task <Operation> > operationFactory) { try { var operation = await operationFactory(); s_pendingOperations.Add(pendingOperation); await WaitAsync(operation); } catch (GoogleApiException ex) { Debug.WriteLine($"Failed to call api: {ex.Message}"); throw new DataSourceException(ex.Message, ex); } finally { s_pendingOperations.Remove(pendingOperation); } }
/// <summary> /// Stores the given operation in the pending operations list as the operation for this API call /// and performs the API call to stop the instance. /// </summary> /// <param name="pendingOperation">The operation to use for this API call.</param> /// <param name="zoneName">The zone where the instance is localed.</param> /// <param name="name">The name of the instance.</param> /// <returns>The task that will be completed when the API call is complete, including the cleanup.</returns> private Task StartInstanceImplAsync(GceOperation pendingOperation, string zoneName, string name) => RegisterPendingOperation(pendingOperation, () => Service.Instances.Start(ProjectId, zoneName, name).ExecuteAsync());
private async void UpdateInstanceState(GceOperation pendingOperation) { while (pendingOperation != null && !pendingOperation.OperationTask.IsCompleted) { // Since there's a pending operation the loading state needs to be set to show // progress ui. IsLoading = true; // Setting the content according to the operation type. switch (pendingOperation.OperationType) { case OperationType.StartInstance: Caption = String.Format(Resources.CloudExplorerGceInstanceStartingCaption, Instance.Name); break; case OperationType.StopInstance: Caption = String.Format(Resources.CloudExplorerGceInstanceStoppingCaption, Instance.Name); break; case OperationType.SettingTags: Caption = String.Format(Resources.CloudExplorerGceInstanceSettingTagsCaption, Instance.Name); break; case OperationType.ModifyingFirewall: Caption = String.Format(Resources.CloudExplorerGceInstanceUpdatingFirewallCaption, Instance.Name); break; } // Update the context menu to reflect the state. UpdateContextMenu(); try { // Await the end of the task. We can also get here if the task is faulted, // in which case we need to handle that case. while (true) { // Refresh the instance before waiting for the operation to finish. Instance = await _owner.DataSource.RefreshInstance(Instance); // Wait for the operation to finish up to the timeout, which we will use to refresh the // state of the instance. var result = await Task.WhenAny(pendingOperation.OperationTask, Task.Delay(s_pollTimeout)); if (result == pendingOperation.OperationTask) { // Await the task again to get any possible exception. await pendingOperation.OperationTask; break; } } // Refresh the instance state after the operation is finished. Instance = await _owner.DataSource.RefreshInstance(Instance); } catch (DataSourceException ex) { Caption = Instance.Name; IsLoading = false; IsError = true; UpdateContextMenu(); Debug.WriteLine($"Previous operation failed."); switch (pendingOperation.OperationType) { case OperationType.StartInstance: GcpOutputWindow.OutputLine(String.Format(Resources.CloudExplorerGceStartOperationFailedMessage, Instance.Name, ex.Message)); break; case OperationType.StopInstance: GcpOutputWindow.OutputLine(String.Format(Resources.CloudExplorerGceStopOperationFailedMessage, Instance.Name, ex.Message)); break; } // Permanent error. return; } // See if there are more operations. pendingOperation = _owner.DataSource.GetPendingOperation(Instance); } // Normal state, no pending operations. IsLoading = false; Caption = Instance.Name; UpdateContextMenu(); }