Just for review too


var base = require("../../client/base"),
    error = require("../../client/error"),
    urljoin = require("../../client/utils").urljoin;


var ServerManager = base.Manager.extend({
  namespace: "servers",

  get_base_url: function (params) {
    var base_url = this._super(params);
    if (params.detail) {
      base_url = this.urljoin(base_url, 'detail');
    }
    return base_url;
  },

  get: function (params, callback) {
    // get_addresses_for_instance also uses this method, so let's not
    // clobber our parsing functions.
    if (!params.parseResult) {
      params.parseResult = function (result) {
        Object.keys(result.addresses).forEach(function (network_name) {
          result.addresses[network_name].forEach(function (address) {
            address.network = network_name;
          });
        });
        return result;
      };
    }
    return this._super(params, callback);
  },

  all: function (params, callback) {
    if (typeof params.detail === "undefined") params.detail = true;
    params.parseResult = function (results) {
      results.forEach(function (item) {
        Object.keys(item.addresses).forEach(function (network_name) {
          item.addresses[network_name].forEach(function (address) {
            address.network = network_name;
          });
        });
      });
      return results;
    };
    return this._super(params, callback);
  },

  create: function (params, callback) {
    if (!params.data.name) {
      params.data.name = null;
    }

    // Convenience method for simplest boot-from-volume case; parity with boot from image.
    // NOT REFLECTIVE OF THE UNDERLYING API.
    // TODO: Support full block device mapping featureset.
    if (params.data.volumeRef && !params.data.imageRef) {
      params.data.block_device_mapping = [{
        device_name: 'vda',
        source_type: 'volume',
        volume_id: params.data.volumeRef,
        delete_on_termination: 0,
        boot_index: 0,
        uuid: params.data.volumeRef
      }];
      delete params.data.volumeRef;
    }

    if (params.data.scheduler_hints) {
      params.data['os:scheduler_hints'] = params.data.scheduler_hints;
      delete params.data.scheduler_hints;
    }

    // Base64 encode user data if present
    if (params.data.user_data) {
      // Use Buffer built-in if in Node, otherwise use btoa in the browser
      if (typeof Buffer !== 'undefined') {
        params.data.user_data = new Buffer(params.data.user_data).toString('base64');
      } else {
        params.data.user_data = btoa(params.data.user_data);
      }
    }
    console.log('***************************')
    console.log(params);
    console.log('***************************')
    return this._super(params, callback);
  },

  security_groups: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-security-groups");
    params.result_key = 'security_groups';
    params = this.prepare_params(params, url, "singular");
    return this.client.get(params, callback);
  },

  attachments: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-volume_attachments");
    params.result_key = 'volumeAttachments';
    params = this.prepare_params(params, url, "singular");
    return this.client.get(params, callback);
  },

  attach: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-volume_attachments");
    params.result_key = 'volumeAttachment';
    params.data.device = params.data.device || null;
    params = this.prepare_params(params, url, "singular");
    params.data.volumeAttachment = {
        volumeId: params.data.server.server,
        device: params.data.server.device
    };
    delete params.data.server;
    return this.client.post(params, callback);
  },

  detach: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-volume_attachments", params.data.volumeId);
    delete params.data;
    params = this.prepare_params(params, url, "singular");
    return this.client.del(params, callback);
  },

  volumes: function (params, callback) {
    var Cinder = require("../../cinder/v1/client");  // Avoid circular imports.

    var manager = this,
        cinder = new Cinder(this.client),
        success = params.success,
        error = params.error;

    if (params.success) delete params.success;
    if (params.error) delete params.error;

    return this.attachments(params, function (err, results, xhr) {
      if (err) return manager.safe_complete(err, null, xhr, {error: error}, callback);

      var new_params = {
        success: success,
        error: error,
        data: {
          ids: []
        }
      };

      results.forEach(function (result) {
        new_params.data.ids.push(result.id);
      });

      cinder.volumes.in_bulk(new_params, callback);
    });
  },

  _action: function (params, action, info, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "action");
    if (params.data && params.data.id) delete params.data.id;
    params = this.prepare_params(params, url, "singular");
    params.data[action] = info || null;
    delete params.data.server
    return this.client.post(params, callback);
  },

  addInterface: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-interface");
    params.url = url;
    return this.client.post(params, callback);
  },

  removeInterface: function (params, callback) {
    var url = urljoin(this.get_base_url(params), params.id || params.data.id, "os-interface", params.data);
    params.url = url;
    delete params.data;
    return this.client.del(params, callback);
  },

  reboot: function (params, callback) { return this._action(params, "reboot", params.data, callback); },

  migrate: function (params, callback) { return this._action(params, "migrate", null, callback); },

  stop: function (params, callback) { return this._action(params, "os-stop", null, callback); },
  start: function (params, callback) { return this._action(params, "os-start", null, callback); },

  pause: function (params, callback) { return this._action(params, "pause", null, callback); },
  unpause: function (params, callback) { return this._action(params, "unpause", null, callback); },

  lock: function (params, callback) { return this._action(params, "lock", null, callback); },
  unlock: function (params, callback) { return this._action(params, "unlock", null, callback); },

  suspend: function (params, callback) { return this._action(params, "suspend", null, callback); },
  resume: function (params, callback) { return this._action(params, "resume", null, callback); },

  rescue: function (params, callback) { return this._action(params, "rescue", null, callback); },
  resize: function (params, callback) {
    var extra = {
      flavorRef: params.data.flavorRef
    }
    return this._action(params, "resize", extra, callback);
  },
  unrescue: function (params, callback) { return this._action(params, "unrescue", null, callback); },

  set_active_state: function (params, callback) { return this._action(params, "os-resetState", {state: "active"}, callback); },
  set_error_state: function (params, callback) { return this._action(params, "os-resetState", {state: "error"}, callback); },

  snapshot: function (params, callback) {
    var extra = {name: params.data.name, metadata: {}};
    params.id = params.id || params.data.id;
    params.data = {};
    return this._action(params, "createImage", extra, callback);
  },

  getAvailableHost: function (params, callback) {
    var instance_id = params.id || params.data.id;
    params.result_key = "avhosts";
    params.parseResult = function (result) {
      return result
    }
    return this._action(params, "avhosts", {}, callback);
  },

  forceDelete: function (params, callback) {
    return this._action(params, "forceDelete", null, callback);
  },

  restore: function (params, callback) {
    return this._action(params, "restore", null, callback);
  },

  live_migrate: function (params, callback) {
    var block_migrate = params.data.block_migrate || false,
        disk_over_commit = params.data.disk_over_commit || false,
        host = params.data.host;
    var opts = {
        "disk_over_commit": disk_over_commit,
        "block_migration": block_migrate,
        "host": host
    }
    return this._action(params, "os-migrateLive", opts, callback);
  },

  getConsole: function (params, callback) {
    var instance_id = params.id || params.data.id,
        type = params.data.type || "novnc",
        action = type === "spice-html5" ? "os-getSPICEConsole" : "os-getVNCConsole";
    params.result_key = "console";
    params.parseResult = function (result) {
      result.id = instance_id;
      return result;
    };
    return this._action(params, action, {"type": type}, callback);
  },

  getLog: function (params, callback) {
    params.id = params.id || params.data.id;
    params.result_key = "output";
    params.parseResult = function (result) {
      return {id: params.id, data: result};
    };
    if (params.data.length) {
      query = {length: params.data.length}
    } else {
      query = {}
    }
    return this._action(params, "os-getConsoleOutput", query, callback);
  },

  get_addresses_for_instance: function (params, callback) {
    // Convenience method for returning all the addresses associated with
    // the specific instance in a flattened list-friendly format. Useful for
    // making selects for floating IP management, etc.
    params.parseResult = function (result) {
      var addresses = [];
      Object.keys(result.addresses).forEach(function (network_name) {
        result.addresses[network_name].forEach(function (address) {
          address.id = address.addr;
          address.network = network_name;
          addresses.push(address);
        });
      });
      return addresses;
    };
    this.get(params, callback);
  },

  add_floating_ip: function (params, callback) {
    var manager = this,
        fixed_address = params.data.fixed_address;

    function finish(address) {
      delete params.data;
      var data = {'address': address};
      if (fixed_address) data.fixed_address = fixed_address;
      return manager._action(params, 'addFloatingIp', data, callback);
    }

    params.id = params.id || params.data.id;
    if (params.data && params.data.address) {
      return finish(params.data.address);
    } else {
      var client = this.client;
      return client.floating_ips.all({
        success: function (ips) {
          var available;

          ips.forEach(function (ip) {
            if (available) return;
            if (!ip.instance_id) available = ip.ip;
          });

          if (available) {
            return finish(available);
          } else {
            client.floating_ips.create({
              success: function (ip) {
                return finish(ip.ip);
              },
              error: function (err, xhr) {
                manager.safe_complete(err, null, xhr, params, callback);
              }
            });
          }
        },
        error: function (err, xhr) {
          manager.safe_complete(err, null, xhr, params, callback);
        }
      });
    }
  },

  remove_floating_ip: function (params, callback) {
    var manager = this;

    function finish(address) {
      delete params.data;
      return manager._action(params, 'removeFloatingIp', {'address': address}, callback);
    }

    params.id = params.id || params.data.id;
    if (params.data && params.data.address) {
      return finish(params.data.address);
    } else {
      var client = this.client;
      return client.floating_ips.all({
        success: function (ips) {
          var associated;

          ips.forEach(function (ip) {
            if (associated) return;
            if (ip.instance_id === params.id) associated = ip.ip;
          });

          if (associated) {
            return finish(associated);
          } else {
            var err = {
              message: 'No floating IP associated with this instance.',
              status: 400
            };
            manager.safe_complete(err, null, {status: 400}, params, callback);
          }
        },
        error: function (err, xhr) {
          manager.safe_complete(err, null, xhr, params, callback);
        }
      });
    }
  },

  // TODO: Methods implemented by python-novaclient which are not yet implemented here...
  // add_fixed_ip
  // remove_fixed_ip
  // add_security_group
  // remove_security_group
  // resize
  // rebuild
  // confirm_resize
  // revert_resize
  // backup
  // set_meta
  // delete_meta
  // live_migrate
  // change_password
  // diagnostics
  // actions

  _rpc_to_api: function (rpc) {
    // Utility method to convert an RPC "notification"-style object into one
    // which resembles data returned by the API for compatibility purposes.
    var api = {};
    api.id = rpc.instance_id;
    api.name = rpc.display_name;
    api.user_id = rpc.user_id;
    api.tenant_id = rpc.tenant_id;
    api.status = rpc.state.toUpperCase();
    api["OS-EXT-STS:task_state"] = (rpc.state_description ? rpc.state_description : null);
    api["OS-EXT-STS:vm_state"] = (rpc.state ? rpc.state : null);
    //api["OS-EXT-AZ:availability_zone"] = rpc.availability_zone;  // Not sure this can be trusted.
    api.created = rpc.created_at.replace(//s/g, '').replace(/(/d{4})-(/d{2})-(/d{2})([/d:]+)+.*/, "$1-$2-$3T$4Z");
    api.accessIPv4 = rpc.access_ip_v4;
    api.accessIPv6 = rpc.access_ip_v6;
    api.metadata = rpc.metadata;
    api.flavor = {id: rpc.instance_flavor_id};
    api.image = {id: rpc.image_meta.base_image_ref};
    if (rpc.fixed_ips) {
      api.addresses = {};
      rpc.fixed_ips.forEach(function (ip) {
        if (!api.addresses[ip.label]) api.addresses[ip.label] = [];
        api.addresses[ip.label].push({
          version: ip.version,
          addr: ip.address,
          "OS-EXT-IPS:type": ip.type
        });
        // ip.floating_ips.forEach(function (floating) {});  // Can't get a notification show up when this is populated...
      });
    }
    return api;
  }
});


module.exports = ServerManager;

发表评论

电子邮件地址不会被公开。 必填项已用*标注

您可以使用这些HTML标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>