public async Task CreateDeploymentTest( string deploymentName, string deviceGroupId, string deviceGroupQuery, string packageContent, int priority, string expectedException) { // Arrange var depModel = new DeploymentServiceModel() { Name = deploymentName, DeviceGroupId = deviceGroupId, DeviceGroupQuery = deviceGroupQuery, PackageContent = packageContent, PackageType = PackageType.EdgeManifest, Priority = priority, }; var newConfig = new Configuration("test-config") { Labels = new Dictionary <string, string>() { { DeploymentNameLabel, deploymentName }, { this.packageTypeLabel, PackageType.EdgeManifest.ToString() }, { DeploymentGroupIdLabel, deviceGroupId }, { RmCreatedLabel, bool.TrueString }, }, Priority = priority, }; this.registry.Setup(r => r.AddConfigurationAsync(It.Is <Configuration>(c => c.Labels.ContainsKey(DeploymentNameLabel) && c.Labels.ContainsKey(DeploymentGroupIdLabel) && c.Labels.ContainsKey(RmCreatedLabel) && c.Labels[DeploymentNameLabel] == deploymentName && c.Labels[DeploymentGroupIdLabel] == deviceGroupId && c.Labels[RmCreatedLabel] == bool.TrueString))) .ReturnsAsync(newConfig); this.tenantHelper.Setup(e => e.GetRegistry()).Returns(this.registry.Object); // Act if (string.IsNullOrEmpty(expectedException)) { var createdDeployment = await this.deployments.CreateAsync(depModel); // Assert Assert.False(string.IsNullOrEmpty(createdDeployment.Id)); Assert.Equal(deploymentName, createdDeployment.Name); Assert.Equal(deviceGroupId, createdDeployment.DeviceGroupId); Assert.Equal(priority, createdDeployment.Priority); } else { await Assert.ThrowsAsync( Type.GetType(expectedException), async() => await this.deployments.CreateAsync(depModel)); } }
/// <summary> /// Schedules a deployment of the provided package, to the given group. /// </summary> /// <returns>Scheduled deployment</returns> public async Task <DeploymentServiceModel> CreateAsync(DeploymentServiceModel model) { if (string.IsNullOrEmpty(model.DeviceGroupId)) { throw new ArgumentNullException(DEVICE_GROUP_ID_PARAM); } if (string.IsNullOrEmpty(model.DeviceGroupQuery)) { throw new ArgumentNullException(DEVICE_GROUP_QUERY_PARAM); } if (string.IsNullOrEmpty(model.Name)) { throw new ArgumentNullException(NAME_PARAM); } if (string.IsNullOrEmpty(model.PackageContent)) { throw new ArgumentNullException(PACKAGE_CONTENT_PARAM); } if (model.Priority < 0) { throw new ArgumentOutOfRangeException(PRIORITY_PARAM, model.Priority, "The priority provided should be 0 or greater"); } var edgeConfiguration = this.CreateEdgeConfiguration(model); // TODO: Add specific exception handling when exception types are exposed // https://github.com/Azure/azure-iot-sdk-csharp/issues/649 return(new DeploymentServiceModel(await this.registry.AddConfigurationAsync(edgeConfiguration))); }
public DeploymentApiModel(DeploymentServiceModel serviceModel) { this.CreatedDateTimeUtc = serviceModel.CreatedDateTimeUtc; this.DeploymentId = serviceModel.Id; this.DeviceGroupId = serviceModel.DeviceGroupId; this.DeviceGroupName = serviceModel.DeviceGroupName; this.DeviceGroupQuery = serviceModel.DeviceGroupQuery; this.Name = serviceModel.Name; this.PackageContent = serviceModel.PackageContent; this.PackageName = serviceModel.PackageName; this.PackageId = serviceModel.PackageId; this.Priority = serviceModel.Priority; this.PackageType = serviceModel.PackageType; this.ConfigType = serviceModel.ConfigType; this.IsActive = !(serviceModel.Tags != null && serviceModel.Tags.Contains(InActiveTag)); this.IsLatest = serviceModel.Tags != null && serviceModel.Tags.Contains(LatestTag); this.Metrics = new DeploymentMetricsApiModel(serviceModel.DeploymentMetrics) { DeviceStatuses = serviceModel.DeploymentMetrics?.DeviceStatuses, }; this.Metadata = new Dictionary <string, string> { { "$type", $"DevicePropertyList;1" }, { "$url", $"/v1/deviceproperties" }, }; this.CreatedDate = serviceModel.CreatedDate; this.CreatedBy = serviceModel.CreatedBy; this.ModifiedDate = serviceModel.ModifiedDate; this.ModifiedBy = serviceModel.ModifiedBy; }
public static Configuration ToHubConfiguration(DeploymentServiceModel model) { var packageConfiguration = JsonConvert.DeserializeObject <Configuration>(model.PackageContent); if (model.PackageType.Equals(PackageType.EdgeManifest) && packageConfiguration.Content?.DeviceContent != null) { throw new InvalidInputException("Deployment type does not match with package contents."); } else if (model.PackageType.Equals(PackageType.DeviceConfiguration) && packageConfiguration.Content?.ModulesContent != null) { throw new InvalidInputException("Deployment type does not match with package contents."); } var deploymentId = Guid.NewGuid().ToString().ToLower(); var configuration = new Configuration(deploymentId); configuration.Content = packageConfiguration.Content; var targetCondition = QueryConditionTranslator.ToQueryString(model.DeviceGroupQuery); configuration.TargetCondition = string.IsNullOrEmpty(targetCondition) ? "*" : targetCondition; configuration.Priority = model.Priority; configuration.ETag = string.Empty; configuration.Labels = packageConfiguration.Labels ?? new Dictionary <string, string>(); // Required labels configuration.Labels[PACKAGE_TYPE_LABEL] = model.PackageType.ToString(); configuration.Labels[DEPLOYMENT_NAME_LABEL] = model.Name; configuration.Labels[DEPLOYMENT_GROUP_ID_LABEL] = model.DeviceGroupId; configuration.Labels[RM_CREATED_LABEL] = bool.TrueString; if (!String.IsNullOrEmpty(model.ConfigType)) { configuration.Labels[CONFIG_TYPE_LABEL] = model.ConfigType; } var customMetrics = packageConfiguration.Metrics?.Queries; if (customMetrics != null) { configuration.Metrics.Queries = SubstituteDeploymentIdIfPresent( customMetrics, deploymentId); } // Add optional labels if (model.DeviceGroupName != null) { configuration.Labels[DEPLOYMENT_GROUP_NAME_LABEL] = model.DeviceGroupName; } if (model.PackageName != null) { configuration.Labels[DEPLOYMENT_PACKAGE_NAME_LABEL] = model.PackageName; } return(configuration); }
public async Task VerifyGroupAndPackageNameLabelsTest() { // Arrange var deviceGroupId = "dvcGroupId"; var deviceGroupName = "dvcGroupName"; var deviceGroupQuery = "dvcGroupQuery"; var packageName = "packageName"; var deploymentName = "depName"; var priority = 10; var userid = "testUser"; var tenantId = "testTenant"; var depModel = new DeploymentServiceModel() { Name = deploymentName, DeviceGroupId = deviceGroupId, DeviceGroupName = deviceGroupName, DeviceGroupQuery = deviceGroupQuery, PackageContent = TestEdgePackageJson, PackageName = packageName, Priority = priority, }; var newConfig = new Configuration("test-config") { Labels = new Dictionary <string, string>() { { this.packageTypeLabel, PackageType.EdgeManifest.ToString() }, { DeploymentNameLabel, deploymentName }, { DeploymentGroupIdLabel, deviceGroupId }, { RmCreatedLabel, bool.TrueString }, { DeploymentGroupNameLabel, deviceGroupName }, { DeploymentPackageNameLabel, packageName }, }, Priority = priority, }; this.registry.Setup(r => r.AddConfigurationAsync(It.Is <Configuration>(c => c.Labels.ContainsKey(DeploymentNameLabel) && c.Labels.ContainsKey(DeploymentGroupIdLabel) && c.Labels.ContainsKey(RmCreatedLabel) && c.Labels[DeploymentNameLabel] == deploymentName && c.Labels[DeploymentGroupIdLabel] == deviceGroupId && c.Labels[RmCreatedLabel] == bool.TrueString))) .ReturnsAsync(newConfig); this.tenantHelper.Setup(e => e.GetRegistry()).Returns(this.registry.Object); // Act var createdDeployment = await this.deployments.CreateAsync(depModel, userid, tenantId); // Assert Assert.False(string.IsNullOrEmpty(createdDeployment.Id)); Assert.Equal(deploymentName, createdDeployment.Name); Assert.Equal(deviceGroupId, createdDeployment.DeviceGroupId); Assert.Equal(priority, createdDeployment.Priority); Assert.Equal(deviceGroupName, createdDeployment.DeviceGroupName); Assert.Equal(packageName, createdDeployment.PackageName); }
public async Task <DeploymentServiceModel> GetAsync(string deploymentId, bool includeDeviceStatus = false, bool isLatest = true) { if (string.IsNullOrEmpty(deploymentId)) { throw new ArgumentNullException(nameof(deploymentId)); } DeploymentServiceModel deployment = await this.GetDeploymentFromStorageAsync(deploymentId, true); isLatest = deployment.Tags.Contains(LatestTag); if (isLatest) { var deploymentFromHub = await this.tenantHelper.GetRegistry().GetConfigurationAsync(deploymentId); if (deploymentFromHub == null) { throw new ResourceNotFoundException($"Deployment with id {deploymentId} not found."); } if (!this.CheckIfDeploymentWasMadeByRM(deploymentFromHub)) { throw new ResourceNotSupportedException($"Deployment with id {deploymentId}" + @" was created externally and therefore not supported"); } IDictionary <string, DeploymentStatus> deviceStatuses = this.GetDeviceStatuses(deploymentFromHub); return(new DeploymentServiceModel(deploymentFromHub) { DeploymentMetrics = { DeviceMetrics = this.CalculateDeviceMetrics(deviceStatuses), DeviceStatuses = includeDeviceStatus ? deviceStatuses : null, }, Tags = new List <string>() { LatestTag }, }); } else { if (deployment != null && deployment.DeploymentMetrics != null) { deployment.PackageContent = null; if (deployment.DeploymentMetrics.DeviceStatuses == null) { deployment.DeploymentMetrics.DeviceStatuses = new Dictionary <string, DeploymentStatus>(); } deployment.DeploymentMetrics.DeviceMetrics = this.CalculateDeviceMetrics(deployment.DeploymentMetrics.DeviceStatuses); deployment.DeploymentMetrics.DeviceStatuses = includeDeviceStatus ? deployment.DeploymentMetrics.DeviceStatuses : null; } return(deployment); } }
private async Task <bool> UpdateMetricsOfCurrentDeployment(string deviceGroupId, int priority) { var deploymentsFromHub = await this.ListAsync(); var deploymentsOfDeviceGroup = deploymentsFromHub.Items.Where(i => i.DeviceGroupId == deviceGroupId).OrderByDescending(p => p.Priority).ThenByDescending(q => q.CreatedDateTimeUtc); if (deploymentsOfDeviceGroup != null && deploymentsOfDeviceGroup.Count() > 0) { var deployment = deploymentsOfDeviceGroup.First(); if (priority >= deployment.Priority) { var deploymentDetails = await this.GetDeploymentAsync(deployment.Id); DeploymentServiceModel currentDeployment = await this.GetDeploymentFromStorageAsync(deployment.Id); // Update the Device Statuses for the DeploymentId for future references. currentDeployment.DeploymentMetrics = new DeploymentMetricsServiceModel(deploymentDetails.SystemMetrics, deploymentDetails.Metrics); currentDeployment.DeploymentMetrics.DeviceStatuses = this.GetDeviceStatuses(deploymentDetails); var deviceTwins = await this.GetDeviceProperties(currentDeployment.DeploymentMetrics.DeviceStatuses.Keys); // Since the deployment that will be created have highest priority, remove latest tag on current deployment if (currentDeployment?.Tags != null) { var existingTag = currentDeployment.Tags.FirstOrDefault(t => t.Equals(LatestTag, StringComparison.OrdinalIgnoreCase)); if (existingTag != null) { currentDeployment.Tags.Remove(existingTag); } } var value = JsonConvert.SerializeObject( currentDeployment, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); await this.client.UpdateAsync(DeploymentsCollection, currentDeployment.Id, value, currentDeployment.ETag); await this.StoreDevicePropertiesInStorage(deviceTwins, currentDeployment.Id); // Since the deployment that will be created have highest priority, mark it as the latest return(true); } else { return(false); } } return(true); }
public async Task VerifyGroupAndPackageNameLabelsTest() { // Arrange var deviceGroupId = "dvcGroupId"; var deviceGroupName = "dvcGroupName"; var deviceGroupQuery = "dvcGroupQuery"; var packageName = "packageName"; var deploymentName = "depName"; var priority = 10; var depModel = new DeploymentServiceModel() { Name = deploymentName, DeviceGroupId = deviceGroupId, DeviceGroupName = deviceGroupName, DeviceGroupQuery = deviceGroupQuery, PackageContent = TEST_EDGE_PACKAGE_JSON, PackageName = packageName, Priority = priority }; var newConfig = new Configuration("test-config") { Labels = new Dictionary <string, string>() { { PACKAGE_TYPE_LABEL, PackageType.EdgeManifest.ToString() }, { DEPLOYMENT_NAME_LABEL, deploymentName }, { DEPLOYMENT_GROUP_ID_LABEL, deviceGroupId }, { RM_CREATED_LABEL, bool.TrueString }, { DEPLOYMENT_GROUP_NAME_LABEL, deviceGroupName }, { DEPLOYMENT_PACKAGE_NAME_LABEL, packageName } }, Priority = priority }; this.registry.Setup(r => r.AddConfigurationAsync(It.Is <Configuration>(c => c.Labels.ContainsKey(DEPLOYMENT_NAME_LABEL) && c.Labels.ContainsKey(DEPLOYMENT_GROUP_ID_LABEL) && c.Labels.ContainsKey(RM_CREATED_LABEL) && c.Labels[DEPLOYMENT_NAME_LABEL] == deploymentName && c.Labels[DEPLOYMENT_GROUP_ID_LABEL] == deviceGroupId && c.Labels[RM_CREATED_LABEL] == bool.TrueString))) .ReturnsAsync(newConfig); // Act var createdDeployment = await this.deployments.CreateAsync(depModel); // Assert Assert.False(string.IsNullOrEmpty(createdDeployment.Id)); Assert.Equal(deploymentName, createdDeployment.Name); Assert.Equal(deviceGroupId, createdDeployment.DeviceGroupId); Assert.Equal(priority, createdDeployment.Priority); Assert.Equal(deviceGroupName, createdDeployment.DeviceGroupName); Assert.Equal(packageName, createdDeployment.PackageName); }
public async Task CreateDeploymentTest(string deploymentName, string deviceGroupId, string deviceGroupQuery, string packageContent, int priority, string expectedException) { // Arrange var depModel = new DeploymentServiceModel() { Name = deploymentName, DeviceGroupId = deviceGroupId, DeviceGroupQuery = deviceGroupQuery, PackageContent = packageContent, PackageType = PackageType.EdgeManifest, Priority = priority }; var newConfig = new Configuration("test-config") { Labels = new Dictionary <string, string>() { { DEPLOYMENT_NAME_LABEL, deploymentName }, { PACKAGE_TYPE_LABEL, PackageType.EdgeManifest.ToString() }, { DEPLOYMENT_GROUP_ID_LABEL, deviceGroupId }, { RM_CREATED_LABEL, bool.TrueString }, }, Priority = priority }; this.registry.Setup(r => r.AddConfigurationAsync(It.Is <Configuration>(c => c.Labels.ContainsKey(DEPLOYMENT_NAME_LABEL) && c.Labels.ContainsKey(DEPLOYMENT_GROUP_ID_LABEL) && c.Labels.ContainsKey(RM_CREATED_LABEL) && c.Labels[DEPLOYMENT_NAME_LABEL] == deploymentName && c.Labels[DEPLOYMENT_GROUP_ID_LABEL] == deviceGroupId && c.Labels[RM_CREATED_LABEL] == bool.TrueString))) .ReturnsAsync(newConfig); // Act if (string.IsNullOrEmpty(expectedException)) { var createdDeployment = await this.deployments.CreateAsync(depModel); // Assert Assert.False(string.IsNullOrEmpty(createdDeployment.Id)); Assert.Equal(deploymentName, createdDeployment.Name); Assert.Equal(deviceGroupId, createdDeployment.DeviceGroupId); Assert.Equal(priority, createdDeployment.Priority); } else { await Assert.ThrowsAsync(Type.GetType(expectedException), async() => await this.deployments.CreateAsync(depModel)); } }
public async Task <DeploymentServiceModel> CreateAsync(DeploymentServiceModel model, string userId, string tenantId) { if (string.IsNullOrEmpty(model.DeviceGroupId)) { throw new ArgumentNullException(DeviceGroupIdParameter); } if (string.IsNullOrEmpty(model.DeviceGroupQuery) && (model.DeviceIds == null || (model.DeviceIds != null && model.DeviceIds.Count() == 0))) { throw new ArgumentNullException(DeviceGroupQueryParameter); } if (string.IsNullOrEmpty(model.Name)) { throw new ArgumentNullException(NameParameter); } if (string.IsNullOrEmpty(model.PackageContent)) { throw new ArgumentNullException(PackageContentParameter); } if (model.PackageType.Equals(PackageType.DeviceConfiguration) && string.IsNullOrEmpty(model.ConfigType)) { throw new ArgumentNullException(ConfigurationTypeParameter); } if (model.Priority < 0) { throw new ArgumentOutOfRangeException( PriorityParameter, model.Priority, "The priority provided should be 0 or greater"); } var configuration = ConfigurationsHelper.ToHubConfiguration(model); // TODO: Add specific exception handling when exception types are exposed // https://github.com/Azure/azure-iot-sdk-csharp/issues/649 var result = new DeploymentServiceModel(await this.tenantHelper.GetRegistry().AddConfigurationAsync(configuration)); // Setting the id so that deployment id is populated model.Id = result.Id; // Log a custom event to Application Insights this.deploymentLog.LogDeploymentCreate(model, tenantId, userId); return(result); }
public DeploymentApiModel(DeploymentServiceModel serviceModel, IDictionary <string, DeploymentStatus> deviceStatuses) { this.CreatedDateTimeUtc = serviceModel.CreatedDateTimeUtc; this.DeploymentId = serviceModel.Id; this.DeviceGroupId = serviceModel.DeviceGroupId; this.Name = serviceModel.Name; this.Priority = serviceModel.Priority; this.Type = serviceModel.Type; this.Metrics = new DeploymentMetricsApiModel(serviceModel.DeploymentMetrics) { DeviceStatuses = deviceStatuses }; }
public DeploymentApiModel(DeploymentServiceModel serviceModel) { this.CreatedDateTimeUtc = serviceModel.CreatedDateTimeUtc; this.DeploymentId = serviceModel.Id; this.DeviceGroupId = serviceModel.DeviceGroupId; this.DeviceGroupName = serviceModel.DeviceGroupName; this.DeviceGroupQuery = serviceModel.DeviceGroupQuery; this.Name = serviceModel.Name; this.PackageContent = serviceModel.PackageContent; this.PackageName = serviceModel.PackageName; this.Priority = serviceModel.Priority; this.Type = serviceModel.Type; this.Metrics = new DeploymentMetricsApiModel(serviceModel.DeploymentMetrics) { DeviceStatuses = serviceModel.DeploymentMetrics?.DeviceStatuses }; }
public async Task <DeploymentServiceModel> CreateAsync(DeploymentServiceModel model) { if (string.IsNullOrEmpty(model.DeviceGroupId)) { throw new ArgumentNullException(DeviceGroupIdParameter); } if (string.IsNullOrEmpty(model.DeviceGroupQuery)) { throw new ArgumentNullException(DeviceGroupQueryParameter); } if (string.IsNullOrEmpty(model.Name)) { throw new ArgumentNullException(NameParameter); } if (string.IsNullOrEmpty(model.PackageContent)) { throw new ArgumentNullException(PackageContentParameter); } if (model.PackageType.Equals(PackageType.DeviceConfiguration) && string.IsNullOrEmpty(model.ConfigType)) { throw new ArgumentNullException(ConfigurationTypeParameter); } if (model.Priority < 0) { throw new ArgumentOutOfRangeException( PriorityParameter, model.Priority, "The priority provided should be 0 or greater"); } var configuration = ConfigurationsHelper.ToHubConfiguration(model); // TODO: Add specific exception handling when exception types are exposed // https://github.com/Azure/azure-iot-sdk-csharp/issues/649 return(new DeploymentServiceModel(await this.tenantHelper.GetRegistry().AddConfigurationAsync(configuration))); }
private ValueApiModel CreateDeploymentStorageData(int idx, bool isLatest = true) { // Arrange var deviceGroupId = "dvcGroupId"; var deviceGroupName = "dvcGroupName"; var deviceGroupQuery = "dvcGroupQuery"; var packageName = "packageName"; var deploymentName = "deployment"; var priority = 10; var userid = "testUser"; var deployment = new DeploymentServiceModel() { Name = deploymentName + idx, DeviceGroupId = deviceGroupId, DeviceGroupName = deviceGroupName, DeviceGroupQuery = deviceGroupQuery, PackageContent = TestEdgePackageJson, PackageName = packageName, Priority = priority, CreatedBy = userid, CreatedDateTimeUtc = DateTime.UtcNow, CreatedDateTime = DateTime.UtcNow, DeploymentMetrics = new DeploymentMetricsServiceModel() { DeviceStatuses = new Dictionary <string, DeploymentStatus> { { "device1", DeploymentStatus.Pending } } }, Tags = isLatest ? new List <string>() { "reserved.latest" } : new List <string>(), }; var jsonValue = JsonConvert.SerializeObject(deployment); ValueApiModel value = new ValueApiModel() { Key = idx.ToString(), Data = jsonValue }; return(value); }
private async Task <DeploymentServiceModel> MarkDeploymentAsDeleted(DeploymentServiceModel existingDeployment, string userId) { if (existingDeployment != null) { existingDeployment.Tags.Add(DeleteTag); AuditHelper.UpdateAuditingData(existingDeployment, userId); var value = JsonConvert.SerializeObject( existingDeployment, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); var response = await this.client.UpdateAsync(DeploymentsCollection, existingDeployment.Id, value, existingDeployment.ETag); } return(existingDeployment); }
private async Task StoreDeploymentInSecondaryStorage(DeploymentServiceModel deployment, string userId) { if (string.IsNullOrWhiteSpace(deployment.ETag)) { AuditHelper.AddAuditingData(deployment, userId); } else { AuditHelper.UpdateAuditingData(deployment, userId); } var value = JsonConvert.SerializeObject( deployment, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); var response = await this.client.UpdateAsync(DeploymentsCollection, deployment.Id, value, deployment.ETag); }
public void LogDeploymentCreate(DeploymentServiceModel deployment, string tenantId, string userId) { var eventInfo = new CustomEvent { EventSource = Convert.ToString(EventSource.IotHubManager), EventType = Convert.ToString(EventType.DeploymentCreate), EventTime = DateTimeOffset.UtcNow.ToString(AppInsightDateFormat), EventDescription = $@"Deployment created by User {userId} for package {deployment.PackageName} targeting {deployment.DeviceGroupName} Devicegroup", TenantId = tenantId, PackageId = deployment.PackageId, PackageName = deployment.PackageName, DeviceGroup = deployment.DeviceGroupName, PackageType = deployment.PackageType.ToString(), UserId = userId, DeploymentId = deployment.Id, DeploymentName = deployment.Name, }; this.LogCustomEvent($"{tenantId.Substring(0, 8)}-{deployment.Id}", deployment.Name, eventInfo); this.LogCustomEvent($"{tenantId.Substring(0, 8)}-{deployment.PackageId}", deployment.Name, eventInfo); }
public DeploymentApiModel(DeploymentServiceModel serviceModel) { this.CreatedDateTimeUtc = serviceModel.CreatedDateTimeUtc; this.DeploymentId = serviceModel.Id; this.DeviceGroupId = serviceModel.DeviceGroupId; this.DeviceGroupName = serviceModel.DeviceGroupName; this.DeviceGroupQuery = serviceModel.DeviceGroupQuery; this.Name = serviceModel.Name; this.PackageContent = serviceModel.PackageContent; this.PackageName = serviceModel.PackageName; this.Priority = serviceModel.Priority; this.PackageType = serviceModel.PackageType; this.ConfigType = serviceModel.ConfigType; this.Metrics = new DeploymentMetricsApiModel(serviceModel.DeploymentMetrics) { DeviceStatuses = serviceModel.DeploymentMetrics?.DeviceStatuses }; this.Metadata = new Dictionary <string, string> { { "$type", $"DevicePropertyList;{Version.NUMBER}" }, { "$url", $"/{Version.PATH}/deviceproperties" } }; }
private Configuration CreateEdgeConfiguration(DeploymentServiceModel model) { var deploymentId = Guid.NewGuid().ToString().ToLower(); var edgeConfiguration = new Configuration(deploymentId); var packageEdgeConfiguration = JsonConvert.DeserializeObject <Configuration>(model.PackageContent); edgeConfiguration.Content = packageEdgeConfiguration.Content; var targetCondition = QueryConditionTranslator.ToQueryString(model.DeviceGroupQuery); edgeConfiguration.TargetCondition = string.IsNullOrEmpty(targetCondition) ? "*" : targetCondition; edgeConfiguration.Priority = model.Priority; edgeConfiguration.ETag = string.Empty; if (edgeConfiguration.Labels == null) { edgeConfiguration.Labels = new Dictionary <string, string>(); } // Required labels edgeConfiguration.Labels.Add(DEPLOYMENT_NAME_LABEL, model.Name); edgeConfiguration.Labels.Add(DEPLOYMENT_GROUP_ID_LABEL, model.DeviceGroupId); edgeConfiguration.Labels.Add(RM_CREATED_LABEL, bool.TrueString); // Add optional labels if (model.DeviceGroupName != null) { edgeConfiguration.Labels.Add(DEPLOYMENT_GROUP_NAME_LABEL, model.DeviceGroupName); } if (model.PackageName != null) { edgeConfiguration.Labels.Add(DEPLOYMENT_PACKAGE_NAME_LABEL, model.PackageName); } return(edgeConfiguration); }
public async Task CreateDeploymentTest( string deploymentName, string deviceGroupId, string deviceGroupQuery, string packageContent, int priority, string expectedException) { // Arrange var depModel = new DeploymentServiceModel() { Name = deploymentName, DeviceGroupId = deviceGroupId, DeviceGroupQuery = deviceGroupQuery, PackageContent = packageContent, PackageType = PackageType.EdgeManifest, Priority = priority, }; var userId = "testUser"; var tenantId = "testTenat"; var existingConfig = new Configuration("test-config1") { Labels = new Dictionary <string, string>() { { DeploymentNameLabel, deploymentName }, { this.packageTypeLabel, PackageType.EdgeManifest.ToString() }, { DeploymentGroupIdLabel, deviceGroupId }, { RmCreatedLabel, bool.TrueString }, }, Priority = priority, }; var newConfig = new Configuration("test-config") { Labels = new Dictionary <string, string>() { { DeploymentNameLabel, deploymentName }, { this.packageTypeLabel, PackageType.EdgeManifest.ToString() }, { DeploymentGroupIdLabel, deviceGroupId }, { RmCreatedLabel, bool.TrueString }, }, Priority = priority, }; this.registry.Setup(r => r.AddConfigurationAsync(It.Is <Configuration>(c => c.Labels.ContainsKey(DeploymentNameLabel) && c.Labels.ContainsKey(DeploymentGroupIdLabel) && c.Labels.ContainsKey(RmCreatedLabel) && c.Labels[DeploymentNameLabel] == deploymentName && c.Labels[DeploymentGroupIdLabel] == deviceGroupId && c.Labels[RmCreatedLabel] == bool.TrueString))) .ReturnsAsync(newConfig); this.registry.Setup(r => r.CreateQuery(It.IsAny <string>())).Returns(new ResultQuery(0)); this.registry.Setup(r => r.GetConfigurationAsync(It.IsAny <string>())).ReturnsAsync(existingConfig); this.tenantHelper.Setup(e => e.GetRegistry()).Returns(this.registry.Object); this.storageAdapterClient.Setup(s => s.UpdateAsync( It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(new ValueApiModel()); this.storageAdapterClient.Setup(s => s.CreateAsync( It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(new ValueApiModel()); var deploymentStorageData = this.CreateDeploymentStorageData(0); this.storageAdapterClient.Setup(r => r.GetAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(deploymentStorageData); this.devices.Setup(d => d.GetListAsync(It.IsAny <string>(), It.IsAny <string>())).ReturnsAsync(new DeviceServiceListModel(new List <DeviceServiceModel>())); var configurations = new List <Configuration>(); configurations.Add(existingConfig); this.registry.Setup(r => r.GetConfigurationsAsync(1000)).ReturnsAsync(configurations); this.tenantHelper.Setup(e => e.GetRegistry()).Returns(this.registry.Object); // Act if (string.IsNullOrEmpty(expectedException)) { var createdDeployment = await this.deployments.CreateAsync(depModel, userId, tenantId); // Assert Assert.False(string.IsNullOrEmpty(createdDeployment.Id)); Assert.Equal(deploymentName, createdDeployment.Name); Assert.Equal(deviceGroupId, createdDeployment.DeviceGroupId); Assert.Equal(priority, createdDeployment.Priority); } else { await Assert.ThrowsAsync( Type.GetType(expectedException), async() => await this.deployments.CreateAsync(depModel, userId, tenantId)); } }
public static Configuration ToHubConfiguration(DeploymentServiceModel model) { var packageConfiguration = JsonConvert.DeserializeObject <Configuration>(model.PackageContent); if (model.PackageType.Equals(PackageType.EdgeManifest) && packageConfiguration.Content?.DeviceContent != null) { throw new InvalidInputException("Deployment type does not match with package contents."); } else if (model.PackageType.Equals(PackageType.DeviceConfiguration) && packageConfiguration.Content?.ModulesContent != null) { throw new InvalidInputException("Deployment type does not match with package contents."); } var deploymentId = Guid.NewGuid().ToString().ToLower(); var configuration = new Configuration(deploymentId); configuration.Content = packageConfiguration.Content; var targetCondition = QueryConditionTranslator.ToQueryString(model.DeviceGroupQuery); if (model.DeviceIds != null && model.DeviceIds.Any()) { string deviceIdCondition = $"({string.Join(" or ", model.DeviceIds.Select(v => $"deviceId = '{v}'"))})"; if (!string.IsNullOrWhiteSpace(targetCondition)) { string[] conditions = { targetCondition, deviceIdCondition }; targetCondition = string.Join(" or ", conditions); } else { targetCondition = deviceIdCondition; } } configuration.TargetCondition = string.IsNullOrEmpty(targetCondition) ? "*" : targetCondition; configuration.Priority = model.Priority; configuration.ETag = string.Empty; configuration.Labels = packageConfiguration.Labels ?? new Dictionary <string, string>(); // Required labels configuration.Labels[PackageTypeLabel] = model.PackageType.ToString(); configuration.Labels[DeploymentNameLabel] = model.Name; configuration.Labels[DeploymentGroupIdLabel] = model.DeviceGroupId; configuration.Labels[RmCreatedLabel] = bool.TrueString; if (!string.IsNullOrEmpty(model.ConfigType)) { configuration.Labels[ConfigTypeLabel] = model.ConfigType; } var customMetrics = packageConfiguration.Metrics?.Queries; if (customMetrics != null) { configuration.Metrics.Queries = SubstituteDeploymentIdIfPresent( customMetrics, deploymentId); } // Add optional labels if (model.DeviceGroupName != null) { configuration.Labels[DeploymentGroupNameLabel] = model.DeviceGroupName; } if (model.PackageName != null) { configuration.Labels[DeploymentPackageNameLabel] = model.PackageName; } return(configuration); }
public async Task <DeploymentServiceModel> CreateAsync(DeploymentServiceModel model, string userId, string tenantId) { if (string.IsNullOrEmpty(model.DeviceGroupId)) { throw new ArgumentNullException(DeviceGroupIdParameter); } if (string.IsNullOrEmpty(model.DeviceGroupQuery) && (model.DeviceIds == null || (model.DeviceIds != null && model.DeviceIds.Count() == 0))) { throw new ArgumentNullException(DeviceGroupQueryParameter); } if (string.IsNullOrEmpty(model.Name)) { throw new ArgumentNullException(NameParameter); } if (string.IsNullOrEmpty(model.PackageContent)) { throw new ArgumentNullException(PackageContentParameter); } if (model.PackageType.Equals(PackageType.DeviceConfiguration) && string.IsNullOrEmpty(model.ConfigType)) { throw new ArgumentNullException(ConfigurationTypeParameter); } if (model.Priority < 0) { throw new ArgumentOutOfRangeException( PriorityParameter, model.Priority, "The priority provided should be 0 or greater"); } var configuration = ConfigurationsHelper.ToHubConfiguration(model); // Update the Metrics related to previous deployment which targets the same device group as the metrics // will be overriden once the new deployment gets applied to the devices. bool shouldMarkAsLatest = await this.UpdateMetricsOfCurrentDeployment(model.DeviceGroupId, model.Priority); // TODO: Add specific exception handling when exception types are exposed // https://github.com/Azure/azure-iot-sdk-csharp/issues/649 var result = new DeploymentServiceModel(await this.tenantHelper.GetRegistry().AddConfigurationAsync(configuration)); // Setting the id so that deployment id is populated model.Id = result.Id; model.CreatedDateTimeUtc = result.CreatedDateTimeUtc; // Add latest tag to deployment if deployment has highest priority for the device group. if (shouldMarkAsLatest) { if (model.Tags == null) { model.Tags = new List <string>(); } model.Tags.Add(LatestTag); } else { // Update the Device Statuses for the DeploymentId for future references. model.DeploymentMetrics = result.DeploymentMetrics; } // Store the deployment details in Cosmos DB await this.StoreDeploymentInSecondaryStorage(model, userId); // Log a custom event to Application Insights // this.deploymentLog.LogDeploymentCreate(model, tenantId, userId); return(model); }
private async Task <DeploymentServiceModel> MarkDeploymentAsInactive(DeploymentServiceModel existingDeployment, string userId, List <TwinServiceModel> deviceTwins, bool isDelete) { if (existingDeployment != null) { if (existingDeployment.Tags == null) { existingDeployment.Tags = new List <string>(); } if (existingDeployment.Tags.Contains(InActiveTag, StringComparer.InvariantCultureIgnoreCase)) { return(existingDeployment); } existingDeployment.Tags.Add(InActiveTag); if (isDelete) { existingDeployment.Tags.Add(DeleteTag); } bool isLatestDeployment = existingDeployment.Tags.Contains(LatestTag, StringComparer.InvariantCultureIgnoreCase); if (isLatestDeployment) { existingDeployment.Tags.Remove(LatestTag); } AuditHelper.UpdateAuditingData(existingDeployment, userId); var value = JsonConvert.SerializeObject( existingDeployment, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); var response = await this.client.UpdateAsync(DeploymentsCollection, existingDeployment.Id, value, existingDeployment.ETag); if (deviceTwins != null && deviceTwins.Count > 0) { await this.StoreDevicePropertiesInStorage(deviceTwins, existingDeployment.Id); } if (isLatestDeployment) { // Mark the deployment with highest priority and which is created last as the latest deployment. var deployments = await this.ListAsync(); if (deployments != null && deployments.Items.Count > 0) { var deploymentsOfDeviceGroup = deployments.Items.Where(i => i.DeviceGroupId == existingDeployment.DeviceGroupId).OrderByDescending(p => p.Priority).ThenByDescending(q => q.CreatedDateTimeUtc); if (deploymentsOfDeviceGroup != null && deploymentsOfDeviceGroup.Count() > 0) { var latestDeployment = deploymentsOfDeviceGroup.First(); var latestDeploymentFromStorage = await this.GetDeploymentFromStorageAsync(latestDeployment.Id); if (latestDeploymentFromStorage != null) { if (latestDeploymentFromStorage.Tags == null) { latestDeploymentFromStorage.Tags = new List <string>(); } if (!latestDeploymentFromStorage.Tags.Contains(LatestTag)) { latestDeploymentFromStorage.Tags.Add(LatestTag); var storageValue = JsonConvert.SerializeObject( latestDeploymentFromStorage, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); await this.client.UpdateAsync(DeploymentsCollection, latestDeployment.Id, storageValue, latestDeploymentFromStorage.ETag); } } } } } } return(existingDeployment); }
private async Task <(bool ShouldMarkAsLatest, string DeploymentId)> UpdateMetricsOfCurrentDeployment(string deviceGroupId, int priority, string tenantId) { var deploymentsFromHub = await this.ListAsync(); var deploymentsOfDeviceGroup = deploymentsFromHub.Items.Where(i => i.DeviceGroupId == deviceGroupId).OrderByDescending(p => p.Priority).ThenByDescending(q => q.CreatedDateTimeUtc); string deploymentId = string.Empty; if (deploymentsOfDeviceGroup != null && deploymentsOfDeviceGroup.Count() > 0) { var deployment = deploymentsOfDeviceGroup.First(); if (priority >= deployment.Priority) { var getDeploymentFromHub = this.GetDeploymentAsync(deployment.Id); var getDeploymentFromCOSMOS = this.GetDeploymentFromStorageAsync(deployment.Id); await Task.WhenAll(getDeploymentFromHub, getDeploymentFromCOSMOS); var deploymentDetails = await getDeploymentFromHub; DeploymentServiceModel currentDeployment = await getDeploymentFromCOSMOS; // Update the Device Statuses for the DeploymentId for future references. currentDeployment.DeploymentMetrics = new DeploymentMetricsServiceModel(deploymentDetails.SystemMetrics, deploymentDetails.Metrics); // Save device statuses in a separate collection this.SaveDeviceStatuses(this.GetDeviceStatuses(deploymentDetails), deployment.Id); if (string.IsNullOrWhiteSpace(currentDeployment.TargetCondition)) { currentDeployment.TargetCondition = deploymentDetails.TargetCondition; } // Since the deployment that will be created have highest priority, remove latest tag on current deployment if (currentDeployment?.Tags != null) { var existingTag = currentDeployment.Tags.FirstOrDefault(t => t.Equals(LatestTag, StringComparison.OrdinalIgnoreCase)); if (existingTag != null) { currentDeployment.Tags.Remove(existingTag); } } var value = JsonConvert.SerializeObject( currentDeployment, Formatting.Indented, new JsonSerializerSettings { NullValueHandling = NullValueHandling.Ignore, }); var updateDeployment = await this.client.UpdateAsync(DeploymentsCollection, currentDeployment.Id, value, currentDeployment.ETag); return(true, currentDeployment.Id); } else { return(false, deploymentId); } } // Since the deployment that will be created have highest priority, mark it as the latest return(true, deploymentId); }