Example #1
0
        /// <summary>
        /// Parses and checks the given JSON object to see if any armTemplateParameters were added or removed.
        /// If parameters were added then they are created in the db along with a join entry in the armTemplateArmTemplateParameters table.
        /// If parameters were removed then the join entry in the armTemplateArmTemplateParameters table is removed.
        /// </summary>
        /// <param name="offer">The name of the offer the parameters belong to</param>
        /// <param name="armTemplateJSON">The JSON object to parse.</param>
        /// <param name="armTemplateId">The ID of the armTemplate.</param>
        /// <returns></returns>
        private async Task UpdateArmTemplateParameters(Offer offer, object armTemplateJSON, long armTemplateId)
        {
            List <KeyValuePair <string, string> >  incompleteParams = ARMTemplateHelper.GetArmTemplateParameters(armTemplateJSON.ToString());
            List <ArmTemplateArmTemplateParameter> joinEntries      = await _armTemplateArmTemplateParameterService.GetAllJoinEntries(armTemplateId);

            Dictionary <string, ArmTemplateParameter> paramsDb = new Dictionary <string, ArmTemplateParameter>();
            HashSet <string> usedParamNames = new HashSet <string>();

            // Populate paramsDb so that it maps the ArmTemplateParameter name to the ArmTemplateParameter object
            foreach (ArmTemplateArmTemplateParameter entry in joinEntries)
            {
                ArmTemplateParameter armTemplateParameter = await _context.ArmTemplateParameters.FindAsync(entry.ArmTemplateParameterId);

                if (!paramsDb.ContainsKey(armTemplateParameter.Name))
                {
                    paramsDb.Add(armTemplateParameter.Name, armTemplateParameter);
                }
            }

            foreach (KeyValuePair <string, string> incompleteParam in incompleteParams)
            {
                // Check if a param with the same name as the incompleteParam already exists
                if (!paramsDb.ContainsKey(incompleteParam.Key))
                {
                    ArmTemplateParameter armParameter = new ArmTemplateParameter
                    {
                        OfferId = offer.Id,
                        Name    = incompleteParam.Key,
                        Type    = incompleteParam.Value,
                        // TODO: do we need to indicate an incomplete parameter?
                        Value = string.Empty
                    };

                    // A param with the same name as the incompleteParam does not exist, so create it
                    await _armTemplateParameterService.CreateAsync(offer.OfferName, armTemplateId, armParameter);
                }

                // Keep track of all the new parameters we are using in usedParamNames
                if (!usedParamNames.Contains(incompleteParam.Key))
                {
                    usedParamNames.Add(incompleteParam.Key);
                }
            }

            foreach (KeyValuePair <string, ArmTemplateParameter> paramDb in paramsDb)
            {
                // Check if there is a param in the db that we are no longer using
                if (!usedParamNames.Contains(paramDb.Key))
                {
                    ArmTemplateArmTemplateParameter armTemplateArmTemplateParameter = await _context.ArmTemplateArmTemplateParameters.FindAsync(armTemplateId, paramDb.Value.Id);

                    // Remove the join entry for any unused params
                    _context.ArmTemplateArmTemplateParameters.Remove(armTemplateArmTemplateParameter);
                    await _context._SaveChangesAsync();
                }
            }
        }
Example #2
0
        /// <summary>
        /// Parse the ARM template to get the parameter names and build an object containing the parameter names and values
        /// </summary>
        /// <param name="offer"></param>
        /// <param name="plan"></param>
        /// <param name="subscriptionAction"></param>
        /// <returns>An object containing the parameter names and values</returns>
        public async Task <Dictionary <string, object> > GetTemplateParameters(
            Offer offer,
            Plan plan,
            FulfillmentAction subscriptionAction
            )
        {
            ArmTemplate template = null;

            switch (subscriptionAction)
            {
            case FulfillmentAction.Activate:
                template = await _lunaClient.GetArmTemplate(offer.OfferName, plan.SubscribeArmTemplateName);

                break;

            case FulfillmentAction.Update:
                template = await _lunaClient.GetArmTemplate(offer.OfferName, plan.SubscribeArmTemplateName);

                break;

            case FulfillmentAction.Unsubscribe:
                template = await _lunaClient.GetArmTemplate(offer.OfferName, plan.UnsubscribeArmTemplateName);

                break;

            default:
                throw new InvalidEnumArgumentException();
            }

            string templateContent = await _storage.DownloadToTextAsync(template.TemplateFilePath);

            var parameters    = ARMTemplateHelper.GetArmTemplateParameters(templateContent);
            var parameterList = new Dictionary <string, object>();

            foreach (var parameter in parameters)
            {
                ArmTemplateParameter atp = await _lunaClient.GetArmTemplateParameter(offer.OfferName, parameter.Key);

                parameterList.Add(
                    atp.Name,
                    new { Value = atp.Value }
                    );
            }
            return(parameterList);
        }
