Compare commits

...

57 Commits
0.13.2 ... main

Author SHA1 Message Date
Natalia Serrano 5541e39b5f Merge pull request 'refs #2308 do ogExecAndLog also when creating images' (#69) from ogexecandlog-createimage into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #69
2025-06-24 15:25:56 +02:00
Natalia Serrano 4f0543fe79 refs #2308 do ogExecAndLog also when creating images 2025-06-24 15:25:09 +02:00
Natalia Serrano a5eacbe203 Merge pull request '#2301 adds mount route when boot mark is created' (#67) from fix-bootMark-linux into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #67
2025-06-24 15:10:25 +02:00
Luis Gerardo Romero Garcia a34c98eb4c refs #2301 updates changelog 0.19.3 2025-06-24 15:09:21 +02:00
Luis Gerardo Romero Garcia c55a75f5ce #2301 adds mount route when boot mark is created 2025-06-24 15:08:29 +02:00
Natalia Serrano 1bf1283aff Merge pull request 'refs #2305 have ogExecAndLog do subprocess.Popen' (#68) from ogexecandlog into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #68
2025-06-24 15:04:40 +02:00
Natalia Serrano d5279eba42 refs #2305 have ogExecAndLog do subprocess.Popen 2025-06-24 15:03:52 +02:00
Natalia Serrano 87fb51ed2a refs #2304 remove obsolete useless function ogMcastRequest
ogclient/pipeline/head This commit looks good Details
2025-06-24 11:50:16 +02:00
Natalia Serrano c9c9e98359 Merge pull request 'refs #2301 write a mark for ogboot on linux only' (#66) from boot-mark-linux-only into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #66
2025-06-24 11:02:59 +02:00
Natalia Serrano 62ed2e3dde refs #2301 write a mark for ogboot on linux only 2025-06-24 11:01:36 +02:00
Natalia Serrano 7cefe8ff43 Merge pull request 'refs #2287 fix efi path' (#65) from fix-path into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #65
2025-06-23 16:28:48 +02:00
Natalia Serrano 9fc48067e6 refs #2287 fix efi path 2025-06-23 16:28:30 +02:00
Natalia Serrano 13b262d8f7 Merge pull request 'refs #2283 create boot mark file' (#64) from boot-mark-file into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #64
2025-06-23 12:57:56 +02:00
Natalia Serrano e43e8baea1 refs #2283 create boot mark file 2025-06-23 12:57:10 +02:00
Natalia Serrano d619cb005d Merge pull request 'refs #2238 support None as partition type' (#63) from createpartitions-none into main
ogclient/pipeline/tag This commit looks good Details
ogclient/pipeline/head This commit looks good Details
Reviewed-on: #63
2025-06-19 11:40:25 +02:00
Natalia Serrano 6d5dea6657 refs #2238 support None as partition type 2025-06-19 11:39:58 +02:00
Natalia Serrano d5fe20d291 Merge pull request 'refs #2236 look for grub.cfg in two places' (#62) from fix-ogboot into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #62
2025-06-18 09:49:40 +02:00
Natalia Serrano c7081b3921 refs #2236 look for grub.cfg in two places 2025-06-18 09:49:16 +02:00
Natalia Serrano 6c543660f9 Merge pull request 'refs #2227 add oggit scripts and libs' (#61) from add-oggit-scripts-libs into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #61
2025-06-16 15:59:21 +02:00
Natalia Serrano 594314161e refs #2227 add oggit scripts and libs 2025-06-16 15:58:54 +02:00
Natalia Serrano 7c326e7114 Merge pull request 'refs #2215 remove loop0 warning, fix windows efi boot' (#60) from loop0 into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #60
2025-06-16 09:44:59 +02:00
Natalia Serrano 944390806b refs #2215 remove loop0 warning, fix windows efi boot 2025-06-16 09:43:33 +02:00
Natalia Serrano 461c5faed5 Merge pull request 'refs #2206 give some care to the Custom scripts' (#59) from scripts-custom into main
ogclient/pipeline/head This commit looks good Details
Reviewed-on: #59
2025-06-12 15:46:59 +02:00
Natalia Serrano a9a2d19653 refs #2206 give some care to the Custom scripts 2025-06-12 15:46:06 +02:00
Natalia Serrano e80ed538b8 Merge pull request 'refs #2204 create missing directory' (#58) from mkdir-grub into main
Reviewed-on: #58
2025-06-12 10:23:56 +02:00
Natalia Serrano 857ebbd267 refs #2204 create missing directory 2025-06-12 10:23:20 +02:00
Natalia Serrano 03f8203598 Merge pull request 'refs #2202 fix bug when creating partitions' (#57) from ogcreatepartitions into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #57
2025-06-11 15:29:07 +02:00
Natalia Serrano 3fd94ecb8f refs #2202 fix bug when creating partitions 2025-06-11 15:28:41 +02:00
Natalia Serrano d2ef8a98f2 Merge pull request 'refs #2198 #2199 #2200 fix bugs' (#56) from bugs-varios into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #56
2025-06-11 10:20:40 +02:00
Natalia Serrano 8af4627e28 refs #2198 #2199 #2200 fix bugs 2025-06-11 10:20:01 +02:00
Natalia Serrano b64b6d79b3 Merge pull request 'refs #2196 remove OG bash functions from the agent's environment' (#55) from no-bash-functions-in-agent into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #55
2025-06-10 12:25:11 +02:00
Natalia Serrano efc22c1bcd refs #2196 remove OG bash functions from the agent's environment 2025-06-10 12:20:16 +02:00
Natalia Serrano 36bf1539d6 Merge pull request 'rc-pipelines' (#54) from rc-pipelines into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #54
2025-06-09 10:35:21 +02:00
Natalia Serrano f2c4371e1e refs #2189 get rc of bash pipelines 2025-06-09 10:35:02 +02:00
Natalia Serrano 39b947e598 refs #2189 get rc of bash pipelines 2025-06-09 10:31:34 +02:00
Natalia Serrano 0a26ebd946 Merge pull request 'deployimage-rc' (#53) from deployimage-rc into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #53
2025-06-06 13:58:33 +02:00
Natalia Serrano 4061f85704 refs #2187 fix rc management in deployImage.py 2025-06-06 13:58:14 +02:00
Natalia Serrano 928dedfeeb refs #2187 fix rc management in deployImage.py 2025-06-06 13:57:33 +02:00
Natalia Serrano 357c94e9ea Merge pull request 'refs #2184 make stunnel use and/or verify tls' (#52) from stunnel-usetls into main
ogclient/pipeline/head This commit looks good Details
ogclient/pipeline/tag This commit looks good Details
Reviewed-on: #52
2025-06-06 11:59:02 +02:00
Natalia Serrano df7d8d96cb refs #2184 make stunnel use and/or verify tls 2025-06-06 11:58:26 +02:00
Natalia Serrano 4df8caa203 Merge pull request 'refs #2171 copy grub.cfg' (#51) from cp-grub-cfg into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #51
2025-06-04 14:00:25 +02:00
Natalia Serrano fa8e94e688 refs #2171 copy grub.cfg 2025-06-04 13:59:59 +02:00
Natalia Serrano 65a3b862f7 Merge pull request 'ogexecandlog-returncode' (#50) from ogexecandlog-returncode into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #50
2025-06-03 09:32:06 +02:00
Natalia Serrano 05279ba7c5 refs #2165 review returncodes to the shell 2025-06-03 09:30:47 +02:00
Natalia Serrano 15a238c206 refs #2161 fix call to ogTorrentStart via ogExecAndLog 2025-06-02 15:15:18 +02:00
Natalia Serrano 93e349105a Merge pull request 'refs #2164 correctly parse the mcast session' (#49) from mcast-sess into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #49
2025-06-02 14:57:54 +02:00
Natalia Serrano d733d04b69 refs #2164 correctly parse the mcast session 2025-06-02 14:57:29 +02:00
Natalia Serrano e83e0e6e16 Merge pull request 'refs #2162 fix variable name' (#48) from unicast-direct into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #48
2025-06-02 12:13:59 +02:00
Natalia Serrano 972c2a7c8c refs #2162 fix variable name 2025-06-02 12:13:20 +02:00
Natalia Serrano def329436d Merge pull request 'fix-ucast-mcast' (#47) from fix-ucast-mcast into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #47
2025-05-30 13:33:16 +02:00
Natalia Serrano 29cc09105e refs #2153 fully qualify method call 2025-05-30 13:32:42 +02:00
Natalia Serrano 64c5eeae6e refs #2153 fully qualify method call 2025-05-30 13:31:27 +02:00
Natalia Serrano 1050133d59 refs #2151 explicitly return a true value 2025-05-30 13:30:05 +02:00
Natalia Serrano d76390a7b9 Merge pull request 'refs #2105 show sgdisk error' (#46) from fix-configurar into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #46
2025-05-28 14:32:46 +02:00
Natalia Serrano afe190c47d refs #2105 show sgdisk error 2025-05-28 14:30:39 +02:00
Natalia Serrano 9d1224e0c8 Merge pull request 'refs #2103 unlink() only existing files' (#45) from unlink-existing into main
ogclient/pipeline/head There was a failure building this commit Details
ogclient/pipeline/tag There was a failure building this commit Details
Reviewed-on: #45
2025-05-28 14:05:51 +02:00
Natalia Serrano 02b6708442 refs #2103 unlink() only existing files 2025-05-28 14:05:18 +02:00
41 changed files with 3521 additions and 703 deletions

View File

@ -5,6 +5,161 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [0.20.2] - 2025-06-24
### Changed
- Do a couple of ogExecAndLog()s also when creating images
## [0.20.1] - 2025-06-24
### Changed
- Fix mark for ogboot on linux
## [0.20.0] - 2025-06-24
### Changed
- In order to have /tmp/command.log updated in realtime, ogExecAndLog now spawns a subprocess rather than calling functions directly
## [0.19.2] - 2025-06-24
### Changed
- Write a mark for ogboot on linux only
## [0.19.1] - 2025-06-23
### Fixed
- Fixed path of EFI boot entry
## [0.19.0] - 2025-06-23
### Changed
- Write a mark for ogboot
## [0.18.2] - 2025-06-19
### Fixed
- Accept None as partition type
## [0.18.1] - 2025-06-18
### Fixed
- Look for grub.cfg in two places rather than one
## [0.18.0] - 2025-06-16
### Added
- Added scripts and libs for oggit
## [0.17.0] - 2025-06-16
### Changed
- Removed useless warning about /dev/loop0
- Fix windows EFI booting, and a typo
## [0.16.0] - 2025-06-12
### Changed
- Gave some care to the "Custom" scripts
## [0.15.3] - 2025-06-12
### Fixed
- Create missing dir
## [0.15.2] - 2025-06-11
### Fixed
- Fixed a condition check
## [0.15.1] - 2025-06-11
### Fixed
- Add a missing "import"
- Fix retrieving windows version from the registry
- Fix bug while building the "Part-01-01" string
- Removed obsolete unused "bootOS" scripts (with a capital "S")
## [0.15.0] - 2025-06-10
### Changed
- Remove opengnsys bash functions from the agent's environment
## [0.14.2] - 2025-06-09
### Fixed
- Get rc of bash pipelines in ProtocolLib
## [0.14.1] - 2025-06-07
### Fixed
- Fixed rc management in deployImage.py
## [0.14.0] - 2025-06-07
### Changed
- Read $ogusetls and $ogverifytls from the environment and configure stunnel accordingly
## [0.13.9] - 2025-06-04
### Fixed
- Copy grub.cfg so that grub finds the config upon boot
## [0.13.8] - 2025-06-03
### Fixed
- Paid attention to return codes between python (True for success) and shell (0 for success)
## [0.13.7] - 2025-06-02
### Fixed
- Fixed management of the "multicast session" parameter
## [0.13.6] - 2025-06-02
### Fixed
- Fixed variable name in restoreImage.py
## [0.13.5] - 2025-05-30
### Fixed
- Return a true value from the unicast/multicast methods
- Fully qualify a method call
## [0.13.4] - 2025-05-28
### Changed
- Show sgdisk output
## [0.13.3] - 2025-05-28
### Fixed
- unlink() only existing files
## [0.13.2] - 2025-05-28
### Changed

View File

@ -26,7 +26,12 @@ if [ -f "/usr/share/OGAgent/opengnsys/linux/OGAgentService.py" -a "$ogstatus" !=
export OGAGENTCFG_URLMENU_SCHEME=http
export OGAGENTCFG_URLMENU_IP=127.0.0.1
export OGAGENTCFG_URLMENU_PORT=81
python3 -m opengnsys.linux.OGAgentService fg
(
## remove bash functions and some OG vars from the agent's environment
unset -f $(declare -F |awk '/og[A-Z]|NT[A-Z]/ { print $3 }')
unset $(declare |awk -F= '/^MSG_|^OG_ERR_/ { print $1 }')
python3 -m opengnsys.linux.OGAgentService fg
)
else
for FILE in index $OGGROUP $(ogGetIpAddress)
do

View File

@ -13,12 +13,49 @@ ogIsEfiActive && mount -t efivarfs none /sys/firmware/efi/efivars
# Lanzar servicios complementarios del cliente.
echo "${MSG_OTHERSERVICES:-.}"
# Iniciar stunnel
if [ -e /etc/stunnel/menu.conf ]; then
sed -i -e "s/__OGCORE_IP__/$ogcore/; s/__OGCORE_PORT__/8443/" /etc/stunnel/menu.conf
mkdir -p /var/run/stunnel4; chown stunnel4:stunnel4 /var/run/stunnel4
stunnel /etc/stunnel/menu.conf &>/var/log/stunnel4/menu.log &
# stunnel start
cat >/etc/stunnel/menu.conf <<__EOF__
setuid = stunnel4
setgid = stunnel4
pid = /var/run/stunnel4/menu.pid
foreground = yes
debug = info
[menu]
client = yes
accept = 127.0.0.1:81
connect = $ogcore:8443
__EOF__
if [[ true == "$ogusetls" ]]; then
if [[ true == "$ogverifytls" ]]; then
## use tls and verify
cat >>/etc/stunnel/menu.conf <<__EOF__
cert = /opt/opengnsys/etc/ogagent.crt
key = /opt/opengnsys/etc/ogagent.key
CAfile = /opt/opengnsys/etc/ca.crt
requireCert = yes
verifyChain = yes
__EOF__
else
## use tls but not verify
cat >>/etc/stunnel/menu.conf <<__EOF__
cert = /opt/opengnsys/etc/ogagent.crt
key = /opt/opengnsys/etc/ogagent.key
CAfile = /opt/opengnsys/etc/ca.crt
requireCert = no
verifyChain = no
__EOF__
fi
else
## don't use tls
cat >>/etc/stunnel/menu.conf <<__EOF__
requireCert = no
verifyChain = no
__EOF__
fi
mkdir -p /var/run/stunnel4; chown stunnel4:stunnel4 /var/run/stunnel4
stunnel /etc/stunnel/menu.conf &>/var/log/stunnel4/menu.log &
# stunnel end
# Iniciar dbus
if [ -e /etc/dbus-1/system.d/ogbrowser.conf ]; then

View File

@ -19,6 +19,7 @@ if 5 == len (sys.argv):
args = parser.parse_args()
src = { 'container': args.src_container, 'file': args.src_file }
dst = { 'container': args.dst_container, 'file': args.dst_file }
elif 7 == len (sys.argv):
parser.add_argument ('src_disk')
parser.add_argument ('src_par')
@ -29,6 +30,31 @@ elif 7 == len (sys.argv):
args = parser.parse_args()
src = { 'disk': args.src_disk, 'par': args.src_par, 'file': args.src_file }
dst = { 'disk': args.dst_disk, 'par': args.dst_par, 'file': args.dst_file }
elif 4 == len (sys.argv):
## can be either:
## - src_container src_file dst_file
## - src_file dst_container dst_file
if 'REPO' == sys.argv[1] or 'CACHE' == sys.argv[1]:
## we are in "src_container src_file dst_file"
parser.add_argument ('src_container')
parser.add_argument ('src_file')
parser.add_argument ('dst_file')
args = parser.parse_args()
src = { 'container': args.src_container, 'file': args.src_file }
dst = { 'file': args.dst_file }
elif 'REPO' == sys.argv[2] or 'CACHE' == sys.argv[2]:
## we are in "src_file dst_container dst_file"
parser.add_argument ('src_file')
parser.add_argument ('dst_container')
parser.add_argument ('dst_file')
args = parser.parse_args()
src = { 'file': args.src_file }
dst = { 'container': args.dst_container, 'file': args.dst_file }
else:
ogHelp ('ogCopyFile', 'ogCopyFile [ str_repo | int_ndisk int_npartition ] path_source [ str_repo | int_ndisk int_npartition ] path_target', ['ogCopyFile REPO newfile.txt 1 2 /tmp/newfile.txt'])
sys.exit (1)
elif 6 == len (sys.argv):
## can be either:
## - src_disk src_par src_file dst_container dst_file
@ -36,7 +62,7 @@ elif 6 == len (sys.argv):
try:
num = int (sys.argv[1]) ## raises ValueError if sys.argv[1] doesn't look like a number
## "src_disk src_par src_file dst_container dst_file"
## we are in "src_disk src_par src_file dst_container dst_file"
parser.add_argument ('src_disk')
parser.add_argument ('src_par')
parser.add_argument ('src_file')
@ -46,7 +72,7 @@ elif 6 == len (sys.argv):
src = { 'disk': args.src_disk, 'par': args.src_par, 'file': args.src_file }
dst = { 'container': args.dst_container, 'file': args.dst_file }
except:
## "src_container src_file dst_disk dst_par dst_file"
## we are in "src_container src_file dst_disk dst_par dst_file"
parser.add_argument ('src_container')
parser.add_argument ('src_file')
parser.add_argument ('dst_disk')

View File

@ -143,15 +143,15 @@ cur_ptt = DiskLib.ogGetPartitionTableType (dis)
ptt = 'GPT' if InventoryLib.ogIsEfiActive() else 'MSDOS'
if not cur_ptt or ptt != cur_ptt:
DiskLib.ogDeletePartitionTable (dis)
SystemLib.ogExecAndLog ('command', DiskLib.ogUpdatePartitionTable)
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
DiskLib.ogCreatePartitionTable (dis, ptt)
# Inicia la cache.
if 'CACHE' in sparam:
SystemLib.ogEcho (['session', 'log'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogCreateCache}')
SystemLib.ogEcho (['session', 'log'], None, f' initCache {tch}')
rc = SystemLib.ogExecAndLog ('command', CacheLib.initCache, tch)
if rc:
rc = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGSCRIPTS}/initCache', tch])
if not rc:
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_CACHE, f'initCache failed')
coproc.kill()
sys.exit (1)
@ -159,12 +159,12 @@ if 'CACHE' in sparam:
# Definir particionado.
SystemLib.ogEcho (['session', 'log'], None, f'[50] {ogGlobals.lang.MSG_HELP_ogCreatePartitions}')
SystemLib.ogEcho (['session', 'log'], None, f' ogCreatePartitions {dis} {' '.join (tbp)}')
res = SystemLib.ogExecAndLog ('command', DiskLib.ogCreatePartitions, dis, tbp)
res = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCreatePartitions', dis] + tbp)
if not res:
coproc.kill()
SystemLib.ogRaiseError (['log', 'session'], ogGlobals.OG_ERR_GENERIC, f'ogCreatePartitions {dis} {' '.join (tbp)}')
sys.exit (1)
SystemLib.ogExecAndLog ('command', DiskLib.ogUpdatePartitionTable)
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogUpdatePartitionTable'])
# Formatear particiones
SystemLib.ogEcho (['session', 'log'], None, f'[70] {ogGlobals.lang.MSG_HELP_ogFormat}')
@ -174,10 +174,10 @@ for p in range (1, maxp+1):
if 'CACHE' == tbf[p]:
if CACHESIZE == tch: # Si el tamaño es distinto ya se ha formateado.
SystemLib.ogEcho (['session', 'log'], None, ' ogFormatCache')
retval = SystemLib.ogExecAndLog ('command', CacheLib.ogFormatCache)
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatCache'])
else:
SystemLib.ogEcho (['session', 'log'], None, f' ogFormatFs {dis} {p} {tbf[p]}')
retval = SystemLib.ogExecAndLog ('command', FileSystemLib.ogFormatFs, dis, str(p), tbf[p])
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogFormatFs', dis, str(p), tbf[p]])
if retval:
coproc.kill()
SystemLib.ogRaiseError (['session', 'log'], ogGlobals.OG_ERR_GENERIC, f'ogFormatFs {dis} {p} {tbf[p]}')

View File

@ -0,0 +1,38 @@
#!/usr/bin/env python3
import os
import subprocess
import sys
import time
sys.path.insert(0, "/opt/oglive/rootfs/opt/opengnsys/lib/python3/")
sys.path.insert(0, "/opt/opengnsys/interfaceAdm/git/")
sys.path.insert(0, "/opt/opengnsys/ogrepository/oggit/lib/")
import NetLib
import ogGlobals
import SystemLib
from gitlib import OpengnsysGitLibrary, NTFSImplementation
def create_image(disk_num, partition_num, repo, image_name):
ntfs_impl = NTFSImplementation.NTFS3G
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
device = og_git._runBashFunction("ogDiskToDev", [str(disk_num), str(partition_num)])
og_git.initRepo(device, image_name)
def main():
if len(sys.argv) != 6:
sys.exit(SystemLib.ogRaiseError(OG_ERR_FORMAT, "Incorrect number of arguments"))
disk_num, partition_num, image_name, repo, tag = sys.argv[1:6]
retval = create_image(disk_num, partition_num, repo, image_name)
sys.exit(retval)
if __name__ == "__main__":
main()

View File

@ -0,0 +1,32 @@
#!/usr/bin/env python3
import sys
import subprocess
sys.path.insert(0, "/opt/oglive/rootfs/opt/opengnsys/lib/python3/")
sys.path.insert(0, "/opt/opengnsys/interfaceAdm/git/")
sys.path.insert(0, "/opt/opengnsys/ogrepository/oggit/lib/")
import NetLib
import ogGlobals
import SystemLib
from gitlib import OpengnsysGitLibrary, NTFSImplementation
if __name__ == "__main__":
if len(sys.argv) < 4:
print("Usage: python RestaurarImagenGit.py <disk> <partition> <repo> <boot_device>")
sys.exit(1)
disk = sys.argv[1]
partition = sys.argv[2]
repo = sys.argv[3]
boot_device = sys.argv[4]
ntfs_impl = NTFSImplementation.NTFS3G
og_git = OpengnsysGitLibrary(ntfs_implementation = ntfs_impl)
device = og_git._runBashFunction("ogDiskToDev", [str(disk), str(partition)])
og_git.cloneRepo(repo, device, boot_device)

View File

@ -112,7 +112,7 @@ def ogBoot (disk, par, nvramperm=False, params=''):
bootloader = 'shimx64.efi'
# Obtener parcición EFI.
esp = DiskLib.ogGetEsp()
#efidisk, efipart = esp.split()
efidisk, efipart = esp.split()
# TODO: Comprobamos que existe la BOOTLABEL, si no buscamos por sistema operativo
if '' == FileLib.ogGetPath (src=esp, file=f'EFI/{bootlabel}'):
osversion = InventoryLib.ogGetOsVersion (disk, par)
@ -126,6 +126,14 @@ def ogBoot (disk, par, nvramperm=False, params=''):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'{esp} Boot loader')
return None
esp_dev = DiskLib.ogDiskToDev (efidisk, efipart)
esp_mntdir = esp_dev.replace ('dev', 'mnt')
os.makedirs (f'{esp_mntdir}/boot/grub', exist_ok=True)
grub_cfg_src = f'{esp_mntdir}/EFI/{bootlabel}/Boot/grub.cfg'
if not os.path.exists (grub_cfg_src):
grub_cfg_src = f'{esp_mntdir}/boot/grubMBR/boot/grub/grub.cfg'
shutil.copy2 (grub_cfg_src, f'{esp_mntdir}/boot/grub/grub.cfg')
# Crear orden de arranque (con unos valores por defecto).
UEFILib.ogNvramAddEntry (bootlabel, f'/EFI/{bootlabel}/Boot/{bootloader}', nvramperm)
# Marcar próximo arranque y reiniciar.
@ -156,9 +164,17 @@ def ogBoot (disk, par, nvramperm=False, params=''):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, f'{disk} {par} ({type}, EFI)')
return None
esp_dev = DiskLib.ogDiskToDev (efidisk, efipart)
esp_mntdir = esp_dev.replace ('dev', 'mnt')
os.makedirs (f'{esp_mntdir}/boot/grub', exist_ok=True)
grub_cfg_src = f'{esp_mntdir}/EFI/{bootlabel}/Boot/grub.cfg'
if not os.path.exists (grub_cfg_src):
grub_cfg_src = f'{esp_mntdir}/boot/grubMBR/boot/grub/grub.cfg'
shutil.copy2 (grub_cfg_src, f'{esp_mntdir}/boot/grub/grub.cfg')
# Crear orden de arranque (con unos valores por defecto).
l = re.sub ('^.*EFI(.*)$', r'\1', loader)
UEFILib.ogNvramAddEntry (bootlabel, l, nvramperm)
UEFILib.ogNvramAddEntry (bootlabel, '/EFI'+l, nvramperm)
# Marcar próximo arranque y reiniciar.
UEFILib.ogNvramSetNext (bootlabel)
subprocess.run (['reboot'])
@ -437,7 +453,7 @@ def ogWindowsBootParameters (disk, par):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_PARTITION, f'ESP: {bootdisk} {bootpar}')
return
bootdisk = str (int (bootdisk) - 1)
bootlabel = f'Part-{int(bootdisk):02d}-{int(bootpar):02d}'
bootlabel = f'Part-{int(disk):02d}-{int(par):02d}'
bcdfile = f'boot_BCD_file=/EFI/{bootlabel}/Boot/BCD'
else:
bootdisk = disk0
@ -449,9 +465,9 @@ def ogWindowsBootParameters (disk, par):
winver = InventoryLib.ogGetOsVersion (disk, par)
parts = re.split (':| ', winver)
if 'Windows' == parts[0] and 'Server' == parts[2]:
winver = parts[1] + parts[2] + parts[3]
winver = parts[1] + ' ' + parts[2] + ' ' + parts[3]
else:
winver = parts[1] + parts[2]
winver = parts[1] + ' ' + parts[2]
if not winver:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTOS, 'Windows')
return
@ -739,7 +755,7 @@ def ogGrubInstallMbr (disk, par, checkos='FALSE', kernelparam=''):
neworder = neworder[0:1] + [grubentry] + neworder[1:] ## la ponemos en segundo lugar
UEFILib.ogNvramSetOrder (neworder)
return eval
return not eval ## negate shell success code
#/**
@ -834,7 +850,7 @@ def ogGrubInstallPartition (disk, par, checkos='FALSE', kernelparam=''):
# Nombre OpenGnsys para cargador
shutil.copy2 (f'{efisecondstage}/EFI/{efisubdir}/Boot/grubx64.efi', f'{efisecondstage}/EFI/{efisubdir}/Boot/ogloader.efi')
return eval
return not eval ## negate shell success code

View File

@ -86,7 +86,7 @@ def ogCreateCache (ndsk=1, part=4, sizecache=0):
get_ptt = DiskLib.ogGetPartitionTableType (ndsk)
if 'GPT' == get_ptt:
# Si la tabla de particiones no es valida, volver a generarla.
if subprocess.run (['sgdisk', '-p', DISK], capture_output=True, text=True).returncode:
if subprocess.run (['sgdisk', '-p', DISK], capture_output=True, text=True).returncode: ## if True, then sgdisk failed
subprocess.run (['gdisk', DISK], input='2\nw\nY\n', capture_output=True, text=True)
# Si existe la cache se borra previamente
if ogFindCache(): ogDeleteCache()
@ -96,7 +96,7 @@ def ogCreateCache (ndsk=1, part=4, sizecache=0):
subprocess.run (['sgdisk', DISK, f'-n{part}:{START}:{END}', f'-c{part}:CACHE', f'-t{part}:{ID}'])
elif 'MSDOS' == get_ptt:
# Si la tabla de particiones no es valida, volver a generarla.
if subprocess.run (['parted', '-s', DISK, 'print']).returncode:
if subprocess.run (['parted', '-s', DISK, 'print']).returncode: ## if True, then parted failed
subprocess.run (['fdisk', DISK], input='w\n', text=True)
# Definir particiones y notificar al kernel.
ID = DiskLib.ogTypeToId ('CACHE', 'MSDOS')
@ -139,12 +139,12 @@ def ogDeleteCache():
ptt = DiskLib.ogGetPartitionTableType (ndisk)
if 'GPT' == ptt:
# Si la tabla de particiones no es valida, volver a generarla.
if subprocess.run (['sgdisk', '-p', disk]).returncode:
if subprocess.run (['sgdisk', '-p', disk]).returncode: ## if True, then sgdisk failed
subprocess.run (['gdisk', disk], input='2\nw\nY\n', text=True)
subprocess.run (['sgdisk', disk, f'-d{npart}'])
elif 'MSDOS' == ptt:
# Si la tabla de particiones no es valida, volver a generarla.
if subprocess.run (['parted', '-s', disk, 'print']).returncode:
if subprocess.run (['parted', '-s', disk, 'print']).returncode: ## if True, then parted failed
subprocess.run (['fdisk', disk], input='w', text=True)
# Eliminar la partición de caché.
subprocess.run (['fdisk', disk], input=f'd\n{npart}\nw', text=True)
@ -357,4 +357,4 @@ def ogUnmountCache():
#*/ ##
def initCache (*args):
p = subprocess.run ([f'{ogGlobals.OGSCRIPTS}/initCache.py'] + list(args))
return p.returncode
return not p.returncode ## negate shell return code

View File

@ -76,7 +76,7 @@ def ogCreatePartitions (disk, parts):
CACHEPART = CacheLib.ogFindCache()
if CACHEPART:
cache_disk, cache_part = CACHEPART.split()
if ND == int (cache_disk):
if int (ND) == int (cache_disk):
CACHESIZE = int (CacheLib.ogGetCacheSize()) * 2
# Sector de inicio (la partición 1 empieza en el sector 63).
IODISCO = ogDiskToDev (disk)
@ -112,6 +112,7 @@ def ogCreatePartitions (disk, parts):
# Leer formato de cada parámetro - Tipo:Tamaño
TYPE, SIZE = p.split (':')
if TYPE is None or 'None' == TYPE: TYPE='EMPTY'
try:
SIZE = int (SIZE)
except ValueError:
@ -176,7 +177,7 @@ def ogCreatePartitions (disk, parts):
ogCreatePartitionTable (ND)
# Definir particiones y notificar al kernel.
p = subprocess.run (['sfdisk', DISK], input=sfdisk_input, capture_output=True, text=True)
p = subprocess.run (['sfdisk', DISK], input=sfdisk_input, text=True)
subprocess.run (['partprobe', DISK])
if CACHESIZE: CacheLib.ogMountCache()
return not p.returncode
@ -283,6 +284,7 @@ def ogCreateGptPartitions (disk, parts):
# Definir particiones y notificar al kernel.
p = subprocess.run (['sgdisk'] + DELOPTIONS + OPTIONS + [DISK], capture_output=True, text=True)
print (f'sgdisk rc ({p.returncode}) stdout ({p.stdout}) stderr ({p.stderr})')
subprocess.run (['partprobe', DISK])
if CACHESIZE: CacheLib.ogMountCache()
return not p.returncode
@ -391,7 +393,8 @@ def ogDevToDisk(arg_dev):
DEV = arg_dev
if not os.path.exists(DEV):
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_dev)
if '/dev/loop' != DEV[0:9]:
SystemLib.ogRaiseError([], ogGlobals.OG_ERR_NOTFOUND, arg_dev)
return
# Error si no es fichero de bloques o directorio (para LVM).

View File

@ -215,8 +215,8 @@ def ogCopyFile (src, dst):
return
# Copiar fichero (para evitar problemas de comunicaciones las copias se hacen con rsync en vez de cp).
result = subprocess.run(["rsync", "--progress", "--inplace", "-avh", SOURCE, TARGET], capture_output=True, text=True)
return result.returncode
result = subprocess.run(["rsync", "--progress", "--inplace", "-avh", SOURCE, TARGET], text=True) ## they want the output
return not result.returncode ## negate shell result
#/**

View File

@ -254,7 +254,7 @@ def ogCreateImage (disk, par, container, imgfile, tool='partclone', level='gzip'
#trap
p = subprocess.run (program, shell=True, check=True)
errcode = p.returncode
if 0 == errcode:
if 0 == errcode: ## success
i = ogGetImageInfo (IMGFILE)
h = NetLib.ogGetHostname()
with open (f'{IMGFILE}.info', 'w') as fd:
@ -515,10 +515,8 @@ def ogRestoreImage (repo, imgpath, disk, par):
rc = None
try:
p = subprocess.run (program, shell=True, capture_output=True, text=True)
print (p.stdout)
print (p.stderr)
rc = p.returncode
p = subprocess.run (program, shell=True, text=True)
rc = not p.returncode
if not rc:
SystemLib.ogRaiseError ([], ogGlobalsOG_ERR_IMAGE, f'{imgfile}, {disk}, {par}')
except:
@ -607,7 +605,7 @@ def ogGetImageInfo (imgfile):
## original bash idiom is: $($COMPRESSOR -dc $IMGFILE 2>/dev/null | head -n 40 > $FILEHEAD) || ogRaiseError
## the purpose of which I can't fully comprehend
#print (f'shelling out "{compressor} -dc {imgfile} |head -n 40 > {filehead}"')
if subprocess.run (f'{compressor} -dc {imgfile} |head -n 40 > {filehead}', shell=True).returncode:
if subprocess.run (f'{compressor} -dc {imgfile} |head -n 40 > {filehead}', shell=True).returncode: ## if True, then the compressor failed
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, f'Image format is not valid {imgfile}')
return

View File

@ -428,7 +428,7 @@ def ogGetOsVersion(disk, part):
f'load {file}',
r'cd \Microsoft\Windows NT\CurrentVersion',
'lsval ProductName',
'lsval DisplayVersion',
'lsval ReleaseId',
])
version = subprocess.run (['hivexsh'], input=i, capture_output=True, text=True).stdout
version = version.replace ('\n', ' ')

View File

@ -129,11 +129,11 @@ def ogUcastSendPartition (disk, par, sess, tool, level):
cmd = ogUcastSyntax ('SENDPARTITION', sess, device=PART, tool=tool, level=level)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDPARTITION, ' ')
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDPARTITION, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
@ -160,11 +160,11 @@ def ogUcastReceiverPartition (disk, par, sess, tool, level):
cmd = ogUcastSyntax ('RECEIVERPARTITION', sess, device=PART, tool=tool, level=level)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTRECEIVERPARTITION, ' ')
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTRECEIVERPARTITION, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
@ -224,17 +224,18 @@ def ogUcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
return
path2 = FileLib.ogGetPath (file=source)
print (f'nati path2 ({path2})')
if not path2:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
return
cmd = ogUcastSyntax ('SENDFILE', sess, file=source)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDFILE, ' ')
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_UCASTSENDFILE, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
def _clientip():
ipas = subprocess.run (['ip', '-json', 'address', 'show', 'up'], capture_output=True, text=True).stdout
@ -482,17 +483,18 @@ def ogMcastSendFile (disk=None, par=None, container=None, file=None, sess=None):
return
path2 = FileLib.ogGetPath (file=source)
print (f'nati path2 ({path2})')
if not path2:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or file {dev_err} not found')
return
cmd = ogMcastSyntax ('SENDFILE', sess, file=source)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDFILE, ' ')
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDFILE, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
@ -549,11 +551,11 @@ def ogMcastReceiverFile (disk=None, par=None, container=None, file=None, sess=No
cmd = ogMcastSyntax ('RECEIVERFILE', sess, file=os.path.join (targetdir, targetfile))
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERFILE, targetfile)
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERFILE, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
#/**
@ -581,11 +583,11 @@ def ogMcastSendPartition (disk, par, sess, tool, compressor):
FileSystemLib.ogUnmount (disk, par)
cmd = ogMcastSyntax ('SENDPARTITION', sess, device=PART, tool=tool, level=compressor)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDPARTITION, ' ')
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTSENDPARTITION, f'pipeline "{cmd}" returned code "{rc}"')
return None
return True
#/**
# ogMcastReceiverPartition
@ -606,22 +608,10 @@ def ogMcastReceiverPartition (disk, par, sess, tool, compressor):
FileSystemLib.ogUnmount (disk, par)
cmd = ogMcastSyntax ('RECEIVERPARTITION', sess, device=PART, tool=tool, level=compressor)
if not cmd: return None
try:
subprocess.run (cmd, shell=True, check=True)
except subprocess.CalledProcessError:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERPARTITION, ' ') ## original code has OG_ERR_MCASTSENDPARTITION
rc = subprocess.run (cmd, shell=True).returncode
if rc:
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_MCASTRECEIVERPARTITION, f'pipeline "{cmd}" returned code "{rc}"') ## original code has OG_ERR_MCASTSENDPARTITION
return None
#/**
# ogMcastRequest
#@brief Función temporal para solicitar al ogRepoAux el envio de un fichero por multicast
#@param 1 Fichero a enviar ubicado en el REPO. puede ser ruta absoluta o relatica a /opt/opengnsys/images
#@param 2 PROTOOPT opciones protocolo multicast
#*/ ##
## now ogCore takes this responsibility
def ogMcastRequest (img, proto):
return True
@ -681,7 +671,7 @@ def ogTorrentStart (disk=None, par=None, container=None, torrentfile=None, torre
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, f'device or torrentfile {dev_err} not found')
return
if subprocess.run (['ctorrent', '-x', source]).returncode:
if subprocess.run (['ctorrent', '-x', source]).returncode: ## if True, then ctorrent failed
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, '')
return None
@ -736,20 +726,22 @@ def ogTorrentStart (disk=None, par=None, container=None, torrentfile=None, torre
# Creamos el fichero de resumen por defecto
open (f'{source}.bf', 'w').close()
# ctorrent controla otro fichero -b ${SOURCE}.bfog
subprocess.run (['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog'])
ctorrent_cmd = ['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog']
elif 'leecher' == mode:
print ('Donwloading Torrent as leecher')
subprocess.run (['ctorrent', '${SOURCE}', '-X', 'sleep 30; kill -2 $(pidof ctorrent)', '-C', '100', '-U', '0'])
ctorrent_cmd = ['ctorrent', source, '-X', 'sleep 30; kill -2 $(pidof ctorrent)', '-C', '100', '-U', '0']
elif 'seeder' == mode:
print ('MODE seeder ctorrent')
# Creamos el fichero de resumen por defecto
open (f'{source}.bf', 'w').close()
# ctorrent controla otro fichero -b ${SOURCE}.bfog
subprocess.run (['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog'])
ctorrent_cmd = ['ctorrent', '-f', '-c', '-X', f'sleep {time}; kill -2 $(pidof ctorrent)', '-C', '100', source, '-s', target, '-b', f'{source}.bfog']
else:
print ('this should not happen')
return None
print (f'executing ctorrent: {' '.join(ctorrent_cmd)}')
subprocess.run (ctorrent_cmd)
os.chdir (cwd)
@ -858,9 +850,9 @@ def ogUpdateCacheIsNecesary (repo, file, proto):
filetarget = FileLib.ogGetPath (src='CACHE', file=file)
if not filetarget:
# borramos el fichero bf del torrent, en el caso de que se hubiese quedado de algun proceso fallido
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.torrent.bf'): ogDeleteFile (container='CACHE', file=f'{file}.torrent.bf')
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.sum'): ogDeleteFile (container='CACHE', file=f'{file}.sum')
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.full.sum'): ogDeleteFile (container='CACHE', file=f'{file}.full.sum')
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.torrent.bf'): FileLib.ogDeleteFile (container='CACHE', file=f'{file}.torrent.bf')
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.sum'): FileLib.ogDeleteFile (container='CACHE', file=f'{file}.sum')
if FileLib.ogGetPath (src='CACHE', file=f'/{file}.full.sum'): FileLib.ogDeleteFile (container='CACHE', file=f'{file}.full.sum')
print ('TRUE(0), es necesario actualizar. Paso 1, la cache no contiene esa imagen ')
return True
@ -926,6 +918,7 @@ def ogUpdateCacheIsNecesary (repo, file, proto):
else:
print ('imagen en cache distinta, borramos la imagen anterior')
for f in [f'{filetarget}', f'{filetarget}.sum', f'{filetarget}.torrent', f'{filetarget}.full.sum']:
os.unlink (f)
if os.path.exists (f):
os.unlink (f)
print ('TRUE (0), Si es necesario actualizar.')
return True

View File

@ -3,22 +3,15 @@ import datetime
from zoneinfo import ZoneInfo
import sys
import os
import select
import json
import shutil
import inspect
import glob
## for ogExecAndLog
from io import StringIO
from contextlib import redirect_stdout, redirect_stderr
import ogGlobals
import StringLib
#NODEBUGFUNCTIONS, OGIMG, OG_ERR_CACHESIZE, OG_ERR_NOTCACHE, OG_ERR_NOTWRITE, OG_ERR_FILESYS
#OG_ERR_REPO, OG_ERR_NOTOS, OG_ERR_NOGPT, OG_ERR_OUTOFLIMIT, OG_ERR_IMAGE, OG_ERR_CACHE
#OGLOGSESSION, OGLOGCOMMAND, OGLOGFILE, OG_ERR_LOCKED, OG_ERR_PARTITION, OG_ERR_FORMAT, OG_ERR_NOTEXEC, OG_ERR_NOTFOUND
def _logtype2logfile (t):
if 'log' == t.lower(): return ogGlobals.OGLOGFILE
if 'jsonlog' == t.lower(): return ogGlobals.OGJSONLOGFILE
@ -84,11 +77,11 @@ def ogEcho (logtypes, loglevel, msg):
#@note str_logfile = { LOG, SESSION, COMMAND }
#*/
#ogExecAndLog (str_logfile ... str_command ...",
#ogExecAndLog ([], ogMyLib.ogSomeMethod, *args, **kwargs)
#ogExecAndLog ('command', ogMyLib.ogSomeMethod, *args, **kwargs)
#ogExecAndLog (['command'], ogMyLib.ogSomeMethod, *args, **kwargs)
#ogExecAndLog (['log', 'command'], ogMyLib.ogSomeMethod, *args, **kwargs)
def ogExecAndLog (logtypes, fun, *args, **kwargs):
#ogExecAndLog ([], ['/path/to/script', *args])
#ogExecAndLog ('command', ['/path/to/script', *args])
#ogExecAndLog (['command'], ['/path/to/script', *args])
#ogExecAndLog (['log', 'command'], ['/path/to/script', *args])
def ogExecAndLog (logtypes, script_and_args):
logfiles = ['/dev/stdout']
if type (logtypes) is list:
for l in logtypes:
@ -106,7 +99,7 @@ def ogExecAndLog (logtypes, fun, *args, **kwargs):
else:
logfiles.append (_logtype2logfile (logtypes))
if not fun:
if not script_and_args:
ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, 'no function provided')
return
@ -129,38 +122,38 @@ def ogExecAndLog (logtypes, fun, *args, **kwargs):
# ## redirect stdout only
# eval $COMMAND | tee -a $FILES
sout = serr = ''
capture_stderr = False
if 'command' in logtypes:
os.unlink (ogGlobals.OGLOGCOMMAND)
open (ogGlobals.OGLOGCOMMAND, 'w').close()
with redirect_stdout (StringIO()) as r_stdout, redirect_stderr (StringIO()) as r_stderr:
rc = fun (*args, **kwargs)
sout = r_stdout.getvalue()
serr = r_stderr.getvalue()
else:
with redirect_stdout (StringIO()) as r_stdout:
rc = fun (*args, **kwargs)
sout = r_stdout.getvalue()
capture_stderr = True
rc_str = str (rc)
if sout or serr or ('True' != rc_str and 'False' != rc_str and 'None' != rc_str):
for f in logfiles:
with open (f, 'a') as fd:
if ogGlobals.OGJSONLOGFILE == f:
if sout: fd.write (json.dumps ({'message':sout}) + '\n')
if serr: fd.write (json.dumps ({'message':serr}) + '\n')
if rc_str: fd.write (json.dumps ({'message':rc_str}) + '\n')
else:
if sout: fd.write (f'{sout}\n')
if serr: fd.write (f'{serr}\n')
if rc_str: fd.write (f'{rc_str}\n')
#fd.write (f"ogExecAndLog: {fun.__name__} rc:\n{rc_str}\n")
#if sout: fd.write (f"ogExecAndLog: {fun.__name__} stdout:\n{sout}\n")
#else: fd.write (f"ogExecAndLog: {fun.__name__} stdout: (none)\n")
#if serr: fd.write (f"ogExecAndLog: {fun.__name__} stderr:\n{serr}\n")
#else: fd.write (f"ogExecAndLog: {fun.__name__} stderr: (none)\n")
p = subprocess.Popen (script_and_args, text=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
while True:
ready_to_read, _, _ = select.select ([p.stdout, p.stderr], [], [], 1)
return rc
partial_out = ''
if p.stdout in ready_to_read:
l = p.stdout.readline()
partial_out += l
if p.stderr in ready_to_read:
l = p.stderr.readline() ## always read from stderr even if we're discarding it, to prevent buffers from filling up
if capture_stderr:
partial_out += l
if partial_out:
for f in logfiles:
with open (f, 'a') as fd:
if ogGlobals.OGJSONLOGFILE == f:
fd.write (json.dumps ({'message':partial_out}))
else:
fd.write (partial_out)
if p.poll() is not None:
break
rc = p.returncode
return not rc ## negate shell return code
#/**
# ogGetCaller

View File

@ -0,0 +1,345 @@
#!/usr/bin/env python3
import hivex
import argparse
import struct
from hivex import Hivex
from hivex.hive_types import *
# Docs:
#
# https://www.geoffchappell.com/notes/windows/boot/bcd/objects.htm
# https://learn.microsoft.com/en-us/previous-versions/windows/desktop/bcd/bcdbootmgrelementtypes
#print(f"Root: {root}")
BCD_Enumerations = {
"BcdLibraryDevice_ApplicationDevice" : 0x11000001,
"BcdLibraryString_ApplicationPath" : 0x12000002,
"BcdLibraryString_Description" : 0x12000004,
"BcdLibraryString_PreferredLocale" : 0x12000005,
"BcdLibraryObjectList_InheritedObjects" : 0x14000006,
"BcdLibraryInteger_TruncatePhysicalMemory" : 0x15000007,
"BcdLibraryObjectList_RecoverySequence" : 0x14000008,
"BcdLibraryBoolean_AutoRecoveryEnabled" : 0x16000009,
"BcdLibraryIntegerList_BadMemoryList" : 0x1700000a,
"BcdLibraryBoolean_AllowBadMemoryAccess" : 0x1600000b,
"BcdLibraryInteger_FirstMegabytePolicy" : 0x1500000c,
"BcdLibraryInteger_RelocatePhysicalMemory" : 0x1500000D,
"BcdLibraryInteger_AvoidLowPhysicalMemory" : 0x1500000E,
"BcdLibraryBoolean_DebuggerEnabled" : 0x16000010,
"BcdLibraryInteger_DebuggerType" : 0x15000011,
"BcdLibraryInteger_SerialDebuggerPortAddress" : 0x15000012,
"BcdLibraryInteger_SerialDebuggerPort" : 0x15000013,
"BcdLibraryInteger_SerialDebuggerBaudRate" : 0x15000014,
"BcdLibraryInteger_1394DebuggerChannel" : 0x15000015,
"BcdLibraryString_UsbDebuggerTargetName" : 0x12000016,
"BcdLibraryBoolean_DebuggerIgnoreUsermodeExceptions" : 0x16000017,
"BcdLibraryInteger_DebuggerStartPolicy" : 0x15000018,
"BcdLibraryString_DebuggerBusParameters" : 0x12000019,
"BcdLibraryInteger_DebuggerNetHostIP" : 0x1500001A,
"BcdLibraryInteger_DebuggerNetPort" : 0x1500001B,
"BcdLibraryBoolean_DebuggerNetDhcp" : 0x1600001C,
"BcdLibraryString_DebuggerNetKey" : 0x1200001D,
"BcdLibraryBoolean_EmsEnabled" : 0x16000020,
"BcdLibraryInteger_EmsPort" : 0x15000022,
"BcdLibraryInteger_EmsBaudRate" : 0x15000023,
"BcdLibraryString_LoadOptionsString" : 0x12000030,
"BcdLibraryBoolean_DisplayAdvancedOptions" : 0x16000040,
"BcdLibraryBoolean_DisplayOptionsEdit" : 0x16000041,
"BcdLibraryDevice_BsdLogDevice" : 0x11000043,
"BcdLibraryString_BsdLogPath" : 0x12000044,
"BcdLibraryBoolean_GraphicsModeDisabled" : 0x16000046,
"BcdLibraryInteger_ConfigAccessPolicy" : 0x15000047,
"BcdLibraryBoolean_DisableIntegrityChecks" : 0x16000048,
"BcdLibraryBoolean_AllowPrereleaseSignatures" : 0x16000049,
"BcdLibraryString_FontPath" : 0x1200004A,
"BcdLibraryInteger_SiPolicy" : 0x1500004B,
"BcdLibraryInteger_FveBandId" : 0x1500004C,
"BcdLibraryBoolean_ConsoleExtendedInput" : 0x16000050,
"BcdLibraryInteger_GraphicsResolution" : 0x15000052,
"BcdLibraryBoolean_RestartOnFailure" : 0x16000053,
"BcdLibraryBoolean_GraphicsForceHighestMode" : 0x16000054,
"BcdLibraryBoolean_IsolatedExecutionContext" : 0x16000060,
"BcdLibraryBoolean_BootUxDisable" : 0x1600006C,
"BcdLibraryBoolean_BootShutdownDisabled" : 0x16000074,
"BcdLibraryIntegerList_AllowedInMemorySettings" : 0x17000077,
"BcdLibraryBoolean_ForceFipsCrypto" : 0x16000079,
"BcdBootMgrObjectList_DisplayOrder" : 0x24000001,
"BcdBootMgrObjectList_BootSequence" : 0x24000002,
"BcdBootMgrObject_DefaultObject" : 0x23000003,
"BcdBootMgrInteger_Timeout" : 0x25000004,
"BcdBootMgrBoolean_AttemptResume" : 0x26000005,
"BcdBootMgrObject_ResumeObject" : 0x23000006,
"BcdBootMgrObjectList_ToolsDisplayOrder" : 0x24000010,
"BcdBootMgrBoolean_DisplayBootMenu" : 0x26000020,
"BcdBootMgrBoolean_NoErrorDisplay" : 0x26000021,
"BcdBootMgrDevice_BcdDevice" : 0x21000022,
"BcdBootMgrString_BcdFilePath" : 0x22000023,
"BcdBootMgrBoolean_ProcessCustomActionsFirst" : 0x26000028,
"BcdBootMgrIntegerList_CustomActionsList" : 0x27000030,
"BcdBootMgrBoolean_PersistBootSequence" : 0x26000031,
"BcdDeviceInteger_RamdiskImageOffset" : 0x35000001,
"BcdDeviceInteger_TftpClientPort" : 0x35000002,
"BcdDeviceInteger_SdiDevice" : 0x31000003,
"BcdDeviceInteger_SdiPath" : 0x32000004,
"BcdDeviceInteger_RamdiskImageLength" : 0x35000005,
"BcdDeviceBoolean_RamdiskExportAsCd" : 0x36000006,
"BcdDeviceInteger_RamdiskTftpBlockSize" : 0x36000007,
"BcdDeviceInteger_RamdiskTftpWindowSize" : 0x36000008,
"BcdDeviceBoolean_RamdiskMulticastEnabled" : 0x36000009,
"BcdDeviceBoolean_RamdiskMulticastTftpFallback" : 0x3600000A,
"BcdDeviceBoolean_RamdiskTftpVarWindow" : 0x3600000B,
"BcdMemDiagInteger_PassCount" : 0x25000001,
"BcdMemDiagInteger_FailureCount" : 0x25000003,
"Reserved1" : 0x21000001,
"Reserved2" : 0x22000002,
"BcdResumeBoolean_UseCustomSettings" : 0x26000003,
"BcdResumeDevice_AssociatedOsDevice" : 0x21000005,
"BcdResumeBoolean_DebugOptionEnabled" : 0x26000006,
"BcdResumeInteger_BootMenuPolicy" : 0x25000008,
"BcdOSLoaderDevice_OSDevice" : 0x21000001,
"BcdOSLoaderString_SystemRoot" : 0x22000002,
"BcdOSLoaderObject_AssociatedResumeObject" : 0x23000003,
"BcdOSLoaderBoolean_DetectKernelAndHal" : 0x26000010,
"BcdOSLoaderString_KernelPath" : 0x22000011,
"BcdOSLoaderString_HalPath" : 0x22000012,
"BcdOSLoaderString_DbgTransportPath" : 0x22000013,
"BcdOSLoaderInteger_NxPolicy" : 0x25000020,
"BcdOSLoaderInteger_PAEPolicy" : 0x25000021,
"BcdOSLoaderBoolean_WinPEMode" : 0x26000022,
"BcdOSLoaderBoolean_DisableCrashAutoReboot" : 0x26000024,
"BcdOSLoaderBoolean_UseLastGoodSettings" : 0x26000025,
"BcdOSLoaderBoolean_AllowPrereleaseSignatures" : 0x26000027,
"BcdOSLoaderBoolean_NoLowMemory" : 0x26000030,
"BcdOSLoaderInteger_RemoveMemory" : 0x25000031,
"BcdOSLoaderInteger_IncreaseUserVa" : 0x25000032,
"BcdOSLoaderBoolean_UseVgaDriver" : 0x26000040,
"BcdOSLoaderBoolean_DisableBootDisplay" : 0x26000041,
"BcdOSLoaderBoolean_DisableVesaBios" : 0x26000042,
"BcdOSLoaderBoolean_DisableVgaMode" : 0x26000043,
"BcdOSLoaderInteger_ClusterModeAddressing" : 0x25000050,
"BcdOSLoaderBoolean_UsePhysicalDestination" : 0x26000051,
"BcdOSLoaderInteger_RestrictApicCluster" : 0x25000052,
"BcdOSLoaderBoolean_UseLegacyApicMode" : 0x26000054,
"BcdOSLoaderInteger_X2ApicPolicy" : 0x25000055,
"BcdOSLoaderBoolean_UseBootProcessorOnly" : 0x26000060,
"BcdOSLoaderInteger_NumberOfProcessors" : 0x25000061,
"BcdOSLoaderBoolean_ForceMaximumProcessors" : 0x26000062,
"BcdOSLoaderBoolean_ProcessorConfigurationFlags" : 0x25000063,
"BcdOSLoaderBoolean_MaximizeGroupsCreated" : 0x26000064,
"BcdOSLoaderBoolean_ForceGroupAwareness" : 0x26000065,
"BcdOSLoaderInteger_GroupSize" : 0x25000066,
"BcdOSLoaderInteger_UseFirmwarePciSettings" : 0x26000070,
"BcdOSLoaderInteger_MsiPolicy" : 0x25000071,
"BcdOSLoaderInteger_SafeBoot" : 0x25000080,
"BcdOSLoaderBoolean_SafeBootAlternateShell" : 0x26000081,
"BcdOSLoaderBoolean_BootLogInitialization" : 0x26000090,
"BcdOSLoaderBoolean_VerboseObjectLoadMode" : 0x26000091,
"BcdOSLoaderBoolean_KernelDebuggerEnabled" : 0x260000a0,
"BcdOSLoaderBoolean_DebuggerHalBreakpoint" : 0x260000a1,
"BcdOSLoaderBoolean_UsePlatformClock" : 0x260000A2,
"BcdOSLoaderBoolean_ForceLegacyPlatform" : 0x260000A3,
"BcdOSLoaderInteger_TscSyncPolicy" : 0x250000A6,
"BcdOSLoaderBoolean_EmsEnabled" : 0x260000b0,
"BcdOSLoaderInteger_DriverLoadFailurePolicy" : 0x250000c1,
"BcdOSLoaderInteger_BootMenuPolicy" : 0x250000C2,
"BcdOSLoaderBoolean_AdvancedOptionsOneTime" : 0x260000C3,
"BcdOSLoaderInteger_BootStatusPolicy" : 0x250000E0,
"BcdOSLoaderBoolean_DisableElamDrivers" : 0x260000E1,
"BcdOSLoaderInteger_HypervisorLaunchType" : 0x250000F0,
"BcdOSLoaderBoolean_HypervisorDebuggerEnabled" : 0x260000F2,
"BcdOSLoaderInteger_HypervisorDebuggerType" : 0x250000F3,
"BcdOSLoaderInteger_HypervisorDebuggerPortNumber" : 0x250000F4,
"BcdOSLoaderInteger_HypervisorDebuggerBaudrate" : 0x250000F5,
"BcdOSLoaderInteger_HypervisorDebugger1394Channel" : 0x250000F6,
"BcdOSLoaderInteger_BootUxPolicy" : 0x250000F7,
"BcdOSLoaderString_HypervisorDebuggerBusParams" : 0x220000F9,
"BcdOSLoaderInteger_HypervisorNumProc" : 0x250000FA,
"BcdOSLoaderInteger_HypervisorRootProcPerNode" : 0x250000FB,
"BcdOSLoaderBoolean_HypervisorUseLargeVTlb" : 0x260000FC,
"BcdOSLoaderInteger_HypervisorDebuggerNetHostIp" : 0x250000FD,
"BcdOSLoaderInteger_HypervisorDebuggerNetHostPort" : 0x250000FE,
"BcdOSLoaderInteger_TpmBootEntropyPolicy" : 0x25000100,
"BcdOSLoaderString_HypervisorDebuggerNetKey" : 0x22000110,
"BcdOSLoaderBoolean_HypervisorDebuggerNetDhcp" : 0x26000114,
"BcdOSLoaderInteger_HypervisorIommuPolicy" : 0x25000115,
"BcdOSLoaderInteger_XSaveDisable" : 0x2500012b
}
def format_value(bcd, bcd_value):
name = bcd.value_key(bcd_value)
(type, length) = bcd.value_type(bcd_value)
typename = ""
str_value = ""
if type == REG_SZ:
typename = "SZ"
str_value = bcd.value_string(bcd_value)
elif type == REG_DWORD:
typename = "DWORD"
dval = bcd.value_dword(bcd_value)
str_value = hex(dval) + " (" + str(bcd.value_dword(bcd_value)) + ")"
elif type == REG_BINARY:
typename = "BIN"
(length, value) = bcd.value_value(bcd_value)
str_value = value.hex()
elif type == REG_DWORD_BIG_ENDIAN:
typename = "DWORD_BE"
elif type == REG_EXPAND_SZ:
typename = "EXPAND SZ"
elif type == REG_FULL_RESOURCE_DESCRIPTOR:
typename = "RES DESC"
elif type == REG_LINK:
typename = "LINK"
elif type == REG_MULTI_SZ:
typename = "MULTISZ"
(length, str_value) = bcd.value_value(bcd_value)
str_value = str_value.decode('utf-16le')
str_value = str_value.replace("\0", ";")
#value = ";".join("\0".split(value))
elif type == REG_NONE:
typename = "NONE"
elif type == REG_QWORD:
typename = "QWORD"
elif type == REG_RESOURCE_LIST:
typename = "RES LIST"
elif type == REG_RESOURCE_REQUIREMENTS_LIST:
typename = "REQ LIST"
else:
typename = str(type)
str_value = "???"
return (typename, length, str_value)
def dump_all(root, depth = 0):
padding = "\t" * depth
children = bcd.node_children(root)
if len(children) > 0:
for child in children:
name = bcd.node_name(child)
print(f"{padding}{name}")
dump_all(child, depth + 1)
# print(f"Child: {child}")
#print(f"Values: {num_vals}")
return
values = bcd.node_values(root)
#print(f"Value list: {values}")
for v in values:
(type_name, length, str_value) = format_value(bcd, v)
name = bcd.value_key(v)
print(f"{padding}{name: <16}: [{type_name: <10}]; ({length: < 4}) {str_value}")
class WindowsBCD:
def __init__(self, filename):
self.filename = filename
self.bcd = Hivex(filename)
def dump(self, root=None, depth = 0):
padding = "\t" * depth
if root is None:
root = self.bcd.root()
children = self.bcd.node_children(root)
if len(children) > 0:
for child in children:
name = self.bcd.node_name(child)
print(f"{padding}{name}")
self.dump(child, depth + 1)
return
values = self.bcd.node_values(root)
for v in values:
(type_name, length, str_value) = format_value(self.bcd, v)
name = self.bcd.value_key(v)
print(f"{padding}{name: <16}: [{type_name: <10}]; ({length: < 4}) {str_value}")
def list(self):
root = self.bcd.root()
objects = self.bcd.node_get_child(root, "Objects")
for child in self.bcd.node_children(objects):
entry_id = self.bcd.node_name(child)
elements = self.bcd.node_get_child(child, "Elements")
description_entry = self.bcd.node_get_child(elements, "12000004")
if description_entry:
values = self.bcd.node_values(description_entry)
if values:
(type_name, length, str_value) = format_value(self.bcd, values[0])
print(f"{entry_id}: {str_value}")
else:
print(f"{entry_id}: [no description value!?]")
appdevice_entry = self.bcd.node_get_child(elements, "11000001")
if appdevice_entry:
values = self.bcd.node_values(appdevice_entry)
(length, data) = self.bcd.value_value(values[0])
hex = data.hex()
print(f"LEN: {length}, HEX: {hex}, RAW: {data}")
if len(data) > 10:
etype = struct.unpack_from('<I', data, offset = 16)
print(f"Type: {etype}")
else:
print(f"{entry_id}: [no description entry 12000004]")
parser = argparse.ArgumentParser(
prog="Windows BCD parser",
description="Parses the BCD",
)
parser.add_argument("--db", type=str, metavar='BCD file', help="Database to use")
parser.add_argument("--dump", action='store_true', help="Dumps the specified database")
parser.add_argument("--list", action='store_true', help="Lists boot entries in the specified database")
args = parser.parse_args()
bcdobj = WindowsBCD(args.db)
if args.dump:
# "/home/vadim/opengnsys/winboot/boot-copy/EFI/Microsoft/Boot/BCD"
#bcd = Hivex(args.dump)
#root = bcd.root()
#dump_all(root)
bcdobj.dump()
elif args.list:
bcdobj.list()

View File

@ -0,0 +1,124 @@
import logging
import subprocess
import re
# pylint: disable=locally-disabled, line-too-long, logging-fstring-interpolation, too-many-lines
class DiskLibrary:
def __init__(self):
self.logger = logging.getLogger("OpengnsysDiskLibrary")
self.logger.setLevel(logging.DEBUG)
def split_device_partition(self, device):
"""
Parses a device file like /dev/sda3 into the root device (/dev/sda) and partition number (3)
Args:
device (str): Device in /dev
Returns:
[base_device, partno]
"""
r = re.compile("^(.*?)(\\d+)$")
m = r.match(device)
disk = m.group(1)
partno = int(m.group(2))
self.logger.debug(f"{device} parsed into disk device {disk}, partition {partno}")
return (disk, partno)
def get_disk_json_data(self, device):
"""
Returns the partition JSON data dump for the entire disk, even if a partition is passed.
This is specifically in the format used by sfdisk.
Args:
device (str): Block device, eg, /dev/sda3
Returns:
str: JSON dump produced by sfdisk
"""
(disk, partno) = self.split_device_partition(device)
result = subprocess.run(["/usr/sbin/sfdisk", "--json", disk], check=True, capture_output=True, encoding='utf-8')
return result.stdout.strip()
def get_disk_uuid(self, device):
"""
Returns the UUID of the disk itself, if there's a GPT partition table.
Args:
device (str): Block device, eg, /dev/sda3
Returns:
str: UUID
"""
(disk, partno) = self.split_device_partition(device)
result = subprocess.run(["/usr/sbin/sfdisk", "--disk-id", disk], check=True, capture_output=True, encoding='utf-8')
return result.stdout.strip()
def set_disk_uuid(self, device, uuid):
(disk, partno) = self.split_device_partition(device)
subprocess.run(["/usr/sbin/sfdisk", "--disk-id", disk, uuid], check=True, encoding='utf-8')
def get_partition_uuid(self, device):
"""
Returns the UUID of the partition, if there's a GPT partition table.
Args:
device (str): Block device, eg, /dev/sda3
Returns:
str: UUID
"""
(disk, partno) = self.split_device_partition(device)
#result = subprocess.run(["/usr/sbin/sfdisk", "--part-uuid", disk, str(partno)], check=True, capture_output=True, encoding='utf-8')
#return result.stdout.strip()
guid = None
result = subprocess.run(["/usr/sbin/sgdisk", "--info", str(partno), disk], check=True, capture_output=True, encoding='utf-8')
for l in result.stdout.splitlines():
if 'Partition unique GUID' not in l: continue
guid = l.replace ('Partition unique GUID: ', '')
if guid is None:
self.logger.error (f'failed to get UUID of disk "{disk}" part "{partno}"')
return None
return guid
def set_partition_uuid(self, device, uuid):
(disk, partno) = self.split_device_partition(device)
subprocess.run(["/usr/sbin/sfdisk", "--part-uuid", disk, str(partno), uuid], check=True, encoding='utf-8')
def get_partition_type(self, device):
"""
Returns the type UUID of the partition, if there's a GPT partition table.
Args:
device (str): Block device, eg, /dev/sda3
Returns:
str: UUID
"""
(disk, partno) = self.split_device_partition(device)
result = subprocess.run(["/usr/sbin/sfdisk", "--part-type", disk, str(partno)], check=True, capture_output=True, encoding='utf-8')
return result.stdout.strip()
def set_partition_type(self, device, uuid):
(disk, partno) = self.split_device_partition(device)
subprocess.run(["/usr/sbin/sfdisk", "--part-type", disk, str(partno), uuid], check=True, encoding='utf-8')

View File

@ -0,0 +1,544 @@
import logging
import subprocess
import os
import json
import blkid
import time
from ntfs import *
# pylint: disable=locally-disabled, line-too-long, logging-fstring-interpolation, too-many-lines
class FilesystemLibrary:
def __init__(self, ntfs_implementation = NTFSImplementation.KERNEL):
self.logger = logging.getLogger("OpengnsysFilesystemLibrary")
self.logger.setLevel(logging.DEBUG)
self.mounts = {}
self.base_mount_path = "/mnt"
self.ntfs_implementation = ntfs_implementation
self.update_mounts()
def _rmmod(self, module):
self.logger.debug("Trying to unload module {module}...")
subprocess.run(["/usr/sbin/rmmod", module], check=False)
def _modprobe(self, module):
self.logger.debug("Trying to load module {module}...")
subprocess.run(["/usr/sbin/modprobe", module], check=True)
# _parse_mounts
def update_mounts(self):
"""
Update the current mount points by parsing the /proc/mounts file.
This method reads the /proc/mounts file to gather information about
the currently mounted filesystems. It stores this information in a
dictionary where the keys are the mount points and the values are
dictionaries containing details about each filesystem.
The details stored for each filesystem include:
- device: The device file associated with the filesystem.
- mountpoint: The directory where the filesystem is mounted.
- type: The type of the filesystem (e.g., ext4, vfat).
- options: Mount options associated with the filesystem.
- dump_freq: The dump frequency for the filesystem.
- passno: The pass number for filesystem checks.
The method also adds an entry for each mount point with a trailing
slash to ensure consistency in accessing the mount points.
Attributes:
mounts (dict): A dictionary where keys are mount points and values
are dictionaries containing filesystem details.
"""
filesystems = {}
self.logger.debug("Parsing /proc/mounts")
with open("/proc/mounts", 'r', encoding='utf-8') as mounts:
for line in mounts:
parts = line.split()
data = {}
data['device'] = parts[0]
data['mountpoint'] = parts[1]
data['type'] = parts[2]
data['options'] = parts[3]
data['dump_freq'] = parts[4]
data['passno'] = parts[5]
filesystems[data["mountpoint"]] = data
filesystems[data["mountpoint"] + "/"] = data
self.mounts = filesystems
def find_mountpoint(self, device):
"""
Find the mount point for a given device.
This method checks if the specified device is currently mounted and returns
the corresponding mount point if it is found.
Args:
device (str): The path to the device to check.
Returns:
str or None: The mount point of the device if it is mounted, otherwise None.
"""
norm = os.path.normpath(device)
self.logger.debug(f"Checking if {device} is mounted")
for mountpoint, mount in self.mounts.items():
#self.logger.debug(f"Item: {mount}")
#self.logger.debug(f"Checking: " + mount['device'])
if mount['device'] == norm:
return mountpoint
return None
def find_device(self, mountpoint):
"""
Find the device corresponding to a given mount point.
Args:
mountpoint (str): The mount point to search for.
Returns:
str or None: The device corresponding to the mount point if found,
otherwise None.
"""
self.update_mounts()
self.logger.debug("Finding device corresponding to mount point %s", mountpoint)
if mountpoint in self.mounts:
return self.mounts[mountpoint]['device']
else:
self.logger.warning("Failed to find mountpoint %s", mountpoint)
return None
def is_mounted(self, device = None, mountpoint = None):
def is_mounted(self, device=None, mountpoint=None):
"""
Check if a device or mountpoint is currently mounted.
Either checking by device or mountpoint is valid.
Args:
device (str, optional): The device to check if it is mounted.
Defaults to None.
mountpoint (str, optional): The mountpoint to check if it is mounted.
Defaults to None.
Returns:
bool: True if the device is mounted or the mountpoint is in the list
of mounts, False otherwise.
"""
self.update_mounts()
if device:
return not self.find_mountpoint(device) is None
else:
return mountpoint in self.mounts
def unmount(self, device = None, mountpoint = None):
def unmount(self, device=None, mountpoint=None):
"""
Unmounts a filesystem.
This method unmounts a filesystem either by the device name or the mountpoint.
If a device is provided, it finds the corresponding mountpoint and unmounts it.
If a mountpoint is provided directly, it unmounts the filesystem at that mountpoint.
Args:
device (str, optional): The device name to unmount. Defaults to None.
mountpoint (str, optional): The mountpoint to unmount. Defaults to None.
Raises:
subprocess.CalledProcessError: If the unmount command fails.
Logs:
Debug information about the unmounting process.
"""
if device:
self.logger.debug("Finding mountpoint of %s", device)
mountpoint = self.find_mountpoint(device)
if not mountpoint is None:
self.logger.debug(f"Unmounting {mountpoint}")
done = False
start_time = time.time()
timeout = 60
while not done and (time.time() - start_time) < timeout:
ret = subprocess.run(["/usr/bin/umount", mountpoint], check=False, capture_output=True, encoding='utf-8')
if ret.returncode == 0:
done=True
else:
if "target is busy" in ret.stderr:
self.logger.debug("Filesystem busy, waiting. %.1f seconds left", timeout - (time.time() - start_time))
time.sleep(0.1)
else:
raise subprocess.CalledProcessError(ret.returncode, ret.args, output=ret.stdout, stderr=ret.stderr)
# We've unmounted a new filesystem, update our filesystems list
self.update_mounts()
else:
self.logger.debug(f"{device} is not mounted")
def mount(self, device, mountpoint, filesystem = None):
"""
Mounts a device to a specified mountpoint.
Parameters:
device (str): The device to be mounted (e.g., '/dev/sda1').
mountpoint (str): The directory where the device will be mounted.
filesystem (str, optional): The type of filesystem to be used (e.g., 'ext4', 'ntfs'). Defaults to None.
Raises:
subprocess.CalledProcessError: If the mount command fails.
Logs:
Debug information about the mounting process, including the mount command, return code, stdout, and stderr.
Side Effects:
Creates the mountpoint directory if it does not exist.
Updates the internal list of mounted filesystems.
"""
self.logger.debug(f"Mounting {device} at {mountpoint}")
if not os.path.exists(mountpoint):
self.logger.debug(f"Creating directory {mountpoint}")
os.mkdir(mountpoint)
mount_cmd = ["/usr/bin/mount"]
if not filesystem is None:
mount_cmd = mount_cmd + ["-t", filesystem]
mount_cmd = mount_cmd + [device, mountpoint]
self.logger.debug(f"Mount command: {mount_cmd}")
result = subprocess.run(mount_cmd, check=True, capture_output = True)
self.logger.debug(f"retorno: {result.returncode}")
self.logger.debug(f"stdout: {result.stdout}")
self.logger.debug(f"stderr: {result.stderr}")
# We've mounted a new filesystem, update our filesystems list
self.update_mounts()
def ensure_mounted(self, device):
"""
Ensure that the given device is mounted.
This method attempts to mount the specified device to a path derived from
the base mount path and the device's basename. If the device is of type NTFS,
it uses the NTFSLibrary to handle the mounting process. For other filesystem
types, it uses a generic mount method.
Args:
device (str): The path to the device that needs to be mounted.
Returns:
str: The path where the device is mounted.
Logs:
- Info: When starting the mounting process.
- Debug: Various debug information including the mount path, filesystem type,
and success message.
Raises:
OSError: If there is an error creating the mount directory or mounting the device.
"""
self.logger.info("Mounting %s", device)
self.unmount(device = device)
path = os.path.join(self.base_mount_path, os.path.basename(device))
self.logger.debug(f"Will mount repo at {path}")
if not os.path.exists(path):
os.mkdir(path)
if self.filesystem_type(device) == "ntfs":
self.logger.debug("Handing a NTFS filesystem")
self._modprobe("ntfs3")
self.ntfsfix(device)
ntfs = NTFSLibrary(self.ntfs_implementation)
ntfs.mount_filesystem(device, path)
self.update_mounts()
else:
self.logger.debug("Handling a non-NTFS filesystem")
self.mount(device, path)
self.logger.debug("Successfully mounted at %s", path)
return path
def filesystem_type(self, device = None, mountpoint = None):
"""
Determine the filesystem type of a given device or mountpoint.
Args:
device (str, optional): The device to probe. If not provided, the device
will be determined based on the mountpoint.
mountpoint (str, optional): The mountpoint to find the device for. This
is used only if the device is not provided.
Returns:
str: The filesystem type of the device.
Raises:
KeyError: If the filesystem type cannot be determined from the probe.
Logs:
Debug: Logs the process of finding the device, probing the device, and
the determined filesystem type.
"""
if device is None:
self.logger.debug("Finding device for mountpoint %s", mountpoint)
device = self.find_device(mountpoint)
self.logger.debug(f"Probing {device}")
pr = blkid.Probe()
pr.set_device(device)
pr.enable_superblocks(True)
pr.set_superblocks_flags(blkid.SUBLKS_TYPE | blkid.SUBLKS_USAGE | blkid.SUBLKS_UUID | blkid.SUBLKS_UUIDRAW | blkid.SUBLKS_LABELRAW)
pr.do_safeprobe()
fstype = pr["TYPE"].decode('utf-8')
self.logger.debug(f"FS type is {fstype}")
return fstype
def is_filesystem(self, path):
"""
Check if the given path is a filesystem root.
Args:
path (str): The path to check.
Returns:
bool: True if the path is a filesystem root, False otherwise.
"""
# This is just an alias for better code readability
return self.is_mounted(mountpoint = path)
def create_filesystem(self, fs_type = None, fs_uuid = None, device = None):
"""
Create a filesystem on the specified device.
Parameters:
fs_type (str): The type of filesystem to create (e.g., 'ntfs', 'ext4', 'xfs', 'btrfs').
fs_uuid (str): The UUID to assign to the filesystem.
device (str): The device on which to create the filesystem (e.g., '/dev/sda1').
Raises:
RuntimeError: If the filesystem type is not recognized or if the filesystem creation command fails.
"""
self.logger.info(f"Creating filesystem {fs_type} with UUID {fs_uuid} in {device}")
if fs_type == "ntfs" or fs_type == "ntfs3":
self.logger.debug("Creating NTFS filesystem")
ntfs = NTFSLibrary(self.ntfs_implementation)
ntfs.create_filesystem(device, "NTFS")
ntfs.modify_uuid(device, fs_uuid)
else:
command = [f"/usr/sbin/mkfs.{fs_type}"]
command_args = []
if fs_type == "ext4" or fs_type == "ext3":
command_args = ["-U", fs_uuid, "-F", device]
elif fs_type == "xfs":
command_args = ["-m", f"uuid={fs_uuid}", "-f", device]
elif fs_type == "btrfs":
command_args = ["-U", fs_uuid, "-f", device]
else:
raise RuntimeError(f"Don't know how to create filesystem of type {fs_type}")
command = command + command_args
self.logger.debug(f"Creating Linux filesystem of type {fs_type} on {device}, command {command}")
result = subprocess.run(command, check = True, capture_output=True)
self.logger.debug(f"retorno: {result.returncode}")
self.logger.debug(f"stdout: {result.stdout}")
self.logger.debug(f"stderr: {result.stderr}")
def mklostandfound(self, path):
"""
Recreate the lost+found if necessary.
When cloning at the root of a filesystem, cleaning the contents
removes the lost+found directory. This is a special directory that requires the use of
a tool to recreate it.
It may fail if the filesystem does not need it. We consider this harmless and ignore it.
The command is entirely skipped on NTFS, as mklost+found may malfunction if run on it,
and has no useful purpose.
"""
if self.is_filesystem(path):
if self.filesystem_type(mountpoint=path) == "ntfs":
self.logger.debug("Not running mklost+found on NTFS")
return
curdir = os.getcwd()
result = None
try:
self.logger.debug(f"Re-creating lost+found in {path}")
os.chdir(path)
result = subprocess.run(["/usr/sbin/mklost+found"], check=True, capture_output=True)
except subprocess.SubprocessError as e:
self.logger.warning(f"Error running mklost+found: {e}")
if result:
self.logger.debug(f"retorno: {result.returncode}")
self.logger.debug(f"stdout: {result.stdout}")
self.logger.debug(f"stderr: {result.stderr}")
os.chdir(curdir)
def ntfsfix(self, device):
"""
Run the ntfsfix command on the specified device.
This method uses the ntfsfix utility to fix common NTFS problems on the given device.
This allows mounting an unclean NTFS filesystem.
Args:
device (str): The path to the device to be fixed.
Raises:
subprocess.CalledProcessError: If the ntfsfix command fails.
"""
self.logger.debug(f"Running ntfsfix on {device}")
subprocess.run(["/usr/bin/ntfsfix", "-d", device], check=True)
def unload_ntfs(self):
"""
Unloads the NTFS filesystem module.
This is a function added as a result of NTFS kernel module troubleshooting,
to try to ensure that NTFS code is only active as long as necessary.
The module is internally loaded as needed, so there's no load_ntfs function.
It may be removed in the future.
Raises:
RuntimeError: If the module cannot be removed.
"""
self._rmmod("ntfs3")
def find_boot_device(self):
"""
Searches for the EFI boot partition on the system.
This method scans the system's partitions to locate the EFI boot partition,
which is identified by the GUID "C12A7328-F81F-11D2-BA4B-00A0C93EC93B".
Returns:
str: The device node of the EFI partition if found, otherwise None.
Logs:
- Debug messages indicating the progress of the search.
- A warning message if the EFI partition is not found.
"""
disks = []
self.logger.debug("Looking for EFI partition")
with open("/proc/partitions", "r", encoding='utf-8') as partitions_file:
line_num=0
for line in partitions_file:
if line_num >=2:
data = line.split()
disk = data[3]
disks.append(disk)
self.logger.debug(f"Disk: {disk}")
line_num = line_num + 1
for disk in disks:
self.logger.debug("Loading partitions for disk %s", disk)
#disk_json_data = subprocess.run(["/usr/sbin/sfdisk", "-J", f"/dev/{disk}"], check=False, capture_output=True)
sfdisk_out = subprocess.run(["/usr/sbin/sfdisk", "-J", f"/dev/{disk}"], check=False, capture_output=True)
if sfdisk_out.returncode == 0:
disk_json_data = sfdisk_out.stdout
disk_data = json.loads(disk_json_data)
for part in disk_data["partitiontable"]["partitions"]:
self.logger.debug("Checking partition %s", part)
if part["type"] == "C12A7328-F81F-11D2-BA4B-00A0C93EC93B":
self.logger.debug("EFI partition found at %s", part["node"])
return part["node"]
else:
self.logger.debug("sfdisk returned with code %i, error %s", sfdisk_out.returncode, sfdisk_out.stderr)
self.logger.warning("Failed to find EFI partition!")
def temp_unmount(self, mountpoint):
"""
Temporarily unmounts the filesystem at the given mountpoint.
This method finds the device associated with the specified mountpoint,
and returns the information to remount it with temp_remount.
The purpose of this function is to temporarily unmount a filesystem for
actions like fsck, and to mount it back afterwards.
Args:
mountpoint (str): The mountpoint of the filesystem to unmount.
Returns:
dict: A dictionary containing the information needed to remount the filesystem.
"""
device = self.find_device(mountpoint)
fs = self.filesystem_type(mountpoint = mountpoint)
data = {"mountpoint" : mountpoint, "device" :device, "filesystem" : fs}
self.logger.debug("Temporarily unmounting device %s, mounted on %s, fs type %s", mountpoint, device, fs)
self.unmount(mountpoint = mountpoint)
return data
def temp_remount(self, unmount_data):
"""
Remounts a filesystem unmounted with temp_unmount
This method remounts a filesystem using the data provided by temp_unmount
Args:
unmount_data (dict): A dictionary containing the data needed to remount the filesystem.
Returns:
None
"""
self.logger.debug("Remounting temporarily unmounted device %s on %s, fs type %s", unmount_data["device"], unmount_data["mountpoint"], unmount_data["filesystem"])
self.mount(device = unmount_data["device"], mountpoint=unmount_data["mountpoint"], filesystem=unmount_data["filesystem"])

View File

@ -0,0 +1,52 @@
#!/usr/bin/env python3
import unittest
import logging
import os
import sys
import urllib.request
import tarfile
import subprocess
from shutil import rmtree
from pathlib import Path
parent_dir = str(Path(__file__).parent.parent.absolute())
sys.path.append(parent_dir)
sys.path.append("/opengnsys/installer")
print(parent_dir)
from gitlib import OpengnsysGitLibrary
class GitTests(unittest.TestCase):
def setUp(self):
self.logger = logging.getLogger("OpengnsysTest")
self.oggit = OpengnsysGitLibrary()
self.logger.info("setUp()")
if not hasattr(self, 'init_complete'):
self.init_complete = True
def test_init(self):
self.assertIsNotNone(self.oggit)
def test_acls(self):
self.oggit.ogCreateAcl()
def test_sync_local(self):
# self.oggit.ogSyncLocalGitImage()
None
if __name__ == '__main__':
logging.basicConfig(level=logging.DEBUG, format='%(asctime)s - %(name)20s - [%(levelname)5s] - %(message)s')
logger = logging.getLogger(__name__)
logger.setLevel(logging.DEBUG)
logger.info("Inicio del programa")
unittest.main()

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,22 @@
def parse_kernel_cmdline():
"""Parse the kernel arguments to obtain configuration parameters in Oglive
OpenGnsys passes data in the kernel arguments, for example:
[...] group=Aula_virtual ogrepo=192.168.2.1 oglive=192.168.2.1 [...]
Returns:
dict: Dict of configuration parameters and their values.
"""
params = {}
with open("/proc/cmdline", encoding='utf-8') as cmdline:
line = cmdline.readline()
parts = line.split()
for part in parts:
if "=" in part:
key, value = part.split("=")
params[key] = value
return params

View File

@ -0,0 +1,111 @@
import logging
import subprocess
from enum import Enum
class NTFSImplementation(Enum):
KERNEL = 1
NTFS3G = 2
class NTFSLibrary:
"""
A library for managing NTFS filesystems.
Attributes:
logger (logging.Logger): Logger for the class.
implementation (NTFSImplementation): The implementation to use for mounting NTFS filesystems.
"""
def __init__(self, implementation):
"""
Initializes the instance with the given implementation.
Args:
implementation: The implementation to be used by the instance.
Attributes:
logger (logging.Logger): Logger instance for the class, set to debug level.
implementation: The implementation provided during initialization.
"""
self.logger = logging.getLogger("NTFSLibrary")
self.logger.setLevel(logging.DEBUG)
self.implementation = implementation
self.logger.debug("Initializing")
def create_filesystem(self, device, label):
"""
Creates an NTFS filesystem on the specified device with the given label.
Args:
device (str): The device path where the NTFS filesystem will be created.
label (str): The label to assign to the NTFS filesystem.
Returns:
None
Logs:
Logs the creation process with the device and label information.
"""
self.logger.info(f"Creating NTFS in {device} with label {label}")
subprocess.run(["/usr/sbin/mkntfs", device, "-Q", "-L", label], check=True)
def mount_filesystem(self, device, mountpoint):
"""
Mounts a filesystem on the specified mountpoint using the specified NTFS implementation.
Args:
device (str): The device path to be mounted (e.g., '/dev/sda1').
mountpoint (str): The directory where the device will be mounted.
Raises:
ValueError: If the NTFS implementation is unknown.
"""
self.logger.info(f"Mounting {device} in {mountpoint} using implementation {self.implementation}")
if self.implementation == NTFSImplementation.KERNEL:
subprocess.run(["/usr/bin/mount", "-t", "ntfs3", device, mountpoint], check = True)
elif self.implementation == NTFSImplementation.NTFS3G:
subprocess.run(["/usr/bin/ntfs-3g", device, mountpoint], check = True)
else:
raise ValueError("Unknown NTFS implementation: {self.implementation}")
def modify_uuid(self, device, uuid):
"""
Modify the UUID of an NTFS device.
This function changes the UUID of the specified NTFS device to the given UUID.
It reads the current UUID from the device, logs the change, and writes the new UUID.
Args:
device (str): The path to the NTFS device file.
uuid (str): The new UUID to be set, in hexadecimal string format.
Raises:
IOError: If there is an error opening or writing to the device file.
"""
ntfs_uuid_offset = 0x48
ntfs_uuid_length = 8
binary_uuid = bytearray.fromhex(uuid)
binary_uuid.reverse()
self.logger.info(f"Changing UUID on {device} to {uuid}")
with open(device, 'r+b') as ntfs_dev:
self.logger.debug("Reading %i bytes from offset %i", ntfs_uuid_length, ntfs_uuid_offset)
ntfs_dev.seek(ntfs_uuid_offset)
prev_uuid = bytearray(ntfs_dev.read(ntfs_uuid_length))
prev_uuid.reverse()
prev_uuid_hex = bytearray.hex(prev_uuid)
self.logger.debug(f"Previous UUID: {prev_uuid_hex}")
self.logger.debug("Writing...")
ntfs_dev.seek(ntfs_uuid_offset)
ntfs_dev.write(binary_uuid)

View File

@ -0,0 +1,13 @@
#!/usr/bin/env python3
def _hex_to_bin( hex_str):
while len(hex_str) != 16:
hex_str = "0" + hex_str
hex_int = int(hex_str, 16)
binary = bin(hex_int)[2:].zfill(64)
return binary
print( _hex_to_bin("0ACA"))

View File

@ -1,62 +0,0 @@
import sys
import os
import subprocess
import SystemLib
import FileSystemLib
import DiskLib
import Boot
#!/usr/bin/env python3
# Script de ejemplo para arrancar un sistema operativo instalado.
# Nota: se usa como base para el programa de arranque de OpenGnsys Admin.
def main():
prog = os.path.basename(__file__)
if len(sys.argv) < 3 or len(sys.argv) > 6:
SystemLib.ogRaiseError(1, f"Formato: {prog} ndisco nfilesys [str_kernel str_initrd str_kernelparams]")
disk = sys.argv[1]
filesystem = sys.argv[2]
try:
part = DiskLib.ogDiskToDev(disk, filesystem)
except Exception as e:
sys.exit(1)
try:
mntdir = FileSystemLib.ogMount(disk, filesystem)
except Exception as e:
sys.exit(1)
print("[0] Inicio del proceso de arranque.")
mount_output = subprocess.getoutput(f"mount | grep -q '{mntdir}.*(rw'")
if mount_output:
SystemLib.ogEcho("log", "session", "MSG_WARNING: MSG_MOUNTREADONLY")
FileSystemLib.ogUnmount(disk, filesystem)
FileSystemLib.ogCheckFs(disk, filesystem)
part = DiskLib.ogDiskToDev(disk, filesystem)
os.makedirs(mntdir, exist_ok=True)
subprocess.run(["ntfs-3g", "-o", "remove_hiberfile", part, mntdir])
SystemLib.ogEcho("log", "session", "Particion desbloqueada")
FileSystemLib.ogUnmount(disk, filesystem)
FileSystemLib.ogMount(disk, filesystem)
if subprocess.call("which bootOsCustom", shell=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) == 0:
print("[10] Configuración personalizada del inicio.")
subprocess.run(["bootOsCustom"] + sys.argv[1:])
print("[70] Desmontar todos los sistemas de archivos.")
subprocess.run(["sync"])
for i in range(1, len(DiskLib.ogDiskToDev(disk, filesystem).split())):
FileSystemLib.ogUnmountAll(i)
print("[80] Desmontar cache local.")
FileSystemLib.ogUnmount_cache()
print("[90] Arrancar sistema operativo.")
BootLib.ogBoot(sys.argv[1:])
if __name__ == "__main__":
main()

View File

@ -1,105 +0,0 @@
import sys
import os
import SystemLib
import DiskLib
import FileSystemLib
import NetLib
import FileLib
#!/usr/bin/env python3
"""
bootOsCustom
@brief Plantilla para script de configuración personalizada de sistema operativo restaurado.
@param $1 de disco
@param $2 de partición
@warning Renombrar este fichero como "bootOsCustom" para personalizar el script estándar "bootOs".
@note La partición a inicializar debe estar montada
@version 1.1.1 Soporta varios discos
"""
# CONFIGURAR: Partición de datos de Windows que no queremos ocultar (valor por defecto '0' no oculta nada)
DISKDATA = 0
PARTDATA = 0
PROG = os.path.basename(__file__)
# Control de errores
if len(sys.argv) < 3:
SystemLib.ogRaiseError(OG_ERR_FORMAT, f"Formato: {PROG} ndisco nparticion")
sys.exit(1)
# Parámetros obligatorios.
DISK = sys.argv[1] # Nº de disco.
PART = sys.argv[2] # Nº de partición.
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
DEVICE = DiskLib.ogDiskToDev(DISK, PART)
if not DEVICE:
sys.exit(1)
# Paso 1: Adaptar el código de ejemplo para arranque personalizado.
# Nota: el script "bootOs" llama al script "bootOsCustom" después de realizar la operaciones de inicio estándar y antes de desmontar las particiones e iniciar el sistema operativo.
MNTDIR = FileSystemLib.ogMount(DISK, PART)
if not MNTDIR:
sys.exit(1)
NAME = NetLib.ogGetHostname()
NAME = NAME if NAME else "pc"
OSTYPE = Inventory.ogGetOsType(DISK, PART)
if OSTYPE == "Windows":
# Mostrar las particiones NTFS de sistema (dos opciones)
# Opción 1: SIN ocultar las demás.
# SystemLib.ogEcho log session "[40] Mostrar y activar particion de Windows {PART}."
# if DiskLib.ogGetPartitionType(DISK, PART) in ["HNTFS", "WIN-RESERV"]:
# DiskLib.ogUnhidePartition(DISK, PART)
# Recorremos los distintos discos
# for DEVICE in DiskLib.ogDiskToDev():
# d = DiskLib.ogDevToDisk(DEVICE)
# # Mostrar las particiones NTFS de sistema (dos opciones)
# # Opción 2: Ocultamos las demás.
# SystemLib.ogEcho log session "[40] Activar particion de Windows {PART} y ocultar las demás."
# for i in range(1, DiskLib.ogGetPartitionsNumber(d) + 1):
# if (d == DISK and i == PART) or (d == DISKDATA and i == PARTDATA):
# if DiskLib.ogGetPartitionType(d, i) in ["HNTFS", "WIN-RESERV"]:
# DiskLib.ogUnhidePartition(d, i)
# else:
# if DiskLib.ogGetPartitionType(d, i) in ["NTFS", "WINDOWS"]:
# DiskLib.ogHidePartition(d, i)
# # Borrar marcas de arrranque de todos los Windows instalados en el disco.
# SystemLib.ogEcho log session "[30] Borrar marcas de arrranque de todos los Windows instalados en el disco."
# for i in range(1, DiskLib.ogGetPartitionsNumber(d) + 1):
# if Inventory.ogGetOsType(d, i) == "Windows":
# FileSystemLib.ogMount(d, i)
# os.system("rm -f /mnt/*/ogboot.*")
elif OSTYPE == "Linux":
# Modificar el nombre del equipo
# SystemLib.ogEcho log session "[30] Asignar nombre Linux \"{NAME}\"."
# ETC = FileLib.ogGetPath(DISK, PART, "/etc")
# if os.path.isdir(ETC):
# with open(os.path.join(ETC, "hostname"), "w") as f:
# f.write(NAME)
# Sustituir UUID o LABEL por su dispositivo en definición de sistema de archivo raíz.
# if os.path.isfile(os.path.join(ETC, "fstab")):
# SystemLib.ogEcho log session "[40] Actualizar fstab con particion raíz \"{PART}\"."
# with open(os.path.join(ETC, "fstab"), "r") as f:
# lines = f.readlines()
# with open("/tmp/fstab", "w") as f:
# for line in lines:
# if line.split()[1] == "/" and not line.startswith("#"):
# line = line.replace(line.split()[0], PART)
# f.write(line)
# os.replace("/tmp/fstab", os.path.join(ETC, "fstab"))
# Cambiar claves usuarios, copiando fichero /etc/passwd
# En el servidor el nuevo fichero debe situarse en el directorio del grupo:
# /opt/opengnsys/images/groups/nombre_aula
# if os.path.isfile(os.path.join(ogGetGroupDir(), "passwd")):
# SystemLib.ogEcho log session "[65] Cambiar claves de usuarios."
# os.system(f"cp {os.path.join(ogGetGroupDir(), 'passwd')} {os.path.join(MNTDIR, 'etc')}")

View File

@ -4,6 +4,7 @@
import sys
import re
import os
import subprocess
import shutil
@ -46,7 +47,7 @@ if not mount_out or not re.search (rf'{mntdir}.*\(rw', mount_out):
if shutil.which ('bootOsCustom.py'):
print ('[10] Configuración personalizada del inicio.')
subprocess.run ([f'{ogGlobals.OGSCRIPTS}/bootOsCustom.py'])
subprocess.run ([f'{ogGlobals.OGSCRIPTS}/bootOsCustom.py', disk, par])
print ('[70] Desmontar todos los sistemas de archivos.')
subprocess.run (['sync'])

View File

@ -1,92 +0,0 @@
#!/bin/bash
#/**
# bootOsCustom
#@brief Plantilla para script de configuración personalizada de sistema operativo restaurado.
#@param $1 nº de disco
#@param $2 nº de partición
#@warning Renombrar este fichero como "bootOsCustom" para personalizar el script estándar "bootOs".
#@note La partición a inicializar debe estar montada
#@version 1.1.1 Soporta varios discos
#@date 2019/08/26
#**/
# CONFIGURAR: Partición de datos de Windows que no queremos ocultar (valor por defecto '0' no oculta nada)
DISKDATA=0
PARTDATA=0
PROG="$(basename $0)"
# Control de errores
if [ $# -lt 2 ]; then
ogRaiseError $OG_ERR_FORMAT "Formato: $PROG ndisco nparticion"
exit $?
fi
# Parámetros obligatorios.
DISK="$1" # Nº de disco.
PART="$2" # Nº de partición.
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
DEVICE=$(ogDiskToDev "$DISK" "$PART") || exit $?
# Paso 1: Adaptar el código de ejemplo para arranque personalizado.
# Nota: el script "bootOs" llama al script "bootOsCustom" después de realizar la operaciones de inicio estándar y antes de desmontar las particiones e iniciar el sistema operativo.
MNTDIR=$(ogMount $DISK $PART) || exit $?
NAME="$(ogGetHostname)"
NAME=${NAME:-"pc"}
OSTYPE=$(ogGetOsType $DISK $PART)
case "$OSTYPE" in
Windows)
## Mostrar las particiones NTFS de sistema (dos opciones)
## Opción 1: SIN ocultar las demás.
#ogEcho log session "[40] Mostrar y activar particion de Windows $PART."
#[ $(ogGetPartitionType $DISK $PART) == "HNTFS" -o $(ogGetPartitionType $DISK $PART) == "WIN-RESERV" ] && ogUnhidePartition $DISK $PART
## Recorremos los distintos discos
#for DEVICE in $(ogDiskToDev); do
# d=$(ogDevToDisk $DEVICE)
# ## Mostrar las particiones NTFS de sistema (dos opciones)
# ## Opción 2: Ocultamos las demás.
# ogEcho log session "[40] Activar particion de Windows $PART y ocultar las demás."
# for (( i=1; i<=$(ogGetPartitionsNumber $d); i++ )); do
# if [ $d == $DISK -a $i == $PART ] || [ $d == $DISKDATA -a $i == $PARTDATA ]; then
# [ $(ogGetPartitionType $d $i) == "HNTFS" -o $(ogGetPartitionType $d $i) == "WIN-RESERV" ] && ogUnhidePartition $d $i
# else
# [ "$(ogGetPartitionType $d $i)" == NTFS -o "$(ogGetPartitionType $d $i)" == "WINDOWS" ] && ogHidePartition $d $i
# fi
# done
# ## Borrar marcas de arrranque de todos los Windows instalados en el disco.
# ogEcho log session "[30] Borrar marcas de arrranque de todos los Windows instalados en el disco."
# for (( i=1; i<=$(ogGetPartitionsNumber $d); i++ )); do
# [ "$(ogGetOsType $d $i)" == "Windows" ] && ogMount $d $i &>/dev/null
# done
# rm -f /mnt/*/ogboot.*
#done
;;
Linux)
## Modificar el nombre del equipo
#ogEcho log session "[30] Asignar nombre Linux \"$NAME\"."
#ETC=$(ogGetPath $DISK $PART /etc)
#[ -d "$ETC" ] && echo "$NAME" >$ETC/hostname 2>/dev/null
## Sustituir UUID o LABEL por su dispositivo en definición de sistema de archivo raíz.
#if [ -f "$ETC/fstab" ]; then
# ogEcho log session "[40] Actualizar fstab con particion raíz \"$PART\"."
# awk -v P="$PART " '{ if ($2=="/" && $1!~/^#/) {sub(/^.*$/, P, $1)}
# print }' $ETC/fstab >/tmp/fstab
# mv /tmp/fstab $ETC/fstab
#fi
## Cambiar claves usuarios, copiando fichero /etc/passwd
## En el servidor el nuevo fichero debe situarse en el directorio del grupo:
## /opt/opengnsys/images/groups/nombre_aula
#if [ -r $(ogGetGroupDir)/passwd ]; then
# ogEcho log session "[65] Cambiar claves de usuarios."
# cp $(ogGetGroupDir)/passwd $MNTDIR/etc
#fi
;;
esac

View File

@ -0,0 +1,43 @@
#!/usr/bin/python3
#/**
# bootOsCustomTemplate.py
#@brief Plantilla para script de configuración personalizada de sistema operativo restaurado.
#@param $1 nº de disco
#@param $2 nº de partición
#@warning Renombrar este fichero como "bootOsCustom.py" para personalizar el script estándar "bootOs.py".
#@note La partición a inicializar debe estar montada
#**/
import sys
import ogGlobals
from SystemLib import ogRaiseError, ogEcho
from DiskLib import ogDiskToDev
from FileSystemLib import ogMount
from NetLib import ogGetHostname
from InventoryLib import ogGetOsType
prog = sys.argv[0]
# Control de errores
if len (sys.argv) < 3:
ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'Formato: {prog} ndisco nfilesys')
sys.exit (1)
disk, par = sys.argv[1:]
device = ogDiskToDev (disk, par)
if not device: sys.exit (1)
# Nota: el script "bootOs.py" llama al script "bootOsCustom.py" después de realizar la operaciones de inicio estándar y antes de desmontar las particiones e iniciar el sistema operativo.
mntdir = ogMount (disk, par)
if not mntdir: sys.exit (1)
name = ogGetHostname()
if not name: name = 'pc'
ostype = ogGetOsType (disk, par)
if 'Windows' == ostype:
pass
elif 'Linux' == ostype:
pass

View File

@ -1,78 +0,0 @@
import sys
import subprocess
#!/usr/bin/env python3
"""
configureOsCustom
@brief Plantilla para script de configuración personalizada de sistema operativo restaurado.
@param $1 de disco
@param $2 de partición
@param $3 Repositorio: CACHE, REPO o dirección IP (opcional)
@param $4 Nombre canónico de la imagen sin extensión (opcional)
@warning Renombrar este fichero como "configureOsCustom" para sustituir al script estándar "configureOs".
@note Los parámetros disco y partición son obligatorios y opcionalmente puede recibir también el repositorio y la imagen usada para en el despliegue.
"""
def main():
if len(sys.argv) not in [3, 5]:
og_raise_error("OG_ERR_FORMAT", "Usage: configureOsCustom int_ndisc int_npart [str_repo str_imgname]")
disk = sys.argv[1]
part = sys.argv[2]
repo = sys.argv[3].upper() if len(sys.argv) > 3 else None
imgname = sys.argv[4] if len(sys.argv) > 4 else None
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Adaptar el código de ejemplo para postconfiguración personalizada.
configure_os(disk, part)
ostype = og_get_os_type(disk, part)
if ostype == "Windows":
# Postconfiguración de Windows.
pass
# Descomentar la siguiente línea para cambiar usuario de inicio.
# subprocess.run(["ogSetWinlogonUser", disk, part, " "], check=True)
# OPCIONAL: desactivar el chkdisk de windows tras la restauracion. Requiere configuracion previa en el engine.cfg
# subprocess.run(["ogLoadHiveWindows", disk, part], check=True)
# subprocess.run(["ogSetWindowsChkdisk", "OGWINCHKDISK"], check=True)
# subprocess.run(["ogUpdateHiveWindows"], check=True)
elif ostype == "Linux":
# Postconfiguración de GNU/Linux.
pass
# OPCIONAL Para UEFI: cambia el UUID de la partición (para tener dos linux en un equipo)
# subprocess.run(["ogUuidChange", disk, part], check=True)
# OPCIONAL Limpiar dispositivos reconocidos previamente
# subprocess.run(["ogCleanLinuxDevices", disk, part], check=True)
# Instala (no configura) el codigo de arranque del Grub en la partición (no lo configura, se mantiene el original de la imagen)
# subprocess.run(["ogGrubInstallPartition", disk, part], check=True)
# OPCIONAL: instala y configura el codigo de arranque del Grub en el MBR (no lo configura, se mantiene el original de la imagen)
# subprocess.run(["ogGrubInstallMbr", disk, part], check=True)
# OPCIONAL: Instala y configura el Grub en el MBR y lo autoconfigura, entradas para los sistemas operativos, además al linux restaurado le añade los parámetros indicados.
# subprocess.run(["ogGrubInstallMbr", disk, part, "TRUE", "irqpoll pci=noacpi noresume quiet splash"], check=True)
elif ostype == "MacOS":
# Postconfiguración de Mac OS X.
with open(f"/mnt/{disk}/{part}/var/root/postconfd.sh", "a") as f:
f.write("""
### NOTA: descomentar las opciones deseadas.
# Activar Journaling en HFS+ (no usar si el cliente continua en OpenGnsys).
#diskutil enableJournal disk$[$1-1]s$2
# Pedir usuario y clave en pantalla de conexión.
#defaults write /Library/Preferences/com.apple.loginwindow SHOWFULLNAME -bool yes
# No mostrar botón de cambio rápido de usuario.
#defaults write /Library/Preferences/.GlobalPreferences MultipleSessionEnabled -bool NO
# Bloquear escritorio, fondo, dock, etc del usuario "usuario".
#chflags uchange /Users/usuario/Library/Preferences/com.apple.desktop.plist
#chflags uchange /Users/usuario/Library/Preferences/com.apple.dock.plist
#chflags uchange /Users/usuario/Desktop
# Añadir usuario "usuario" a la lista de desarrolladores de Xcode.
#DevToolsSecurity --enable
#dscl . -append /Groups/_developer GroupMembership usuario
# Bajar volumen (valor entre 0 y 7).
#osascript -e 'set volume 1'
""")
# Paso 2: Incluir código genérico de postconfiguración.
if __name__ == "__main__":
main()

View File

@ -31,9 +31,8 @@ import FileLib
## [ -f $DEVICECFG ] && source $DEVICECFG
## pero luego no utiliza ninguna de las variables definidas en el archivo...
disk = sys.argv[1]
par = sys.argv[2]
imgname = sys.argv[3]
disk, par, *other = sys.argv[1:]
imgname = other[0] if len (other) > 0 else ''
# Si el sistema de archivos no esta extendido, ampliarlo al tamaño de su partición.
partsize = DiskLib.ogGetPartitionSize (disk, par)
@ -81,6 +80,14 @@ if 'Windows' == ostype:
PostConfLib.ogUninstallWindowsClient (disk, par, 'postconf.cmd')
elif 'Linux' == ostype:
# Marca para arranque.
boot_mark_file = f'{mntdir}/Part-{int(disk):02d}-{int(par):02d}'
try:
open (boot_mark_file, 'w').close()
except Exception as e:
print (f'Failed to create boot mark: {e}')
sys.exit (1)
BootLib.ogConfigureFstab (disk, par) # Configuro fstab: particion de Swap y si es UEFI además la partición EFI.
if InventoryLib.ogIsEfiActive(): # Si es UEFI instalo Grub en la partición EFI
esp = DiskLib.ogGetEsp()

View File

@ -1,81 +0,0 @@
#!/bin/bash
#/**
# configureOsCustom
#@brief Plantilla para scirpt de configuracion personalizada de sistema operativo restaurado.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP (opcional)
#@param $4 Nombre canónico de la imagen sin extensión (opcional)
#@warning Renombrar este fichero como "configureOsCustom" para sustituir al script estándar "configureOs".
#@note Los parámetros disco y partición son obligatorios y opcionalmente puede recibir también el repositorio y la imagen usada para en el despliegue.
#**/
# Control de parámetros.
[ $# -eq 2 -o $# -eq 4 ] || ogRaiseError $OG_ERR_FORMAT "$MSG_FORMAT: configureOsCustom int_ndisc int_npart [str_repo str_imgname]" || exit $?
# Parámetros obligatorios.
DISK="$1" # Nº de disco.
PART="$2" # Nº de partición.
# Parámetros opcionales.
REPO="${3^^}" # Repositorio (en mayúsculas).
IMGNAME="$4" # Nombre canónico de imagen (sin extensión).
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Adaptar el código de ejemplo para postconfiguración personalizada.
# Nota: incluye llamada al script "configureOs" para realizar previamente una configuración estándar.
# Configurarción típica.
configureOs "$1" "$2"
# Postconfiguración personalizada para cada tipo de sistema operativo.
OSTYPE="$(ogGetOsType $1 $2)"
case "$OSTYPE" in
Windows) # Postconfiguración de Windows.
# Descomentar la siguiente línea para cambiar usuario de inicio.
#ogSetWinlogonUser $1 $2 " "
# OPCIONAL: desactivar el chkdisk de windows tras la restauracion. Requiere configuracion previa en el engine.cfg
#ogLoadHiveWindows $1 $2; ogSetWindowsChkdisk $OGWINCHKDISK; ogUpdateHiveWindows
;;
Linux) # Postconfiguración de GNU/Linux.
##OPCIONAL Para UEFI: cambia el UUID de la partición (para tener dos linux en un equipo)
#ogUuidChange $DISK $PART
##OPCIONAL Limpiar dispositivos reconocidos previamente
#ogCleanLinuxDevices $1 $2
## Instala (no configura) el codigo de arranque del Grub en la partición (no lo configura, se mantiene el original de la imagen)
#ogGrubInstallPartition $1 $2
## OPCIONAL: instala y configura el codigo de arranque del Grub en el MBR (no lo configura, se mantiene el original de la imagen)
#ogGrubInstallMbr $1 $2
## OPCIONAL: Instala y configura el Grub en el MBR y lo autoconfigura, entradas para los sitemas operativos, ademas al linux restaurado le añade los parmetros indicados.
#ogGrubInstallMbr $1 $2 TRUE "irqpoll pci=noacpi noresume quiet splash"
;;
MacOS) # Postconfiguración de Mac OS X.
# Programa de inicio que será ejecutado en el arranque de Mac OS X.
# NOTA: no modificar la línea siguiente.
cat << EOT | sed -n -e '/rm -f /r /dev/stdin' -e 1x -e '2,${x;p}' -e '${x;p}' $MNTDIR/var/root/postconfd.sh
### NOTA: descomentar las opciones deseadas.
# Activar Journaling en HFS+ (no usar si el cliente continua en OpenGnsys).
#diskutil enableJournal disk$[$1-1]s$2
# Pedir usuario y clave en pantalla de conexión.
#defaults write /Library/Preferences/com.apple.loginwindow SHOWFULLNAME -bool yes
# No mostrar botón de cambio rápido de usuario.
#defaults write /Library/Preferences/.GlobalPreferences MultipleSessionEnabled -bool NO
# Bloquear escritorio, fondo, dock, etc del usuario "usuario".
#chflags uchange /Users/usuario/Library/Preferences/com.apple.desktop.plist
#chflags uchange /Users/usuario/Library/Preferences/com.apple.dock.plist
#chflags uchange /Users/usuario/Desktop
# Añadir usuario "usuario" a la lista de desarrolladores de Xcode.
#DevToolsSecurity --enable
#dscl . -append /Groups/_developer GroupMembership usuario
# Bajar volumen (valor entre 0 y 7).
#osascript -e 'set volume 1'
EOT
# NOTA: no modificar la línea anterior.
;;
esac
# Paso 2: Incluir código genérico de postconfiguración.

View File

@ -0,0 +1,38 @@
#!/usr/bin/python3
#/**
# configureOsCustom
#@brief Plantilla para scirpt de configuracion personalizada de sistema operativo restaurado.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP (opcional)
#@param $4 Nombre canónico de la imagen sin extensión (opcional)
#@warning Renombrar este fichero como "configureOsCustom" para sustituir al script estándar "configureOs".
#@note Los parámetros disco y partición son obligatorios y opcionalmente puede recibir también el repositorio y la imagen usada para en el despliegue.
#**/
import sys
import subprocess
import ogGlobals
from SystemLib import ogRaiseError, ogEcho
from InventoryLib import ogGetOsType
prog = sys.argv[0]
if len (sys.argv) not in [3, 5]:
ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{ogGlobals.lang.MSG_FORMAT} configureOsCustom int_ndisc int_npart [str_repo str_imgname]')
sys.exit (1)
disk, par, *other = sys.argv[1:]
repo = other[0].upper() if len (other) > 0 else ''
imgname = other[1] if len (other) > 1 else ''
# Nota: incluye llamada al script "configureOs" para realizar previamente una configuración estándar.
subprocess.run ([f'configureOs.py', disk, par, imgname])
ostype = ogGetOsType (disk, par)
if 'Windows' == ostype:
pass
elif 'Linux' == ostype:
pass
elif 'MacOS' == ostype:
pass

View File

@ -63,7 +63,7 @@ def main (disk, par, repo, imgname):
# Clear temporary file used as log track by httpdlog
# Limpia los ficheros temporales usados como log de seguimiento para httpdlog
# salvo si es llamado desde createImageCustom
if 'createImageCustom' != SystemLib.ogGetCaller():
if 'createImageCustom.py' != SystemLib.ogGetCaller():
with open (ogGlobals.OGLOGSESSION, 'w') as fd: fd.write ('')
with open (ogGlobals.OGLOGCOMMAND, 'w') as fd: fd.write ('')
with open (f'{ogGlobals.OGLOGCOMMAND}.tmp', 'w') as fd: fd.write ('')
@ -140,7 +140,7 @@ def main (disk, par, repo, imgname):
# Evaluar variable de engine.cfg para reducir el sistema de archivos en la creacion
if ogGlobals.IMGREDUCE:
SystemLib.ogEcho (['log', 'session'], None, f'[30] {ogGlobals.lang.MSG_HELP_ogReduceFs}')
FileSystemLib.ogReduceFs (disk, par)
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogReduceFs}', disk, par])
newsizefs = FileSystemLib.ogGetFsSize (disk, par)
timeaux = time.time() - time1
SystemLib.ogEcho (['log', 'session'], None, f' {ogGlobals.lang.MSG_SCRIPTS_TIME_PARTIAL} ( {newsizefs} KB ) : {int (timeaux/60)}m {int (timeaux%60)}s')
@ -157,7 +157,7 @@ def main (disk, par, repo, imgname):
with open (ogGlobals.OGLOGCOMMAND, 'w') as fd: fd.write ('')
time2 = time.time()
SystemLib.ogEcho (['log', 'session'], None, f'[40] {ogGlobals.lang.MSG_HELP_ogCreateImage} : ogCreateImage {disk} {par} {repo} {imgname} {ogGlobals.IMGPROG} {ogGlobals.IMGCOMP}')
if not ImageLib.ogCreateImage (disk, par, repo, f'/{imgname}', ogGlobals.IMGPROG, ogGlobals.IMGCOMP):
if not SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCreateImage}', disk, par, repo, f'/{imgname}', ogGlobals.IMGPROG, ogGlobals.IMGCOMP]):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_IMAGE, 'ogCreateImage')
sys.exit (1)
resumecreateimage = subprocess.run (['grep', 'Total Time:', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout

View File

@ -1,35 +0,0 @@
#!/bin/bash
#/**
# createImageCustom
#@brief Plantilla para scirpt de creación personalizada de imagen.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP
#@param $4 Nombre canónico de la imagen sin extensión
#@warning Renombrar este fichero como "createImageCustom" para sustituir al script estándar "createImage".
#**/
# Control de parámetros.
[ $# -eq 4 ] || ogRaiseError $OG_ERR_FORMAT "$MSG_FORMAT: createImageCustom int_ndisc int_npart str_repo str_imgname" || exit $?
# Toma de parámetros.
DISK="$1" # Nº de disco.
PART="$2" # Nº de partición.
REPO="${3^^}" # Repositorio (en mayúsculas).
IMGNAME="$4" # Nombre canónico de imagen (sin extensión).
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Añadir aquí el código para el proceso previo antes de la creación de la imagen en el equipo modelo (opcional).
# Paso 2: Sustituir, si se desea, la llamada al proceso estándar de creación de imagen por código personalizado.
createImage "$@"
# Paso 3: Añadir aquí el código para el proceso posterior tras la creación de la imagen (opcional).

View File

@ -1,27 +1,25 @@
#!/usr/bin/python3
#/**
# createImageCustom
#@brief Plantilla para scirpt de creación personalizada de imagen.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP
#@param $4 Nombre canónico de la imagen sin extensión
#@warning Renombrar este fichero como "createImageCustom" para sustituir al script estándar "createImage".
#**/
import sys
import os
import subprocess
#!/usr/bin/env python3
import ogGlobals
from SystemLib import ogRaiseError
def main():
# Control de parámetros.
if len(sys.argv) != 5:
ogRaiseError(os.getenv('OG_ERR_FORMAT', 1), "createImageCustom int_ndisc int_npart str_repo str_imgname")
# Toma de parámetros.
DISK = sys.argv[1] # Nº de disco.
PART = sys.argv[2] # Nº de partición.
REPO = sys.argv[3].upper() # Repositorio (en mayúsculas).
IMGNAME = sys.argv[4] # Nombre canónico de imagen (sin extensión).
# Control de parámetros.
if len (sys.argv) != 5:
ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'{ogGlobals.lang.MSG_FORMAT} createImageCustom int_ndisc int_npart str_repo str_imgname')
sys.exit (1)
disk, par, repo, imgname = sys.argv[1:]
repo = repo.upper()
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Añadir aquí el código para el proceso previo antes de la creación de la imagen en el equipo modelo (opcional).
# Paso 2: Sustituir, si se desea, la llamada al proceso estándar de creación de imagen por código personalizado.
createImage(DISK, PART, REPO, IMGNAME)
# Paso 3: Añadir aquí el código para el proceso posterior tras la creación de la imagen (opcional).
if __name__ == "__main__":
main()
subprocess.run (['createImage.py', disk, par, repo, imgname])

View File

@ -138,22 +138,19 @@ def main (repo, imgname, disk, par, proto='UNICAST', protoopt=''):
params = [repo, imgname, disk, par, proto, protoopt]
# Si existe, ejecuta script personalizado "restoreImageCustom"; si no, llama al genérico "restoreImage".
if shutil.which ('restoreImageCustom'):
if shutil.which ('restoreImageCustom.py'):
SystemLib.ogEcho (['log', 'session'], None, f'[55] {ogGlobals.lang.MSG_HELP_ogRestoreImage}: restoreImageCustom {params}')
retval = subprocess.run (['restoreImageCustom'] + params).returncode
retval = subprocess.run (['restoreImageCustom.py'] + params).returncode
else:
SystemLib.ogEcho (['log', 'session'], None, f'[55] {ogGlobals.lang.MSG_HELP_ogRestoreImage}: restoreImage {params}')
retval = subprocess.run (['restoreImage.py'] + params).returncode
## turn shell's success into python success (without ending up with True or False)
if retval: retval = 0
else: retval = 1
# Mostrar resultados.
resumerestoreimage = subprocess.run (['grep', '--max-count', '1', 'Total Time:', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout
SystemLib.ogEcho (['log', 'session'], None, f' [ ] {resumerestoreimage} ')
# Si la transferencia ha dado error me salgo.
if retval:
if retval: ## subprocess.run failed
SystemLib.ogEcho (['log', 'session'], None, f'[60] {ogGlobals.lang.MSG_HELP_ogRestoreImage}: error: returncode not 0 but "{retval}"')
SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_IMAGE, f'{repo} {imgname}')
if SystemLib.ogGetCaller() != 'EjecutarScript':
SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_INTERFACE_END} {ogGlobals.OG_ERR_IMAGE}')
@ -163,9 +160,9 @@ def main (repo, imgname, disk, par, proto='UNICAST', protoopt=''):
SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TIME_PARTIAL} : {int (time3/60)}m {int (time3%60)}s')
# Si existe, ejecuta script personalizado de postconfiguración "configureOsCustom"; si no, llama al genérico "configureOs".
if shutil.which ('configureOsCustom'):
if shutil.which ('configureOsCustom.py'):
SystemLib.ogEcho (['log', 'session'], None, '[90] configureOsCustom')
subprocess.run (['configureOsCustom', disk, par, repo, imgname])
subprocess.run (['configureOsCustom.py', disk, par, repo, imgname])
else:
SystemLib.ogEcho (['log', 'session'], None, f'[90] {ogGlobals.lang.MSG_SCRIPTS_OS_CONFIGURE}')
subprocess.run (['configureOs.py', disk, par, imgname])

View File

@ -5,7 +5,6 @@
import sys
import time
import subprocess
import ogGlobals
import SystemLib

12
ogclient/scripts/restoreImage.py 100644 → 100755
View File

@ -59,9 +59,9 @@ repo = repo.upper()
# Si MCASTWAIT menos que tiempo de espera del servidor lo aumento
MCASTWAIT = ogGlobals.MCASTWAIT
if ':' in protoopt:
port, wait = protoopt.split (':')
port, method, mcastip, speed, nclients, wait = protoopt.split (':')
else:
port, wait = ('', '')
port, method, mcastip, speed, nclients, wait = ('', '', '', '', '', '')
if proto.startswith ('MULTICAST') and re.match (r'^-?\d+$', wait):
if int (MCASTWAIT or 0) < int (wait):
MCASTWAIT = int (wait) + 5
@ -76,7 +76,7 @@ if StringLib.ogCheckIpAddress (repo) or 'REPO' == repo:
if not NetLib.ogChangeRepo (repo):
SystemLib.ogRaiseError ([], ogGlobals.OG_ERR_NOTFOUND, repo)
sys.exit (1)
REPO = 'REPO'
repo = 'REPO'
# Comprobar que existe la imagen del origen.
imgfile = FileLib.ogGetPath (repo, f'{imgname}.{imgtype}')
@ -90,7 +90,7 @@ if not imgfile or not imgdir:
retval = 0
if proto in ['UNICAST', 'UNICAST-DIRECT']:
SystemLib.ogEcho (['log', 'session'], None, f'[40] ogRestoreImage {repo} {imgname} {disk} {par} UNICAST')
retval = SystemLib.ogExecAndLog ('command', ImageLib.ogRestoreImage, repo, imgname, disk, par)
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogRestoreImage', repo, imgname, disk, par])
elif proto in ['MULTICAST', 'MULTICAST-DIRECT']:
tool = ImageLib.ogGetImageProgram ('REPO', imgname)
if not tool:
@ -103,9 +103,7 @@ elif proto in ['MULTICAST', 'MULTICAST-DIRECT']:
sys.exit (1)
SystemLib.ogEcho (['log', 'session'], None, f'[40] ogMcastReceiverPartition {disk} {par} {port} {tool} {compress}')
if not ProtocolLib.ogMcastRequest (f'{imgname}.img', protoopt):
sys.exit (1)
retval = SystemLib.ogExecAndLog ('command', ProtocolLib.ogMcastReceiverPartition, disk, par, port, tool, compress)
retval = SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogMcastReceiverPartition', disk, par, port, tool, compress])
else:
SystemLib.ogRaiseError ('session', ogGlobals.OG_ERR_FORMAT, f'{ogGlobals.lang.MSG_FORMAT}: {prog} REPO|CACHE imagen ndisco nparticion [ UNICAST|MULTICAST opciones protocolo]')
sys.exit (1)

View File

@ -1,37 +0,0 @@
#!/bin/bash
#/**
# restoreImageCustom
#@brief Plantilla para scirpt de rastauración personalizada de imagen.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP
#@param $4 Nombre canónico de la imagen sin extensión
#@warning Renombrar este fichero como "restoreImageCustom" para sustituir al script estándar "restoreImage".
#**/
# Control de parámetros.
[ $# -ge 4 -a $# -le 6 ] || ogRaiseError $OG_ERR_FORMAT "$MSG_FORMAT: restoreImageCustom str_repo str_imagen int_ndisco int_npart [ str_proto [\"str_opciones\"] ]" || exit $?
# Toma de parámetros.
REPO="${1^^}" # Repositorio (en mayúsculas).
IMGNAME="$2" # Nombre canónico de imagen (sin extensión).
DISK="$3" # Nº de disco.
PART="$4" # Nº de partición.
PROTO="${5^^}" # Protocolo de comunicaciones (por defecto, UNICAST).
PROTO=${PROTO:-"UNICAST"}
PROTOOPT="$6" # Opciones del protocolo separadas por ":" (opcional).
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Añadir aquí el código para el proceso previo antes de la restauración de la imagen en los equipos (opcional).
# Paso 2: Sustituir, si se desea, la llamada al proceso estándar de restauración de imagen por código personalizado.
restoreImage "$@"
# Aviso: editar la plantilla "configureOsCustom" para añadir el código personalizado para el proceso de postconfiguración de los clientes (no incluir aquí dicho código).

View File

@ -1,35 +1,28 @@
import sys
import os
import SystemLib
#!/usr/bin/python3
#/**
# restoreImageCustom
#@brief Plantilla para scirpt de rastauración personalizada de imagen.
#@param $1 nº de disco
#@param $2 nº de partición
#@param $3 Repositorio: CACHE, REPO o dirección IP
#@param $4 Nombre canónico de la imagen sin extensión
#@warning Renombrar este fichero como "restoreImageCustom" para sustituir al script estándar "restoreImage".
#**/
#!/usr/bin/env python3
"""
restoreImageCustom
@brief Plantilla para script de restauración personalizada de imagen.
@param $1 de disco
@param $2 de partición
@param $3 Repositorio: CACHE, REPO o dirección IP
@param $4 Nombre canónico de la imagen sin extensión
@warning Renombrar este fichero como "restoreImageCustom" para sustituir al script estándar "restoreImage".
"""
import sys
import subprocess
import ogGlobals
from SystemLib import ogRaiseError
# Control de parámetros.
if not (4 <= len(sys.argv) <= 6):
SystemLib.ogRaiseError(os.getenv('OG_ERR_FORMAT'), "restoreImageCustom str_repo str_imagen int_ndisco int_npart [ str_proto [\"str_opciones\"] ]")
if len (sys.argv) < 5 or len (sys.argv) > 7):
ogRaiseError ([], ogGlobals.OG_ERR_FORMAT, f'restoreImageCustom str_repo str_imagen int_ndisco int_npart [ str_proto ["str_opciones"] ]')
sys.exit (1)
# Toma de parámetros.
REPO = sys.argv[1].upper() # Repositorio (en mayúsculas).
IMGNAME = sys.argv[2] # Nombre canónico de imagen (sin extensión).
DISK = sys.argv[3] # Nº de disco.
PART = sys.argv[4] # Nº de partición.
PROTO = sys.argv[5].upper() if len(sys.argv) > 5 else "UNICAST" # Protocolo de comunicaciones (por defecto, UNICAST).
PROTOOPT = sys.argv[6] if len(sys.argv) > 6 else "" # Opciones del protocolo separadas por ":" (opcional).
repo, imgname, disk, par, *other = sys.argv[1:]
repo = repo.upper()
proto = other[0].upper() if len (other) > 0 else 'UNICAST'
protoopt = other[1] if len (other) > 1 else ''
# Paso 0: Añadir código para realizar control de errores de los parámetros de entrada (recomendado).
# Paso 1: Añadir aquí el código para el proceso previo antes de la restauración de la imagen en los equipos (opcional).
# Paso 2: Sustituir, si se desea, la llamada al proceso estándar de restauración de imagen por código personalizado.
restoreImage(*sys.argv[1:])
# Aviso: editar la plantilla "configureOsCustom" para añadir el código personalizado para el proceso de postconfiguración de los clientes (no incluir aquí dicho código).
subprocess.run (['restoreImage.py', repo, imgname, disk, par, proto, protoopt])

14
ogclient/scripts/updateCache.py 100644 → 100755
View File

@ -167,13 +167,13 @@ if 'TORRENT' == protocolo:
SystemLib.ogEcho (['log', 'session'], None, f'ogCopyFile {repositorio} {path}.torrent absolute {ogGlobals.OGCAC}/{ogGlobals.OGIMG}')
mac_digits = NetLib.ogGetMacAddress().split (':')
timewait = int ('0x' + mac_digits[4] + mac_digits[5], 16) * 120 / 65535
if not SystemLib.ogExecAndLog ('command', FileLib.ogCopyFile, {'container':repositorio, 'file':f'{path}.torrent'}, {'file':imgdir}):
if not SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCopyFile', repositorio, f'{path}.torrent', imgdir]):
sys.exit (1)
p2pwait = random.randint (1, 121)
SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TASK_SLEEP} : {p2pwait} seconds')
time.sleep (p2pwait)
SystemLib.ogEcho (['log', 'session'], None, f' [ ] {ogGlobals.lang.MSG_SCRIPTS_TASK_START}: ogTorrentStart CACHE {path}.torrent {optprotocolo}')
SystemLib.ogExecAndLog ('command', ProtocolLib.ogTorrentStart, 'CACHE', f'{path}.torrent', optprotocolo)
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogTorrentStart', 'CACHE', f'{path}.torrent', optprotocolo])
resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '--before-context', '1', 'Download', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout
resumeupdatecachebf = subprocess.run (['grep', '--max-count', '1', 'Download', ogGlobals.OGLOGCOMMAND], capture_output=True, text=True).stdout
if 'Download complete.' == resumeupdatecachebf:
@ -182,19 +182,15 @@ elif 'MULTICAST' == protocolo:
SystemLib.ogEcho (['log', 'session'], None, f'{ogGlobals.lang.MSG_SCRIPTS_UPDATECACHE_CHECKMCASTSESSION}: {repoip}:{port}')
time.sleep (random.randint (1, 31))
SystemLib.ogEcho (['log', 'session'], None, f'ogMcastRequest {path} {optprotocolo}')
if not SystemLib.ogExecAndLog ('command', ProtocolLib.ogMcastRequest, path, optprotocolo):
sys.exit (1)
SystemLib.ogEcho (['log', 'session'], None, f'ogMcastReceiverFile {port} CACHE {path}')
if not SystemLib.ogExecAndLog ('command', ProtocolLib.ogMcastReceiverFile, sess=port, container='CACHE', file=path):
if not SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogMcastReceiverFile', port, 'CACHE', path]):
sys.exit (1)
resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '--before-context', '1', 'Transfer complete', f'{ogGlobals.OGLOGCOMMAND}.tmp'], capture_output=True, text=True).stdout
elif 'UNICAST' == protocolo:
print (f'ogExecAndLog ("command", FileLib.ogCopyFile, {{"container":{repositorio}, "file":{path}}}, {{"file":{imgdir}}})')
SystemLib.ogExecAndLog ('command', FileLib.ogCopyFile, {'container':repositorio, 'file':path}, {'file':imgdir})
print (f'ogExecAndLog ("command", {ogGlobals.OGPYFUNCS}/ogCopyFile {repositorio} {path} {imgdir}')
SystemLib.ogExecAndLog ('command', [f'{ogGlobals.OGPYFUNCS}/ogCopyFile', repositorio, path, imgdir])
time.sleep (5)
resumeupdatecache = subprocess.run (['grep', '--max-count', '1', '100%', f'{ogGlobals.OGLOGCOMMAND}.tmp'], capture_output=True, text=True).stdout