Application Packaging Standard

Last updated 18-Mar-2019

VPS Creation

To make every new VPS be assigned to a domain and optionally have own CNAME aliased to a DNS A record, you have to modify respectively the VPS creation wizard and the views plugged into it as described in this document.

../../../../../_images/dns-step-model2.png ../../../../../_images/dns-step-meta2.png ../../../../../_images/dns-step-provision2.png ../../../../../_images/dns-step-presentation-b1.png ../../../../../_images/dns-step-deploy2.png ../../../../../_images/dns-step-provisioning2.png

Requirements

Integration with DNS adds the following requirements to the wizard:

  • The wizard must analyze if a request for creating a VPS contains a domain APS ID, which indicates if the wizard is started from a domain profile. In this is a case, the wizard must send the ID to the first plugged application view. The latter must use the received domain APS ID to make the respective domain preselected for a new VPS.
  • If the CNAME is required for the new VPS, the wizard must create such a DNS record.
  • The first plugged view must require a customer to select one of available domains for the new VPS and to specify if the CNAME is required.

Continue Your Demo Project

Continue the demo project from the previous step.

VPS Creation Wizard

Follow these steps to meet the above requirements in the ui/vps-wizard.js file.

  1. In the main callback function, define a function for creating the CNAME record:

    Note

    If in your own project, you also need to create various other DNS records, modify the function to make it more general and able to create the needed type of DNS record.

    function createDnsRecord(vps, domain) {
       var jsonData = {
          "aps": {
             "type": "http://aps-standard.org/types/dns1p/record/cname/1.0"
          },
          "RRState": "active",
          "TTL": 3600,
          "source": vps.name + "." + domain + ".",
          "cname": "vps." + domain + ".",
          "zone": {
             "aps": {
                "id": vps.domain.aps.id
             }
          }
       };
       return xhr("/aps/2/resources/" + vps.aps.id + "/records", {
          method: "POST",
          data: JSON.stringify(jsonData)
       });
    }
    
  2. In the onNext handler, send the domain APS ID to the first view if the wizard has received that ID:

    onNext: function() {
       /* Direct a user to the first view */
       if (aps.context.params.domainApsId) { // If we've come here from the DNS Manager
          aps.apsc.next(aps.context.params.domainApsId);
       }
       else aps.apsc.next();
    },
    
  3. In the onSubmit handler, create the CNAME record if it is required:

    onSubmit: function() {
       /* Specify the subscription whose resource will be used */
       aps.context.subscriptionId = aps.context.vars.context.aps.subscription;
    
       /* Declare the data store */
       var store = new Store({
          apsType: "http://aps-standard.org/samples/dns1p/vps/1.0",
          target: "/aps/2/resources/" + aps.context.vars.context.aps.id + "/vpses"
       });
    
       /* Receive data from the 1st view and save the new VPS */
       var newVPS =
          aps.context.wizardData["http://aps-standard.org/samples/dns1p#server-new-1"];
       store.put(newVPS)
       .then(function(vps) {
          if(newVPS.cnameRecord)
          return createDnsRecord(vps, newVPS.domainName);
       })
       .then(function() {
             aps.apsc.gotoView("servers");
          }, displayError
       );
    }
    

First View in Server Creation

