github.com/jbking/gohan@v0.0.0-20151217002006-b41ccf1c2a96/etc/extensions/donburi.js (about)

     1  // Copyright (C) 2015 NTT Innovation Institute, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
    12  // implied.
    13  // See the License for the specific language governing permissions and
    14  // limitations under the License.
    15  
    16  var donburi = {
    17    plugin: {},
    18    no_template_keywords: ['eval', 'block', 'define',
    19                           'resources',
    20                           'netconf_close', 'netconf_exec',
    21                           'ssh_close', 'ssh_exec'],
    22    register_plugin: function(name, plugin){
    23      this.plugin[name] = plugin
    24    },
    25    apply_template: function(context, data){
    26      var self = this;
    27      if(_.isString(data)){
    28        return gohan_template(data, context);
    29      }
    30      if(_.isArray(data)){
    31        var result = [];
    32        _.each(data, function(sub_data){
    33          result.push(self.apply_template(context, sub_data));
    34        });
    35        return result;
    36      }
    37      if(_.isObject(data)){
    38        var result = {};
    39        _.each(data, function(sub_data, key){
    40          result[key] = self.apply_template(context, sub_data);
    41        });
    42        return result;
    43      }
    44      return data
    45    }
    46    run_task: function(event_type, context, task){
    47      var self = this;
    48      if(!_.isUndefined(task.when)){
    49        with(context){
    50          try{
    51            if(eval(task.when) == false){
    52              if(!_.isUndefined(task["else"])){
    53                try{
    54                  self.run_tasks(event_type, context, task["else"])
    55                }catch(err){
    56                  context.error = err;
    57                }
    58              }
    59              return;
    60            }
    61          }catch(err){
    62            context.error = err;
    63            return;
    64          }
    65        }
    66      }
    67      var result;
    68      var retry_count = task.retry;
    69      if(_.isUndefined(retry_count)){
    70        retry_count = 1;
    71      }
    72      for(var retry = 0; retry < retry_count; retry++){
    73        try{
    74          _.each(_.keys(task), function(key){
    75            var plugin = self.plugin[key];
    76            if(_.isUndefined(plugin)){
    77              return;
    78            }
    79            var with_items = task.with_items;
    80            var with_dict = task.with_dict;
    81            if(_.isUndefined(with_items) && _.isUndefined(with_dict)){
    82              result = self.run_plugin(plugin, event_type, context, key, task[key]);
    83            }else{
    84              if(_.isString(with_items)){
    85                with(context){
    86                  with_items = eval(with_items);
    87                }
    88              }
    89              if(_.isArray(with_items)){
    90                result = [];
    91                _.each(with_items, function(item){
    92                  context.item = item;
    93                  var sub_result = self.run_plugin(plugin, event_type, context, key, task[key]);
    94                  result.push(sub_result);
    95                });
    96              }
    97              if(_.isString(with_dict)){
    98                with(context){
    99                  with_dict = eval(with_dict);
   100                }
   101              }
   102              if(_.isObject(with_dict)){
   103                result = {};
   104                _.each(with_dict, function(value, item_key){
   105                  context.item = {key: item_key, value:value};
   106                  var sub_result = self.run_plugin(plugin, event_type, context, key, task[key]);
   107                  result[key] = sub_result;
   108                });
   109              }
   110            }
   111          });
   112          if(!_.isUndefined(task.register)){
   113              context[task.register] = result;
   114          }
   115        }catch(err){
   116          context.error = err;
   117          if(!_.isUndefined(task.rescue)){
   118            try{
   119              self.run_tasks(event_type, context, task.rescue)
   120            }catch(err){
   121              context.error = err;
   122            }
   123          }else{
   124            throw err;
   125          }
   126        }
   127        if(!_.isUndefined(task.always)){
   128          try{
   129            self.run_tasks(event_type, context, task.always)
   130          }catch(err){
   131            context.error = err;
   132          }
   133        }
   134      }
   135      return result;
   136    },
   137    run_plugin: function(plugin, event_type, context, key, value){
   138      var self = this;
   139      if(self.no_template_keywords.indexOf(key) == -1){
   140        value = self.apply_template(context, value);
   141      }
   142      return plugin(event_type, context, value);
   143    }
   144    run_tasks: function(event_type, context, tasks){
   145      var self = this;
   146      var result;
   147      _.each(tasks, function(task){
   148        result = self.run_task(event_type, context, task);
   149      });
   150      return result;
   151    },
   152    run: function(code){
   153      var self = this;
   154      var events = ["post_create",
   155                    "post_update",
   156                    "pre_delete",
   157                    "notification"]
   158      _.each(events, function(event_type){
   159        gohan_register_handler(event_type, function(context){
   160          try{
   161            self.run_tasks(event_type, context, code.tasks);
   162          }catch(err){
   163            context.error = err;
   164          }
   165        });
   166        var event_type_in_transaction = event_type + "_in_transaction"
   167        gohan_register_handler(event_type_in_transaction, function(context){
   168          try{
   169            self.run_tasks(event_type_in_transaction, context, code.db_tasks);
   170          }catch(err){
   171            context.error = err;
   172          }
   173        });
   174      });
   175    }
   176  }
   177  
   178  donburi.register_plugin("define", function(event_type, context, value){
   179     var func_name = value.name;
   180     var tasks = value.tasks;
   181     donburi.register_plugin(func_name, function(event_type, context, value){
   182       var new_context = _.extend(context, value)
   183       return donburi.run_tasks(event_type, new_context, tasks);
   184     });
   185  });
   186  
   187  donburi.register_plugin("debug", function(event_type, context, value){
   188    console.log(value);
   189  });
   190  
   191  donburi.register_plugin("sleep", function(event_type, context, value){
   192    gohan_sleep(value);
   193  });
   194  
   195  donburi.register_plugin("block", function(event_type, context, value){
   196    donburi.run_tasks(event_type, context, value);
   197  });
   198  
   199  donburi.register_plugin("netconf_open", function(event_type, context, value){
   200  	return gohan_netconf_open(value.host, value.username)
   201  });
   202  
   203  donburi.register_plugin("netconf_exec", function(event_type, context, value){
   204      var command = donburi.apply_template(context, value.command);
   205  	with(context){
   206  		return gohan_netconf_exec(eval(value.connection), command)
   207  	}
   208  });
   209  
   210  donburi.register_plugin("netconf_close", function(event_type, context, value){
   211  	with(context){
   212  		gohan_netconf_close(eval(value))
   213  	}
   214  });
   215  
   216  donburi.register_plugin("ssh_open", function(event_type, context, value){
   217  	return gohan_ssh_open(value.host, value.username)
   218  });
   219  
   220  donburi.register_plugin("ssh_exec", function(event_type, context, value){
   221      var command = donburi.apply_template(context, value.command);
   222  	with(context){
   223  		return gohan_ssh_exec(eval(value.connection), command)
   224  	}
   225  });
   226  
   227  donburi.register_plugin("ssh_close", function(event_type, context, value){
   228  	with(context){
   229  		gohan_ssh_close(eval(value))
   230  	}
   231  });
   232  
   233  donburi.register_plugin("resources", function(event_type, context, value){
   234    if(event_type == "pre_delete" || event_type == "pre_delete_in_transaction"){
   235      var reversed = value.slice()
   236      reversed.reverse();
   237      donburi.run_tasks(event_type, context, reversed);
   238    }else{
   239      donburi.run_tasks(event_type, context, value);
   240    }
   241  });
   242  
   243  donburi.register_plugin("command", function(event_type, context, value){
   244    return gohan_exec(value.name, value.args);
   245  });
   246  
   247  donburi.register_plugin("eval", function(event_type, context, value){
   248    with(context){
   249      return eval(value);
   250    }
   251  });
   252  
   253  donburi.register_plugin("vars", function(event_type, context, value){
   254    _.each(value, function(value, key){
   255      context[key] = value;
   256    });
   257  });
   258  
   259  donburi.register_plugin("return", function(event_type, context, value){
   260    return value;
   261  });
   262  
   263  donburi.register_plugin("list", function(event_type, context, value){
   264    var transaction = context.transaction;
   265    var filter = value.filter || {};
   266    filter.tenant_id = value.tenant_id;
   267    return gohan_db_list(transaction, value.schema, filter);
   268  });
   269  
   270  donburi.register_plugin("fetch", function(event_type, context, value){
   271    var transaction = context.transaction;
   272    var value = gohan_db_fetch(transaction, value.schema, value.id, value.tenant_id);
   273    return value
   274  });
   275  
   276  donburi.register_plugin("resource", function(event_type, context, value){
   277    var transaction = context.transaction;
   278    if(event_type == "post_create_in_transaction" || event_type == "post_create"){
   279      if(_.isUndefined(value.id)){
   280        value.id = gohan_uuid();
   281      }
   282      value.properties.id = value.id;
   283      var result = gohan_db_create(transaction, value.schema, value.properties);
   284      return result;
   285    }
   286    var id = value.id;
   287    if(event_type == "post_update_in_transaction" || event_type == "post_update"){
   288      return gohan_db_update(transaction, value.schema, value.properties);
   289    }
   290    if(event_type == "pre_delete_in_transaction" || event_type == "pre_delete"){
   291      return gohan_db_delete(transaction, value.schema, id);
   292    }
   293    return
   294  });
   295  
   296  donburi.register_plugin("update", function(event_type, context, value){
   297    var transaction = context.transaction;
   298    var resource = gohan_db_fetch(transaction, value.schema, value.properties.id, "");
   299    if(_.isUndefined(resource)){
   300      return
   301    }
   302    _.each(value.properties, function(value, key){
   303      resource[key] = value;
   304    });
   305    return gohan_db_update(transaction, value.schema, resource);
   306  });
   307  
   308  donburi.register_plugin("delete", function(event_type, context, value){
   309    var transaction = context.transaction;
   310    return gohan_db_delete(transaction, value.schema, value.id);
   311  });
   312  
   313  donburi.register_plugin("contrail", function(event_type, context, value){
   314      var schema_id = value.schema;
   315      if(_.isUndefined(contrail_donburi[schema_id])){
   316        return contrail_donburi["generic"](event_type, context, value);
   317      }
   318      return contrail_donburi[schema_id](event_type, context, value);
   319  });
   320  
   321  donburi.register_plugin("contrail_fetch", function(event_type, context, value){
   322      var schema_id = value.schema;
   323      var id = value.id;
   324      var token = context.auth_token;
   325      return contrail_donburi.get_request(token, schema_id, id);
   326  });
   327  
   328  donburi.register_plugin("contrail_list", function(event_type, context, value){
   329      var schema_id = value.schema;
   330      var token = context.auth_token;
   331      return contrail_donburi.get_request(token, schema_id);
   332  });
   333  
   334  donburi.register_plugin("heat", function(event_type, context, value){
   335      return heat_donburi["stack"](event_type, context, value);
   336  });
   337  
   338  var contrail_donburi = {
   339    api_url: function(schema_id, id){
   340      if(_.isUndefined(id)){
   341        return CONTRAIL_URL + schema_id + "s";
   342      }
   343      return CONTRAIL_URL + schema_id + "/" + id;
   344    },
   345    create_request: function(schema_id, token, data){
   346      var self = this;
   347      var request = {};
   348      request[schema_id] = data;
   349      var response = gohan_http("POST", self.api_url(schema_id),
   350                        {"X-Auth-Token": token,
   351                         "Content-Type": "application/json"
   352                        },
   353                        request)
   354      var result = {}
   355      result.status_code = parseInt(response.status_code);
   356      result.body = response.body;
   357      if(result.status_code == 200){
   358        result["data"] = JSON.parse(response.body);
   359      }
   360      return result;
   361    },
   362    update_request: function(schema_id, token, id, data){
   363      var self = this;
   364      var request = {};
   365      request[schema_id] = data;
   366      var response = gohan_http("PUT", self.api_url(schema_id, id),
   367                        {"X-Auth-Token": token,
   368                         "Content-Type": "application/json"
   369                        },
   370                        request)
   371      var result = {}
   372      result.status_code = parseInt(response.status_code);
   373      result.body = response.body;
   374      if(result.status_code == 200){
   375        result["data"] = JSON.parse(response.body);
   376      }
   377      return result;
   378    },
   379    delete_request: function(schema_id, token, id){
   380      var self = this;
   381      var response = gohan_http(
   382        "DELETE",
   383        self.api_url(schema_id, id),
   384        {"X-Auth-Token": token}, null);
   385      var result = {}
   386      result.status_code = parseInt(response.status_code);
   387      result.body = response.body;
   388      return result;
   389    },
   390    get_request: function(token, schema_id, id){
   391      var self = this;
   392      var response = gohan_http(
   393        "GET",
   394        self.api_url(schema_id, id),
   395        {"X-Auth-Token": token}, null);
   396      var result = {}
   397      result.status_code = response.status_code;
   398      if(response.status_code == "200"){
   399        result["data"] = JSON.parse(response.body);
   400      }
   401      return result;
   402    },
   403    generic: function(event_type, context, value){
   404      var self = this;
   405      var transaction = context.transaction;
   406      var schema_id = value.schema;
   407      var token = context.auth_token;
   408      var data = value.properties;
   409  
   410      if(event_type == "post_create"){
   411        return self.create_request(schema_id, token, data);
   412      }
   413  
   414      var id = value.id;
   415      if(_.isUndefined(id) || id === ""){
   416        return;
   417      }
   418      if(event_type == "post_update"){
   419        var update_data = {};
   420        _.each(value.allow_update, function(key){
   421          update_data[key] = data[key];
   422        });
   423        if(update_data == {}){
   424            return;
   425        }
   426        return self.update_request(schema_id, token, id, update_data);
   427      }else if(event_type == "pre_delete"){
   428        return self.delete_request(schema_id, token, id);
   429      }
   430  
   431      return;
   432    },
   433    "virtual-network-subnet": function (event_type, context, value){
   434      var self = this;
   435      var token = context.auth_token;
   436      var network_id = value.network_id;
   437      var data = value.properties;
   438      var network_response = self.get_request(token, "virtual-network",  network_id);
   439      if( _.isUndefined(network_response.data)){
   440        return
   441      }
   442      var subnet_strings = data.subnet_cidr.split("/");
   443      data.subnet = {
   444        ip_prefix: subnet_strings[0],
   445        ip_prefix_len: parseInt(subnet_strings[1])
   446      }
   447      var network = network_response.data["virtual-network"];
   448      var network_ipam_refs = network["network_ipam_refs"];
   449      if(_.isUndefined(network_ipam_refs)){
   450        network_ipam_refs = [
   451          {
   452            "attr": {"ipam_subnets": []},
   453            "to": ["default-domain", "default-project", "default-network-ipam"]
   454          }];
   455       network["network_ipam_refs"] = network_ipam_refs;
   456      }
   457      var ipam_subnets = network_ipam_refs[0]["attr"]["ipam_subnets"];
   458      if(event_type == "post_create"){
   459        ipam_subnets.push(data);
   460      }
   461      if(event_type == "post_update"){
   462        _.each(ipam_subnets, function(subnet){
   463          if( subnet.subnet_uuid != data.subnet_uuid ){
   464            return
   465          }
   466          _.each(data, function(key){
   467            subnet[key] = data[key];
   468          });
   469        });
   470      }
   471      if(event_type == "pre_delete"){
   472        var new_ipam_subnets = []
   473        _.each(ipam_subnets, function(subnet){
   474          if( subnet.subnet_uuid != data.subnet_uuid ){
   475            new_ipam_subnets.push(subnet);
   476          }
   477        });
   478        network_ipam_refs[0]["attr"]["ipam_subnets"] = new_ipam_subnets;
   479      }
   480      var result = self.update_request("virtual-network", token, network_id, network);
   481      return result;
   482    }
   483  };
   484  
   485  //TODO(nati) This is experimental.
   486  //We need to use output on keystone context
   487  
   488  var heat_donburi = {
   489    api_url: function(url, schema_id, id){
   490      var base_url = url + "/" + schema_id + "s";
   491      if(_.isUndefined(id)){
   492        return base_url;
   493      }
   494      return base_url + "/" + id;
   495    },
   496    create_request: function(url, schema_id, token, data){
   497      var self = this;
   498      var response = gohan_http("POST", self.api_url(url, schema_id),
   499                        {"X-Auth-Token": token,
   500                         "Content-Type": "application/json"
   501                        },
   502                        data)
   503      var result = {}
   504      result.status_code = parseInt(response.status_code);
   505      result.body = response.body;
   506      if(result.status_code == 201){
   507        result["data"] = JSON.parse(response.body);
   508      }
   509      return result;
   510    },
   511    update_request: function(url, schema_id, token, id, data){
   512      var self = this;
   513      var request = {};
   514      request[schema_id] = data;
   515      var response = gohan_http("PUT", self.api_url(url, schema_id, id),
   516                        {"X-Auth-Token": token,
   517                         "Content-Type": "application/json"
   518                        },
   519                        request)
   520      var result = {}
   521      result.status_code = parseInt(response.status_code);
   522      if(result.status_code == 200){
   523        result["data"] = JSON.parse(response.body);
   524      }
   525      return result;
   526    },
   527    delete_request: function(url, schema_id, token, id){
   528      var self = this;
   529      var response = gohan_http(
   530        "DELETE",
   531        self.api_url(url, schema_id, id),
   532        {"X-Auth-Token": token}, null);
   533      var result = {}
   534      result.status_code = parseInt(response.status_code);
   535      return result;
   536    },
   537    get_request: function(url, schema_id, token, id){
   538      var self = this;
   539      var response = gohan_http(
   540        "GET",
   541        self.api_url(schema_id, id),
   542        {"X-Auth-Token": token}, null);
   543      var result = {}
   544      result.status_code = parseInt(response.status_code);
   545      if(response.status_code == 200){
   546        result["data"] = JSON.parse(response.body);
   547      }
   548      return result;
   549    },
   550    get_endpoint: function(context, endpoint_interface, type){
   551      var url = "";
   552      _.each(context.catalog, function(catalog){
   553        if(catalog.Type === type){
   554          _.each(catalog.Endpoints, function(endpoint){
   555            if(endpoint.Interface === endpoint_interface){
   556               url = endpoint.URL.replace("%(tenant_id)s", context.tenant);
   557            }
   558          });
   559        }
   560      })
   561      return url;
   562    },
   563    stack: function(event_type, context, value){
   564      var self = this;
   565      var transaction = context.transaction;
   566      var schema_id = "stack";
   567      var tenant_id = context.tenant;
   568      var token = context.auth_token;
   569      var stack_name = value.stack_name;
   570      var url = self.get_endpoint(context, "public", "orchestration");
   571      var data = {
   572        stack_name: stack_name,
   573        template: value.template,
   574      };
   575  
   576      if(event_type == "post_create"){
   577        var response = self.create_request(url, schema_id, token, data);
   578        return response;
   579      }
   580  
   581      var id = stack_name + "/" + value.id;
   582      if(_.isUndefined(id) || id === ""){
   583        return;
   584      }
   585      if(event_type == "post_update"){
   586        var update_data = {};
   587        _.each(value.allow_update, function(key){
   588          update_data[key] = data[key];
   589        });
   590        if(update_data == {}){
   591            return;
   592        }
   593        return self.update_request(url, schema_id, token, id, update_data);
   594      }else if(event_type == "pre_delete"){
   595        return self.delete_request(url, schema_id, token, id);
   596      }
   597  
   598      return;
   599    },
   600  };