RackHD/on-http

View on GitHub
lib/api/redfish-1.0/managers.js

Summary

Maintainability
F
5 days
Test Coverage
// Copyright 2016, EMC, Inc.

'use strict';

var injector = require('../../../index.js').injector;
var redfish = injector.get('Http.Api.Services.Redfish');
var waterline = injector.get('Services.Waterline');
var Promise = injector.get('Promise');    // jshint ignore:line
var _ = injector.get('_');                // jshint ignore:line
var nodeApi = injector.get('Http.Services.Api.Nodes');
var controller = injector.get('Http.Services.Swagger').controller;
var Errors = injector.get('Errors');
var assert = injector.get('Assert');
var os = injector.get('os');
var dns = Promise.promisifyAll(require('dns'));
var ip = require('ip');
var configuration = injector.get('Services.Configuration');
var upnpService = injector.get('Http.Services.uPnP');

var reservedId = 'RackHD';

var dnsGetFQDN = function() {
    if(dns.lookupServiceAsync) {
        return dns.lookupServiceAsync(ip.address(), 0)
        .then(function(fqdns) {
            return fqdns[0];
        })
        .catch(function() {
            return os.hostname();
        });
    }
    return os.hostname();
};

var getRedfishDeviceResponse = function(nodeid, req) {
    var catalogSource = req.url.replace(req.swagger.params.identifier.value, nodeid);
    return nodeApi.getNodeCatalogSourceById(nodeid, catalogSource)
    .then(function(response) {
        return response.data;
    })
    .catch(function() {
        throw new Errors.NotImplementedError(req.url + ' Is Not Implemented on this Device');
    });
};

var listManagers = controller(function(req, res) {
    var options = redfish.makeOptions(req, res);
    return Promise.map(waterline.nodes.find({type: ['compute', 'redfishManager']}), function(node) {
        return waterline.nodes.getNodeById(node.id);
    })
    .then(function(nodes) {
        options.managers = _.reduce(nodes, function(arr, val) {
            if (typeof val.obms !== 'undefined' && val.obms.length > 0) {
                arr.push({ id: val.id});
            }
            return arr;
        }, []);
        options.managers.push({id: reservedId});
        return redfish.render('redfish.1.0.0.managercollection.json',
                            'ManagerCollection.json#/definitions/ManagerCollection',
                            options);
    }).catch(function(error) {
        return redfish.handleError(error, res);
    });
});

var getManager = controller(function(req, res) {
    var identifier = req.swagger.params.identifier.value;
    var options = redfish.makeOptions(req, res, identifier);
    return redfish.getVendorNameById(identifier)
    .catch(function() {return{};})
    .then(function(result) {
    if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function() {
                if(identifier === reservedId) {
                    return waterline.nodes.find({type: ['compute','redfish']});
                }
                return nodeApi.getNodeById(identifier)
                .then(function(){
                    assert.string(identifier, 'invalid identifier specified: ' + identifier);
                    return waterline.nodes.find({id: identifier});
                });
            })
            .then(function(nodes) {
                if (!nodes) {
                    throw new Errors.NotFoundError('identifier not found');
                }
                return Promise.map(nodes, function(node) {
                    return waterline.nodes.getNodeById(node.id);
                });
            })
            .then(function(node) {
                options.systems = _.map(node, 'id');
                options.chassis = _.reduce(node, function(arr,val) {
                    if(val.type === 'redfish'){
                        arr.push(val.id);
                    }
                    _.forEach(val.relations, function(val) {
                        if(val.relationType === 'enclosedBy')  {
                            arr.push(val.targets[0]);
                        }
                    });
                    return arr;
                }, []);

                var dellFound = (result.vendor === 'Dell');

                options.noSerial = ((identifier === reservedId) || (dellFound)) ? true : false;
                options.managerType = identifier === reservedId ? 'ManagementController' : 'BMC';
                if (identifier !== reservedId) {
                    if(!dellFound) {
                        return nodeApi.getNodeCatalogSourceById(node[0].id, 'ipmi-mc-info')
                        .then(function(mcInfo) {
                            options.mcInfo = mcInfo.data;
                        });
                    }
                    else {
                        return nodeApi.getNodeCatalogSourceById(node[0].id, 'dmi')
                        .then(function(dmi) {
                            options.mcInfo = dmi.data['System Information'];
                        });
                    }
                }
            })
            .then(function() {
                if(identifier === reservedId) {
                    var locations = _.filter(configuration.get('httpEndpoints', []),
                                    _.matches({routers:'northbound-api-router'}));
                    var httpLocation = _.find(locations, {httpsEnabled: false});
                    var httpsLocation = _.find(locations, {httpsEnabled: true});

                    var services = [];
                    if(httpLocation) {
                        services.push({ name: 'HTTP', port: httpLocation.port, enabled: true });
                    }
                    if(httpsLocation) {
                        services.push({ name: 'HTTPS', port: httpsLocation.port, enabled: true });
                    }
                    var enabled = _.find(upnpService.registry, {urn: 'urn:dmtf-org:service:redfish-rest:1.0'}).alive;
                    services.push({ name: 'SSDP', port: 1900, enabled: enabled });
                    return Promise.props({
                        hostname: os.hostname(),
                        fqdn: dnsGetFQDN(),
                        services: services
                    });
                }
            })
            .then(function(networkProtocol) {
                if(networkProtocol) {
                    options.networkProtocol = networkProtocol;
                }
                return redfish.render('redfish.1.0.0.manager.1.0.0.json',
                                    'Manager.v1_3_0.json#/definitions/Manager',
                                    options);
            });
        }
    })
    .catch(function(error) {
        if(error.name === 'AssertionError') {
            error = new Errors.NotFoundError('invalid resource: ' + error.message);
        }
        return redfish.handleError(error, res);
    });
});

