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

oglive
Last change on this file since a3f2b23 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
Line 
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
29"""
30@author: Ramón M. Gómez, ramongomez at us dot es
31"""
32from __future__ import unicode_literals
33
34import socket
35import platform
36import os
37import fcntl
38import subprocess
39import struct
40import array
41import six
42import chardet
43from opengnsys import utils
44from opengnsys.log import logger
45
46
47def _getMacAddr(ifname):
48    """
49    Returns the mac address of an interface
50    Mac is returned as unicode utf-8 encoded
51    """
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):
65    """
66    Returns the ip address of an interface
67    Ip is returned as unicode utf-8 encoded
68    """
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():
85    """
86    Returns a list of interfaces names coded in utf-8
87    """
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)
111    return ip, mac
112
113
114def _exec_ogcommand(ogcmd):
115    """
116    Loads OpenGnsys environment variables, executes the command and returns the result
117    """
118    ret = subprocess.check_output(ogcmd, shell=True)
119    return ret
120
121
122def getComputerName():
123    """
124    Returns computer name, with no domain
125    """
126    return socket.gethostname().split('.')[0]
127
128
129def getNetworkInfo():
130    """
131    Obtains a list of network interfaces
132    :return: A "generator" of elements, that are dict-as-object, with this elements:
133      name: Name of the interface
134      mac: mac of the interface
135      ip: ip of the interface
136    """
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
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]
154
155
156def reboot():
157    """
158    Simple reboot using OpenGnsys script
159    """
160    # Workaround for dummy thread
161    if six.PY3 is False:
162        import threading
163        threading._DummyThread._Thread__stop = lambda x: 42
164
165    _exec_ogcommand('/opt/opengnsys/scripts/reboot')
166
167
168def poweroff():
169    """
170    Simple power off using OpenGnsys script
171    """
172    # Workaround for dummy thread
173    if six.PY3 is False:
174        import threading
175        threading._DummyThread._Thread__stop = lambda x: 42
176
177    _exec_ogcommand('/opt/opengnsys/scripts/poweroff')
178
179
180def get_etc_path():
181    """
182    Returns etc directory path.
183    """
184    return os.sep + 'etc'
185
186
187def get_configuration():
188    """
189    Returns client's configuration
190    Warning: this operation may take some time
191    :return:
192    """
193    try:
194        _exec_ogcommand('/opt/opengnsys/interfaceAdm/getConfiguration')
195        # Returns content of configuration file
196        cfgdata = open('/tmp/getconfig', 'r').read().strip()
197    except IOError:
198        cfgdata = ''
199    return cfgdata
200
201
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()
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
225    stat = proc.returncode
226    return stat, out, err
227
228
229def get_hardware():
230    """
231    Returns client's hardware list
232    :return:
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
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.