The existing ui/wizard/server-new-1.js file should be modified in several places.

  1. Declare two store objects to operate the domains. One, aps/Memory, must be used to present a list of domains for selection. The other one, aps/ResourceStore, must interact with the APS controller. In the init function, it is not recommended to get resources from the APS controller, since this is a long operations. So, the domain list will be an aps/Memory object with the initially empty data.

    • Require the JS modules in the top level define function as in the following list:

      define([
         "dojo/_base/declare",
         "dojox/mvc/at",
         "dojox/mvc/getStateful",
         "aps/View",
         "aps/ResourceStore",
         "aps/Memory",
         /* Include JSON file that defines the VPS default properties */
         "aps/json!./newvps.json"
      ],
      
    • Declare the respective arguments in the main callback function:

      function (declare, at, getStateful, View, Store, Memory, newVPS) {
      
    • In the init method, declare the domain store object as a global object:

      this.domainStore = new Memory({
         data: [],
         idProperty: "aps.id"
      });
      
  2. Add a field set that allows a user to select a domain and require the CNAME for the VPS in this domain. Make it the last child in the top most aps/Panel:

    ["aps/FieldSet", { id: this.genId("srvNew1_domains") },
      [
        ["aps/Select", {
          id: this.genId("srvNew1_domainSelect"),
          gridSize: 'md-3 xs-12',
          store: this.domainStore,
          labelAttr: "name",
          value: at(this.vpsModel.data.domain.aps, "id")
        }],
        ["aps/CheckBox", {
          id: this.genId("srvNew1_domainCname"),
          gridSize: 'md-3 xs-12',
          description: 'CNAME record',
          checked: at(this.vpsModel.data, "cnameRecord")
        }]
    ]]
    

    Keynotes:

    • The newly declared domainStore is used to select domains.
    • In the selection list, the domain name property will be presented as a label.
    • The selected domain is linked to the VPS through the domain link defined in the Domain Service type.
    • The CNAME record checkbox is synced with the VPS cnameRecord property.
  3. Update the onContext method to do all required operations with the APS controller.

    onContext: function() {
       if (!aps.context.wizardData["http://aps-standard.org/samples/dns1p#server-new-1"])
          this.vpsModel.set("data", newVPS);
    
       var store = new Store({
          target: "/aps/2/resources/",
          apsType: "http://aps-standard.org/types/dns/zone/1.1"
       });
    
       /* Retrieve all customer's domains */
       store.query().then(function(domains) {
    
          /* Refresh the store */
          this.domainStore.setData(domains);
          var domainSelection = this.byId("srvNew1_domainSelect");
          domainSelection.set("store", this.domainStore);
    
          /* Define the selected domain */
          if (aps.context.wizardData["http://aps-standard.org/samples/dns1p#vps-wizard"]) {
             this.vpsModel.data.domain.aps.set(
                "id",
                aps.context.wizardData["http://aps-standard.org/samples/dns1p#vps-wizard"]
             );
          }
          else domainSelection.set("value", domains[0].aps.id);
    
          aps.apsc.hideLoading();
       }.bind(this));
    }
    

    Keynotes:

    • The store operates the resources of the Hosted Domain type. It retrieves all domains available for the customer and assign this list to the domainStore.data array. Then, the store of the domain selection widget is updated.
    • Once the selection list is defined, the method identifies a domain to be pre-selected. If the VPS wizard sends a domain APS ID here, the specified domain must be pre-selected. Otherwise, the first domain from the list is pre-selected.
  4. Modify the onNext handler to identify the selected domain name before proceeding to the next step:

    onNext: function() {
       /* Get domain name from the selection list and set the VPS domainName property*/
        var selectWidget = this.byId("srvNew1_domainSelect");
        var domainId = selectWidget.get("value");
        this.vpsModel.data.set("domainName", selectWidget.getOption(domainId)[0].label);
    
       /* Proceed to the next step */
        aps.apsc.next(this.vpsModel.data);
    }
    

    The code operates the selection widget to identify both, the APS ID and the name of the selected domain.

Last View in Server Creation

The last step in VPS creation must show the selected domain name and display if the CNAME is required by means of an icon.

For the above reasons, modify the ui/wizard/server-new-last.js file as follows.

  1. In the main callback function, declare a global variable to specify if the CNAME was required in the previous step:

    var cNameNeeded = "false";
    
  2. In the widget definition return statement, add two output widgets presenting the DNS properties:

    ["aps/Output", {
       id: this.genId("srvNew_domain"),
       label: "Domain",
       value: at(aps.app.model.newVPS, "domainName")
    }],
    ["aps/Status", {
       id: this.gendId("srvNew_cName"),
       label: "CNAME",
       status: cNameNeeded,
       useIcon: true,
       statusInfo: {
          "no": {
             "label": "",
             "type": "disabled",
             "icon": "fa-minus"
          },
          "yes": {
             "label": "",
             "type": "success",
             "icon": "fa-check"
       }}
    }]
    

    In the above code, the former widget prints out the domain name, and the latter one is an icon indicating if the CNAME is required (success type) or not (disabled type).

  3. In the onContext handler, define the actual value of the cNameNeeded variable and then update the widget that shows if the CNAME is needed:

    cNameNeeded = (this.vpsModel.data.get("cnameRecord")) ? "yes" : "no";
    this.byId("srvNew_cName").set("status", cNameNeeded);
    

Conclusion

On completion of this step, the application is partially integrated with the Domain Manager in terms of providing tools for linking VPSes to domains and creating DNS records for them.

The project files you have updated are similar to the respective files in the sample package.

In the next project phase, you will complete the integration by embedding custom view-plugins into the Domain Manager views.