var listManagerNetworkProtocol = controller(function(req, res) {
    var identifier = req.swagger.params.identifier.value;
    var options = redfish.makeOptions(req, res, identifier);

    return redfish.getVendorNameById(identifier)
    .catch(function() {return{};})
    .then(function(result) {
    if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function() {
                if(identifier === reservedId){
                    var services = [];
                    var locations = _.filter(configuration.get('httpEndpoints', []),
                                    _.matches({routers:'northbound-api-router'}));
                    var httpLocation = _.find(locations, {httpsEnabled: false});
                    var httpsLocation = _.find(locations, {httpsEnabled: true});
                    if(httpLocation) {
                        services.push({ name: 'HTTP', port: httpLocation.port, enabled: true });
                    }
                    if(httpsLocation) {
                        services.push({ name: 'HTTPS', port: httpsLocation.port, enabled: true });
                    }
                    var enabled = _.find(upnpService.registry, {urn: 'urn:dmtf-org:service:redfish-rest:1.0'}).alive;
                    services.push({ name: 'SSDP', port: 1900, enabled: enabled });
                    return Promise.props({
                        hostname: os.hostname(),
                        fqdn: dnsGetFQDN(),
                        services: services
                    })
                    .then(function(networkProtocol) {
                        if(networkProtocol) {
                            options.networkProtocol = networkProtocol;
                        }
                        return redfish.render('redfish.1.0.0.managernetworkprotocol.1.0.0.json',
                                            'ManagerNetworkProtocol.v1_1_0.json#/definitions/ManagerNetworkProtocol',
                                            options);
                    })
                    .catch(function(error) {
                        if(error.name === 'AssertionError') {
                            error = new Errors.NotFoundError('invalid resource: ' + error.message);
                        }
                    return redfish.handleError(error, res);
                    });
                }
                else{
                    return Promise.try(function() {
                        assert.string(identifier, 'invalid identifier specified: ' + identifier);
                        return waterline.nodes.needByIdentifier(identifier);
                    })
                    .then(function(node) {
                        if (!node) {
                            throw new Errors.NotFoundError('identifier not found');
                        }
                        return waterline.nodes.getNodeById(node.id);
                    })
                    .then(function(node) {
                        assert.ok(_.isArray(node.obms), 'invalid obmSettings');
                        assert.ok(node.obms.length > 0, 'invalid obmSetting');
                        options.networkProtocol = "";
                        return redfish.render('redfish.1.0.0.managernetworkprotocol.1.0.0.json',
                                            'ManagerNetworkProtocol.v1_1_0.json#/definitions/ManagerNetworkProtocol',
                                            options);
                    });
                }
            });
        }
    })
    .catch(function(error) {
        if(error.name === 'AssertionError') {
            error = new Errors.NotFoundError('invalid resource: ' + error.message);
        }
        return redfish.handleError(error, res);
    });
});

var patchManager = controller({success: 204}, function(req, res) {
    var identifier = req.swagger.params.identifier.value;
    var payload = req.swagger.params.payload.value;

    return Promise.try(function() {
        if(identifier === reservedId) {
            return waterline.nodes.find({type: 'compute'});
        }

        if(identifier !== reservedId) {
            var err = new Errors.BaseError('method not allowed');
            err.status = 405;
            throw err;
        }

        return waterline.nodes.find({id: identifier});
    })
    .then(function(nodes) {
        if(_.isEmpty(nodes)) {
            throw new Errors.NotFoundError('invalid resource');
        }

        if(!_.isUndefined(_.get(payload, 'NetworkProtocol.SSDP.ProtocolEnabled'))) {
            var server = _.find(upnpService.ssdpList, {urn: 'urn:dmtf-org:service:redfish-rest:1.0'});
            var registry = _.find(upnpService.registry, {urn: 'urn:dmtf-org:service:redfish-rest:1.0'});
            if(server && registry) {
                registry.alive = payload.NetworkProtocol.SSDP.ProtocolEnabled;
                registry.alive ? server.server.start() : server.server.stop();
            }
        }
    })
    .catch(function(error) {
        if(error.name === 'AssertionError') {
            error = new Errors.NotFoundError('invalid resource: ' + error.message);
        }
        return redfish.handleError(error, res);
    });
});