Example #3
0
        /// <summary>
        /// Parses the given JSON object for ArmTemplateParameters then creates them in the db.
        /// The join entry is also created in the armTemplateArmTemplateParameters table.
        /// </summary>
        /// <param name="offer">The name of the offer the parameters belong to.</param>
        /// <param name="armTemplateJSON">The JSON to parse.</param>
        /// <param name="armTemplateId">The ID of the armTemplate.</param>
        /// <returns></returns>
        private async Task CreateArmTemplateParameters(Offer offer, object armTemplateJSON, long armTemplateId)
        {
            var parameters = ARMTemplateHelper.GetArmTemplateParameters(armTemplateJSON.ToString());

            foreach (var param in parameters)
            {
                ArmTemplateParameter armParameter = new ArmTemplateParameter
                {
                    OfferId = offer.Id,
                    Name    = param.Key,
                    Type    = param.Value,
                    // TODO: do we need to indicate an incomplete parameter?
                    Value = string.Empty
                };

                await _armTemplateParameterService.CreateAsync(offer.OfferName, armTemplateId, armParameter);
            }
        }
        public async Task <Subscription> DeployArmTemplateAsync(Guid subscriptionId)
        {
            Subscription subscription = await _context.Subscriptions.FindAsync(subscriptionId);

            ValidateSubscriptionAndInputState(subscription);

            try
            {
                if (subscription.ResourceGroup == null)
                {
                    // If resource group is not created, transit to ProvisioningPending state to create resource group
                    return(await TransitToNextState(subscription, ProvisioningState.ProvisioningPending));
                }

                Offer offer = await FindOfferById(subscription.OfferId);

                Plan plan = await FindPlanById(subscription.PlanId);

                string deploymentName    = $"{plan.PlanName}{offer.OfferName}{new Random().Next(0, 9999).ToString("D4")}"; // deployment name cannot exceed 64 characters, otherwise returns 400
                string isvSubscriptionId = offer.HostSubscription.ToString();

                string templatePath = await GetTemplatePath(plan, subscription.ProvisioningType);

                if (templatePath == null)
                {
                    // If template is not specified, do nothing and transit to WebhookPending state
                    return(await TransitToNextState(subscription, ProvisioningState.WebhookPending));
                }

                // Reevaluate parameters if not subscribe. If it is subscribe, the parameters are evaluated when creating resource group
                if (!subscription.ProvisioningType.Equals(nameof(ProvisioningType.Subscribe)))
                {
                    await EvaluateParameters(offer, plan, subscription);
                }

                templatePath = await _storageUtility.GetFileReferenceWithSasKeyAsync(templatePath);

                JObject parameters = new JObject();
                using (WebClient client = new WebClient())
                {
                    string  content = client.DownloadString(templatePath);
                    Context context = await SetContext(offer.OfferName, subscription.Owner, subscriptionId, plan.PlanName, subscription.ProvisioningType);

                    var paramList = ARMTemplateHelper.GetArmTemplateParameters(content);
                    foreach (var param in paramList)
                    {
                        JProperty value = new JProperty("value", context.Parameters[param.Key]);
                        parameters.Add(param.Key, new JObject(value));
                    }
                }

                _logger.LogInformation(
                    LoggingUtils.ComposeHttpClientLogMessage(
                        _provisioningClient.GetType().Name,
                        nameof(_provisioningClient.PutDeploymentAsync),
                        subscriptionId));

                var result = await _provisioningClient.PutDeploymentAsync(
                    Guid.NewGuid(),
                    Guid.NewGuid(),
                    isvSubscriptionId,
                    subscription.ResourceGroup,
                    deploymentName,
                    parameters : parameters,
                    templatePath : templatePath);

                subscription.DeploymentName = result.Name;

                _logger.LogInformation($"Running ARM deployment {deploymentName} for subscription {isvSubscriptionId} in resource group {subscription.ResourceGroup}.");

                return(await TransitToNextState(subscription, ProvisioningState.ArmTemplateRunning));
            }
            catch (Exception e)
            {
                return(await HandleExceptions(subscription, e));
            }
        }