source: ogAgent-Git/src/opengnsys/oglive/operations.py @ a0bd02c

oglive
Last change on this file since a0bd02c was fb14057, checked in by Ramón M. Gómez <ramongomez@…>, 5 years ago

Bug fixed when out and err are None in operation exec_command

  • Property mode set to 100644
File size: 7.8 KB
RevLine 
[983213c]1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2014 Virtual Cable S.L.
4# All rights reserved.
5#
6# Redistribution and use in source and binary forms, with or without modification,
7# are permitted provided that the following conditions are met:
8#
9#    * Redistributions of source code must retain the above copyright notice,
10#      this list of conditions and the following disclaimer.
11#    * Redistributions in binary form must reproduce the above copyright notice,
12#      this list of conditions and the following disclaimer in the documentation
13#      and/or other materials provided with the distribution.
14#    * Neither the name of Virtual Cable S.L. nor the names of its contributors
15#      may be used to endorse or promote products derived from this software
16#      without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
[be334a5]29"""
[983213c]30@author: Ramón M. Gómez, ramongomez at us dot es
[be334a5]31"""
[983213c]32from __future__ import unicode_literals
33
34import socket
35import platform
[16c3792]36import os
[983213c]37import fcntl
38import subprocess
39import struct
40import array
41import six
[2ac6daa]42import chardet
[983213c]43from opengnsys import utils
[8055b13]44from opengnsys.log import logger
[983213c]45
46
47def _getMacAddr(ifname):
[be334a5]48    """
[983213c]49    Returns the mac address of an interface
50    Mac is returned as unicode utf-8 encoded
[be334a5]51    """
[983213c]52    if isinstance(ifname, list):
53        return dict([(name, _getMacAddr(name)) for name in ifname])
54    if isinstance(ifname, six.text_type):
55        ifname = ifname.encode('utf-8')  # If unicode, convert to bytes (or str in python 2.7)
56    try:
57        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
58        info = bytearray(fcntl.ioctl(s.fileno(), 0x8927, struct.pack(str('256s'), ifname[:15])))
59        return six.text_type(''.join(['%02x:' % char for char in info[18:24]])[:-1])
60    except Exception:
61        return None
62
63
64def _getIpAddr(ifname):
[be334a5]65    """
[983213c]66    Returns the ip address of an interface
67    Ip is returned as unicode utf-8 encoded
[be334a5]68    """
[983213c]69    if isinstance(ifname, list):
70        return dict([(name, _getIpAddr(name)) for name in ifname])
71    if isinstance(ifname, six.text_type):
72        ifname = ifname.encode('utf-8')  # If unicode, convert to bytes (or str in python 2.7)
73    try:
74        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
75        return six.text_type(socket.inet_ntoa(fcntl.ioctl(
76            s.fileno(),
77            0x8915,  # SIOCGIFADDR
78            struct.pack(str('256s'), ifname[:15])
79        )[20:24]))
80    except Exception:
81        return None
82
83
84def _getInterfaces():
[be334a5]85    """
[983213c]86    Returns a list of interfaces names coded in utf-8
[be334a5]87    """
[983213c]88    max_possible = 128  # arbitrary. raise if needed.
89    space = max_possible * 16
90    if platform.architecture()[0] == '32bit':
91        offset, length = 32, 32
92    elif platform.architecture()[0] == '64bit':
93        offset, length = 16, 40
94    else:
95        raise OSError('Unknown arquitecture {0}'.format(platform.architecture()[0]))
96
97    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
98    names = array.array(str('B'), b'\0' * space)
99    outbytes = struct.unpack(str('iL'), fcntl.ioctl(
100        s.fileno(),
101        0x8912,  # SIOCGIFCONF
102        struct.pack(str('iL'), space, names.buffer_info()[0])
103    ))[0]
104    namestr = names.tostring()
105    # return namestr, outbytes
106    return [namestr[i:i + offset].split(b'\0', 1)[0].decode('utf-8') for i in range(0, outbytes, length)]
107
108
109def _getIpAndMac(ifname):
110    ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
[be334a5]111    return ip, mac
[983213c]112
113
[be334a5]114def _exec_ogcommand(ogcmd):
115    """
[983213c]116    Loads OpenGnsys environment variables, executes the command and returns the result
[be334a5]117    """
118    ret = subprocess.check_output(ogcmd, shell=True)
[983213c]119    return ret
120
121
122def getComputerName():
[be334a5]123    """
[983213c]124    Returns computer name, with no domain
[be334a5]125    """
[983213c]126    return socket.gethostname().split('.')[0]
127
128
129def getNetworkInfo():
[be334a5]130    """
[983213c]131    Obtains a list of network interfaces
[be334a5]132    :return: A "generator" of elements, that are dict-as-object, with this elements:
[983213c]133      name: Name of the interface
134      mac: mac of the interface
135      ip: ip of the interface
[be334a5]136    """
[983213c]137    for ifname in _getInterfaces():
138        ip, mac = _getIpAndMac(ifname)
139        if mac != '00:00:00:00:00:00':  # Skips local interfaces
140            yield utils.Bunch(name=ifname, mac=mac, ip=ip)
141
142
143def getDomainName():
144    return ''
145
146
[be334a5]147def get_oglive_version():
148    """
149    Returns ogLive Kernel version and architecture
150    :return: kernel version
151    """
152    kv = platform.os.uname()
153    return kv[2] + ', ' + kv[4]
[983213c]154
155
156def reboot():
[be334a5]157    """
[983213c]158    Simple reboot using OpenGnsys script
[be334a5]159    """
[983213c]160    # Workaround for dummy thread
161    if six.PY3 is False:
162        import threading
163        threading._DummyThread._Thread__stop = lambda x: 42
164
[be334a5]165    _exec_ogcommand('/opt/opengnsys/scripts/reboot')
[983213c]166
167
168def poweroff():
[be334a5]169    """
[f0c847c]170    Simple power off using OpenGnsys script
[be334a5]171    """
[983213c]172    # Workaround for dummy thread
173    if six.PY3 is False:
174        import threading
175        threading._DummyThread._Thread__stop = lambda x: 42
176
[be334a5]177    _exec_ogcommand('/opt/opengnsys/scripts/poweroff')
[983213c]178
179
[16c3792]180def get_etc_path():
181    """
182    Returns etc directory path.
183    """
184    return os.sep + 'etc'
185
186
[863e038]187def get_configuration():
[be334a5]188    """
[863e038]189    Returns client's configuration
[be334a5]190    Warning: this operation may take some time
[f0c847c]191    :return:
[be334a5]192    """
[983213c]193    try:
194        _exec_ogcommand('/opt/opengnsys/interfaceAdm/getConfiguration')
[bb1ff4d]195        # Returns content of configuration file
196        cfgdata = open('/tmp/getconfig', 'r').read().strip()
[983213c]197    except IOError:
198        cfgdata = ''
199    return cfgdata
[863e038]200
201
[ddd54ee]202def exec_command(cmd):
203    """
204    Executing a shell command
205    :param cmd:
206    :return: object with components:
207      output: standard output
208      error: error output
209      exit: exit code
210    """
211    proc = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
212    (out, err) = proc.communicate()
[8055b13]213    try:
214        if out is not None:
215            encoding = chardet.detect(out)["encoding"]
216            if encoding is not None:
217                out = out.decode(encoding).encode("utf8")
218        if err is not None:
219            encoding = chardet.detect(err)["encoding"]
220            if encoding is not None:
221                err = err.decode(encoding).encode("utf8")
222    except Exception as e:
223        logger.debug("ERROR EXEC COMMAND: {}".format(str(e)))
224
[ddd54ee]225    stat = proc.returncode
[fb14057]226    return stat, out, err
[ddd54ee]227
228
[863e038]229def get_hardware():
230    """
231    Returns client's hardware list
[f0c847c]232    :return:
[863e038]233    """
234    try:
235        filepath = _exec_ogcommand('/opt/opengnsys/scripts/listHardwareInfo').strip()
236        # Returns content of configuration file, skipping the header line and newline characters
237        with open(filepath, 'r') as f:
238            harddata = map(str.strip, f.readlines()[1:])
239    except IOError:
240        harddata = ''
241    return harddata
[f0c847c]242
243
244def get_software(disk, part):
245    """
246    Returns software list installed on an operating system
247    :param disk:
248    :param part:
249    :return:
250    """
251    try:
252        filepath = _exec_ogcommand('/opt/opengnsys/scripts/listSoftwareInfo {} {}'.format(disk, part)).strip()
253        # Returns content of configuration file, skipping the header line and newline characters
254        with open(filepath, 'r') as f:
255            softdata = map(str.strip, f.readlines())
256    except IOError:
257        softdata = ''
258    return softdata
Note: See TracBrowser for help on using the repository browser.