var listManagerEthernetInterfaces = controller(function(req, res) {
    var identifier = req.swagger.params.identifier.value;
    var options = redfish.makeOptions(req, res, identifier);

    return redfish.getVendorNameById(identifier)
    .then(function(result) {
    if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function() {
                assert.string(identifier, 'invalid identifier specified: ' + identifier);
                return waterline.nodes.needByIdentifier(identifier);
            })
            .then(function(node) {
                return waterline.nodes.getNodeById(node.id);
            })
            .then(function(node) {
                assert.ok(_.isArray(node.obms), 'invalid obmSettings');
                assert.ok(node.obms.length > 0, 'invalid obmSetting');
                options.name = "Manager Ethernet Interface Collection";
                options.net = [ '0' ];  // there is only one host per obmsetting
                options.baseprofile = 'Managers';
                return redfish.render('redfish.1.0.0.ethernetinterfacecollection.json',
                                    'EthernetInterfaceCollection.json#/definitions/EthernetInterfaceCollection',
                                    options);
            });
        }
    })
    .catch(function(error) {
        if(error.name === 'AssertionError') {
            error = new Errors.NotFoundError('invalid resource');
        }
        return redfish.handleError(error, res);
    });
});

var getManagerEthernetInterface = controller(function(req, res) {
    var identifier = req.swagger.params.identifier.value;
    var index = req.swagger.params.index.value;
    var options = redfish.makeOptions(req, res, identifier);

    return redfish.getVendorNameById(identifier)
    .then(function(result) {
    if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function() {
                assert.string(identifier, 'invalid identifier specified: ' + identifier);
                return waterline.nodes.needByIdentifier(identifier);
            })
            .then(function(node) {
                return waterline.nodes.getNodeById(node.id);
            })
            .then(function(node) {
                assert.ok(_.isArray(node.obms), 'invalid obmSettings');
                assert.ok(node.obms.length > 0, 'invalid obmSetting');
                return nodeApi.getNodeCatalogSourceById(node.id, 'bmc');
            })
            .then(function(data) {
                options.name = "Manager Ethernet Interface";
                options.baseprofile = 'Managers';
                options.index = index;
                options.permanentmacaddress = data.data['MAC Address'];
                options.macaddress = data.data['MAC Address'];
                if(data.data['802_1q VLAN ID'] !== 'Disabled') {
                    options.vlan = data.data['802_1q VLAN ID'];
                }
                options.ipv4 = [
                    {
                        ipaddr: data.data['IP Address'],
                        ipsubnet: data.data['Subnet Mask'],
                        ipgateway: data.data['Default Gateway IP'],
                        ipsrc: _.includes(data.data['IP Address Source'], 'DHCP') ? 'DHCP' : 'Static'
                    }
                ];
                return redfish.render('redfish.1.0.0.ethernetinterface.1.0.0.json',
                                    'EthernetInterface.v1_2_0.json#/definitions/EthernetInterface',
                                    options);
            });
        }
    })
    .catch(function(error) {
        if(error.name === 'AssertionError') {
            error = new Errors.NotFoundError('invalid resource');
        }
        return redfish.handleError(error, res);
    });
});

var listLocalEthernetInterfaces = controller(function(req, res) {
    var options = redfish.makeOptions(req, res);
    options.net = _.reduce(os.networkInterfaces(), function(arr, val, key) {
        _.forEach(val, function(item) {
            if(!item.internal && item.family === 'IPv4') {
                arr.push(key);
            }
        });
        return arr;
    }, []);
    options.name = "Manager Ethernet Interface Collection";
    options.baseprofile = 'Managers';
    options.identifier = reservedId;
    return redfish.render('redfish.1.0.0.ethernetinterfacecollection.json',
                          'EthernetInterfaceCollection.json#/definitions/EthernetInterfaceCollection',
                          options)
    .catch(function(error) {
        return redfish.handleError(error, res);
    });
});

