source: ogAgent-Git/src/opengnsys/macos/operations.py @ 67d5e81

configure-ptt-chedecorare-oglive-methodsejecutarscript-b64fix-cfg2objfixes-winlgromero-filebeatmainmodulesnew-browserno-ptt-paramogadmcliogadmclient-statusogcore1oglogoglog2override-moduleping1ping2ping3ping4report-progresstlsunification2unification3
Last change on this file since 67d5e81 was 64dea9f, checked in by Natalia Serrano <natalia.serrano@…>, 10 months ago

refs #474 #475 #476 fix agent for macos

  • Property mode set to 100644
File size: 8.6 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: Adolfo Gómez, dkmaster at dkmon dot com
31'''
32
33
34import socket
35import platform
36import fcntl
37import os
38import locale
39import ctypes  # @UnusedImport
40import ctypes.util
41import subprocess
42import struct
43import array
44import six
45import json
46from opengnsys import utils
47
48ip_a_s = None
49
50## make sure /usr/local/bin is in PATH
51## we need that to run /usr/local/bin/ip, which uses 'env' and pulls from PATH anyway
52def check_path():
53    path = os.getenv ('PATH', '')
54    usr_local_bin = '/usr/local/bin'
55
56    if usr_local_bin not in path.split (os.pathsep):
57        os.environ['PATH'] = usr_local_bin + os.pathsep + path
58
59def _getMacAddr(ifname):
60    '''
61    Returns the mac address of an interface
62    Mac is returned as unicode utf-8 encoded
63    '''
64    for interface in ip_a_s:
65        if interface.get ('ifname') != ifname: continue
66        return interface.get ('address')
67    return None
68
69
70def _getIpAddr(ifname):
71    '''
72    Returns the first IP address of an interface
73    IPv4 is preferred over IPv6
74    IP is returned as unicode utf-8 encoded
75    '''
76
77    ## loop and return the first IPv4 address found
78    for interface in ip_a_s:
79        if interface.get ('ifname') != ifname: continue
80        for addr_info in interface.get ('addr_info', []):
81            ip_address = addr_info.get ('local')
82            try:
83                ip_address.index ('.')
84                return ip_address
85            except: pass
86
87    ## if nothing found, loop again and return the first IP found, which will be an IPv6
88    for interface in ip_a_s:
89        if interface.get ('ifname') != ifname: continue
90        for addr_info in interface.get ('addr_info', []):
91            return addr_info.get ('local')
92
93    return None
94
95
96def _getInterfaces():
97    '''
98    Returns a list of interfaces names
99    '''
100    global ip_a_s
101
102    check_path()
103    result = subprocess.run (['/usr/local/bin/ip', '-json', 'address', 'show'], capture_output=True, text=True)
104
105    if result.returncode != 0: raise Exception (f'Command "ip" failed with exit code {result.returncode}')
106    ip_a_s = json.loads (result.stdout)
107    return [i.get('ifname') for i in ip_a_s]
108
109
110def _getIpAndMac(ifname):
111    ip, mac = _getIpAddr(ifname), _getMacAddr(ifname)
112    return (ip, mac)
113
114
115def getComputerName():
116    '''
117    Returns computer name, with no domain
118    '''
119    return socket.gethostname().split('.')[0]
120
121
122def getNetworkInfo():
123    '''
124    Obtains a list of network interfaces
125    @return: A "generator" of elements, that are dict-as-object, with this elements:
126      name: Name of the interface
127      mac: mac of the interface
128      ip: ip of the interface
129    '''
130    for ifname in _getInterfaces():
131        ip, mac = _getIpAndMac(ifname)
132        if mac != None and ip != None:  # Skips local interfaces
133            yield utils.Bunch(name=ifname, mac=mac, ip=ip)
134
135
136def getDomainName():
137    return ''
138
139
140def getMacosVersion():
141    return 'macOS {}'.format(platform.mac_ver()[0])
142
143
144def reboot(flags=0):
145    '''
146    Simple reboot command
147    '''
148    # Workaround for dummy thread
149    if six.PY3 is False:
150        import threading
151        threading._DummyThread._Thread__stop = lambda x: 42
152
153    # Exec reboot command
154    subprocess.call('/sbin/shutdown -r now', shell=True)
155
156
157def poweroff(flags=0):
158    '''
159    Simple poweroff command
160    '''
161    # Workaround for dummy thread
162    if six.PY3 is False:
163        import threading
164        threading._DummyThread._Thread__stop = lambda x: 42
165
166    # Exec shutdown command
167    subprocess.call('/sbin/shutdown -h now', shell=True)
168
169
170def logoff():
171    '''
172    Simple logout using AppleScript
173    '''
174    # Workaround for dummy thread
175    if six.PY3 is False:
176        import threading
177        threading._DummyThread._Thread__stop = lambda x: 42
178
179    # Exec logout using AppleScript
180    subprocess.call('/usr/bin/osascript -e \'tell app "System Events" to «event aevtrlgo»\'', shell=True)
181
182
183def renameComputer(newName):
184    rename(newName)
185
186
187def joinDomain(domain, ou, account, password, executeInOneStep=False):
188    pass
189
190
191def changeUserPassword(user, oldPassword, newPassword):
192    '''
193    Simple password change for user using command line
194    '''
195    os.system('echo "{1}\n{1}" | /usr/bin/passwd {0} 2> /dev/null'.format(user, newPassword))
196
197
198class XScreenSaverInfo(ctypes.Structure):
199    _fields_ = [('window', ctypes.c_long),
200                ('state', ctypes.c_int),
201                ('kind', ctypes.c_int),
202                ('til_or_since', ctypes.c_ulong),
203                ('idle', ctypes.c_ulong),
204                ('eventMask', ctypes.c_ulong)]
205
206# Initialize xlib & xss
207try:
208    xlibPath = ctypes.util.find_library('X11')
209    xssPath = ctypes.util.find_library('Xss')
210    xlib = ctypes.cdll.LoadLibrary(xlibPath)
211    xss = ctypes.cdll.LoadLibrary(xssPath)
212
213    # Fix result type to XScreenSaverInfo Structure
214    xss.XScreenSaverQueryExtension.restype = ctypes.c_int
215    xss.XScreenSaverAllocInfo.restype = ctypes.POINTER(XScreenSaverInfo)  # Result in a XScreenSaverInfo structure
216except Exception:  # Libraries not accesible, not found or whatever..
217    xlib = xss = None
218
219
220def initIdleDuration(atLeastSeconds):
221    '''
222    On linux we set the screensaver to at least required seconds, or we never will get "idle"
223    '''
224    # Workaround for dummy thread
225    if six.PY3 is False:
226        import threading
227        threading._DummyThread._Thread__stop = lambda x: 42
228
229    subprocess.call(['/usr/bin/xset', 's', '{}'.format(atLeastSeconds + 30)])
230    # And now reset it
231    subprocess.call(['/usr/bin/xset', 's', 'reset'])
232
233
234def getIdleDuration():
235    '''
236    Returns idle duration, in seconds
237    '''
238    if xlib is None or xss is None:
239        return 0  # Libraries not available
240
241    # production code might want to not hardcode the offset 16...
242    display = xlib.XOpenDisplay(None)
243
244    event_base = ctypes.c_int()
245    error_base = ctypes.c_int()
246
247    available = xss.XScreenSaverQueryExtension(display, ctypes.byref(event_base), ctypes.byref(error_base))
248    if available != 1:
249        return 0  # No screen saver is available, no way of getting idle
250
251    info = xss.XScreenSaverAllocInfo()
252    xss.XScreenSaverQueryInfo(display, xlib.XDefaultRootWindow(display), info)
253
254    if info.contents.state != 0:
255        return 3600 * 100 * 1000  # If screen saver is active, return a high enough value
256
257    return info.contents.idle / 1000.0
258
259
260def getCurrentUser():
261    '''
262    Returns current logged in user
263    '''
264    return os.environ['USER']
265
266
267def getSessionLanguage():
268    '''
269    Returns the user's session language
270    '''
271    lang = locale.getdefaultlocale()[0]
272    if lang is None:
273        return 'C'
274    else:
275        return lang
276
277
278def get_session_type():
279    """
280    Minimal implementation of this required function
281    :return: string
282    """
283    return 'unknown'
284
285
286def showPopup(title, message):
287    '''
288    Displays a message box on user's session (during 1 min).
289    '''
290    # Show a dialog using AppleSctipt
291    return subprocess.call('/usr/bin/osascript -e \'display notification "{}" with title "{}"\''.format(message, title), shell=True)
292
293
294def get_etc_path():
295    """
296    :return:
297    Returns etc directory path.
298    """
299    return os.sep + 'etc'
Note: See TracBrowser for help on using the repository browser.