var getLocalEthernetInterface = controller(function(req, res) {
    var options = redfish.makeOptions(req, res);
    var index = req.swagger.params.index.value;
    return Promise.try(function() {
    var net = _.get(os.networkInterfaces(), index);
    if(!net) {
        throw new Errors.NotFoundError('invalid resource');
    }

    options.name = "Manager Ethernet Interface";
    options.baseprofile = 'Managers';
    options.index = index;
    options.ipv4 = _.reduce(net, function(arr, val) {
        if(!val.internal && val.family === 'IPv4') {
            var obj = {
                ipaddr: val.address
            };
            if(val.netmask) {  // not available in node 0.10
                obj.ipsubnet = val.netmask;
            }
            if(val.mac) { // not available in node 0.10
                options.permanentmacaddress = val.mac;
                options.macaddress = val.mac;
            }
            arr.push(obj);
        }
        return arr;
    }, []);
    return redfish.render('redfish.1.0.0.ethernetinterface.1.0.0.json',
                          'EthernetInterface.v1_2_0.json#/definitions/EthernetInterface',
                          options);
    })
    .catch(function(error) {
        return redfish.handleError(error, res);
    });
});

var listManagerSerialInterfaces = controller(function (req, res) {
    var identifier = req.swagger.params.identifier.value;
    var options = redfish.makeOptions(req, res, identifier);

    return redfish.getVendorNameById(identifier)
    .catch(function() {return{};})
    .then(function(result) {
    if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function() {
                if(identifier === reservedId){
                    throw new Errors.NotFoundError();
                }
                return waterline.nodes.getNodeById(identifier);
            })
            .then(function() {
                if(result.vendor === 'Dell'){
                    throw new Errors.NotFoundError();
                }
                return nodeApi.getNodeCatalogSourceById(identifier, 'dmi');
            })
            .then(function (catalog) {
                var  arr = [];
                if (catalog.length !== 0) {
                    _.forEach(catalog.data['Port Connector Information'], function (item) {
                        if (item['Port Type'].match(/Serial/i)) {
                            item['External Reference Designator'] = item['External Reference Designator'].replace(/ /g, '');
                            arr.push(item);
                        }
                    });
                }
                return arr;
            }).then(function (interfaces) {
                options.interface = interfaces;
                options.name = "Manager Ethernet Interface Collection";
                options.baseprofile = 'Managers';
                return redfish.render('redfish.1.0.0.serialinterfacecollection.json',
                                    'SerialInterfaceCollection.json#/definitions/SerialInterfaceCollection',
                                    options);
            });
        }
    })
    .catch(function (error) {
        return redfish.handleError(error, res);
    });
});

var getManagerSerialInterface = controller(function (req, res) {
    var identifier = req.swagger.params.identifier.value;
    var options = redfish.makeOptions(req, res);
    var index = req.swagger.params.index.raw;

    return redfish.getVendorNameById(identifier)
    .catch(function() {return{};})
    .then(function(result) {
        if (result.vendor === 'Redfish') {
            return getRedfishDeviceResponse(identifier, req);
        } else {
            return Promise.try(function () {
                if(identifier === reservedId){
                    throw new Errors.NotFoundError();
                }
                return waterline.nodes.getNodeById(identifier);
            })
            .then(function() {
                if(result.vendor === 'Dell') {
                    throw new Errors.NotFoundError();
                }
                return nodeApi.getNodeCatalogSourceById(identifier, 'dmi');
            })
            .then(function (catalog) {
                var  arr = [];
                assert.ok(catalog.length !== 0, 'Catalog not found');
                _.forEach(catalog.data['Port Connector Information'], function (item) {
                    if (item['Port Type'].match(/Serial/i) && item['External Reference Designator'].replace(/ /g, '') === index) {
                        item['External Reference Designator'] = item['External Reference Designator'].replace(/ /g, '');
                        arr.push(item);
                        options.name = "Managed Serial Interface";
                        options.description = item['Port Type'];
                        options.Id = index;
                        options.baseprofile = 'Managers';
                        options.interfaceEnabled = true;
                        if (item['External Connector Type'] === "DB-9 male") {
                            options.connectorType = "DB9 Male."; // Currently the schema checks for this exact entry
                        }
                    }
                });
                return redfish.render('redfish.1.0.0.serialinterface.1.0.0.json',
                                    'SerialInterface.v1_0_3.json#/definitions/SerialInterface',
                                    options);
            });
        }
    })
    .catch(function (error) {
        return redfish.handleError(error, res);
    });
});

module.exports = {
    listManagers: listManagers,
    getManager: getManager,
    listManagerNetworkProtocol: listManagerNetworkProtocol,
    patchManager: patchManager,
    listManagerEthernetInterfaces: listManagerEthernetInterfaces,
    getManagerEthernetInterface: getManagerEthernetInterface,
    listLocalEthernetInterfaces: listLocalEthernetInterfaces,
    getLocalEthernetInterface: getLocalEthernetInterface,
    listManagerSerialInterfaces: listManagerSerialInterfaces,
    getManagerSerialInterface: getManagerSerialInterface
};