mirror of
https://github.com/xcat2/confluent.git
synced 2026-09-29 16:50:57 +00:00
Compare commits
582 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 700afc6606 | |||
| e7cb3f9a0c | |||
| 0254963432 | |||
| 110fb27b2a | |||
| 116682082a | |||
| 2c1ca170e5 | |||
| e648c9c065 | |||
| c1576e9787 | |||
| 6ee9ccbc27 | |||
| 2a9d4e8079 | |||
| 335d06ea4c | |||
| 17b8000c0f | |||
| 5f170585c5 | |||
| 356de251ee | |||
| 405bd84ce2 | |||
| e9a14bd180 | |||
| c3fedf7309 | |||
| da8baa2ccb | |||
| 4480d0418e | |||
| 987ac22b4e | |||
| 6471599bb2 | |||
| 05983201ee | |||
| b20517bd82 | |||
| 4e8e44605a | |||
| d75867050c | |||
| b4374817f5 | |||
| 968400d72b | |||
| 88436ff129 | |||
| 213d440052 | |||
| eabf2073c1 | |||
| 906855ecf7 | |||
| 59e9ef2215 | |||
| 021591017c | |||
| ba0d600bf7 | |||
| eda645b792 | |||
| 8ce8f18f56 | |||
| 0af9db5eb7 | |||
| 22d5da3ae9 | |||
| 6246d9e0a4 | |||
| 726cb198c1 | |||
| b34f308c8a | |||
| 0800290c8e | |||
| 51bc7dc88f | |||
| 76952e774b | |||
| 8bff5c272b | |||
| c587cd34ac | |||
| f8b27f1f8d | |||
| 60453973cb | |||
| c48b023236 | |||
| c0bd9f8bfb | |||
| c4379e3fd2 | |||
| b0be352134 | |||
| 7d4ce55127 | |||
| 9506817a00 | |||
| 0a79307cc5 | |||
| 442902ecd8 | |||
| 5540896ab1 | |||
| e696566b42 | |||
| eec7236110 | |||
| ebd41d3e53 | |||
| c5c5b36536 | |||
| 26caffab76 | |||
| 9093a6e80a | |||
| 66f0e8225e | |||
| 5f63875cae | |||
| 92f8acab7a | |||
| 540d0e1795 | |||
| b9cdf0d941 | |||
| dcb9f60ade | |||
| d12ac8a1ba | |||
| 14ba48da1f | |||
| ceefb936c2 | |||
| 9caf8056ec | |||
| 317a1c572b | |||
| 2b39b9b5a6 | |||
| 5dee338d50 | |||
| c459990457 | |||
| 485b5e0dce | |||
| 188467ccf0 | |||
| dcda6a1080 | |||
| 0c575456e3 | |||
| 2211755bf7 | |||
| bf5727cab1 | |||
| a05bfcec80 | |||
| 5ebe127db2 | |||
| b67140248e | |||
| a5adcbd496 | |||
| cab2310f35 | |||
| 4d5ec98525 | |||
| 008bf33be3 | |||
| b52568dc10 | |||
| 24288f988a | |||
| 408d0a8673 | |||
| 579e05972f | |||
| f85693b7e3 | |||
| 7dcad26002 | |||
| 393c3ac38e | |||
| b73c561ca9 | |||
| 1ba2386b82 | |||
| 8a48909ae3 | |||
| 0b01ca59d2 | |||
| 69d14564b0 | |||
| ccd94fb0cf | |||
| bd91c58768 | |||
| 72c22939ad | |||
| 87a7e65b42 | |||
| 1beed070fd | |||
| 5addc7519d | |||
| 7a68d1444b | |||
| b5ccf9446a | |||
| 807c68890d | |||
| ee2f80b5d2 | |||
| a017c5460f | |||
| 51c09d844f | |||
| b7c830b041 | |||
| 853318feba | |||
| 2c4f8dfceb | |||
| 6fa863e8f9 | |||
| d90e87e153 | |||
| b80647a36e | |||
| 2c74cb18b0 | |||
| 8fe1cea2ed | |||
| 471f3bd1cf | |||
| f10bbdc33d | |||
| d6df9db229 | |||
| d5cab22f41 | |||
| 72d52c56b7 | |||
| 4f2d4a7709 | |||
| dcdd453112 | |||
| 5a22168657 | |||
| e18ca3dd94 | |||
| 3f53c55a66 | |||
| 3e02e8bf85 | |||
| cda0f439d3 | |||
| e4bea785c3 | |||
| 404041e226 | |||
| 9180bab761 | |||
| 6d2918ed45 | |||
| dd2dca5837 | |||
| 16b3bc44a0 | |||
| e1e34f9f31 | |||
| e4a4bdf317 | |||
| a4f9fdec3d | |||
| c3b295a4a2 | |||
| 5539a6a1e8 | |||
| bdd982e2ed | |||
| 1db9282058 | |||
| f7dcabc1ab | |||
| efe936a93d | |||
| 4619c466e5 | |||
| 65797abfbb | |||
| 2929e18413 | |||
| cae75dbccf | |||
| de201c9a3b | |||
| f619b5933c | |||
| cb1d5ebd13 | |||
| bbb4f5a0ec | |||
| 14192a6c21 | |||
| 530be7a508 | |||
| 00eb72a627 | |||
| fa40793dfa | |||
| 3f8d825540 | |||
| 924102fa32 | |||
| f3747025ff | |||
| 2ac139934e | |||
| b3b68774ab | |||
| f27e6dfdda | |||
| 45eba14b10 | |||
| 598ec4a294 | |||
| 501ab64e18 | |||
| 3437b8b03c | |||
| 2936c7e8fd | |||
| 68251ffbb8 | |||
| 051b8259fd | |||
| d691bcd306 | |||
| 4f85ba2bff | |||
| 36911c0d2e | |||
| 5232b7c9c4 | |||
| 59aabb0e69 | |||
| 931c7f25d1 | |||
| 149e41c33c | |||
| 21327af140 | |||
| c21ae64f06 | |||
| eb2301b22e | |||
| 06d0e05dbb | |||
| bfac51ba12 | |||
| 49a523ca5e | |||
| 6798e4e848 | |||
| 690c871d29 | |||
| f964fd8ce1 | |||
| 198b26245b | |||
| 4fb7924015 | |||
| e4a9216683 | |||
| dc2df09c4e | |||
| 16667ed41c | |||
| b37c034d6f | |||
| 32038baa75 | |||
| dcdc8e4d5a | |||
| f97fd3105f | |||
| 4e8cc3d801 | |||
| 86a68bf7f9 | |||
| 84988031a2 | |||
| 211b8ab7e8 | |||
| 23e8642950 | |||
| 76f7c12ca5 | |||
| e2aaa2afb4 | |||
| 890793068c | |||
| 09700626b5 | |||
| 709ace4c92 | |||
| 2c1ddabf32 | |||
| 24bc1210d0 | |||
| 276e01434d | |||
| 58fd760698 | |||
| c76a0cfa16 | |||
| bc03da47af | |||
| 2575e32209 | |||
| 989ae614c9 | |||
| bd39171611 | |||
| 814209385c | |||
| 3b3475e073 | |||
| ed050b37e1 | |||
| 331d10140a | |||
| 2bd2946e9f | |||
| a3f7fc12b5 | |||
| 5fb4f2b36c | |||
| 3ddeb4bcd0 | |||
| 1722ad941b | |||
| d18c0a576d | |||
| acda061710 | |||
| 8d1d19d9a8 | |||
| fdd9c0953c | |||
| 137e35217b | |||
| fe3d9da5aa | |||
| d76c576b4e | |||
| 017f3fb372 | |||
| f58b943cfe | |||
| 86628929de | |||
| 46518f890b | |||
| b0a0bad635 | |||
| 7e86a72872 | |||
| 1cfeed3f9d | |||
| 2567503662 | |||
| 061e12beeb | |||
| 6b56181a52 | |||
| 323be19f21 | |||
| 0983cacb20 | |||
| c18ce50138 | |||
| b3c878462f | |||
| 8e8e17a34e | |||
| a0684520d8 | |||
| e78b4e9f17 | |||
| 374aa49016 | |||
| ea537b1a1f | |||
| bc7dc50388 | |||
| 2da5bebf46 | |||
| 0fe136d4ee | |||
| b573ffa897 | |||
| 0986853e6e | |||
| 0b95daa30d | |||
| 96b5d3aa91 | |||
| 6cc0fd20a0 | |||
| d33365195b | |||
| 85c648925f | |||
| 3429173c27 | |||
| 44836cabbe | |||
| 92e657b987 | |||
| 16209bc3d6 | |||
| f6c44922f8 | |||
| 41aa9e1cd2 | |||
| 0c96882fda | |||
| 00681489c7 | |||
| 8c2336b8fa | |||
| a1bb603570 | |||
| 96cbfa5568 | |||
| f0e5572b05 | |||
| 895216d94f | |||
| 1c7c897267 | |||
| 20a26e6fdb | |||
| 433f67730c | |||
| fcd73399fa | |||
| b7d85b2166 | |||
| 22de1153c2 | |||
| e0223706b0 | |||
| 451ff6b5a3 | |||
| b3c49c532c | |||
| 8fb206b1f7 | |||
| 1bf7c6970f | |||
| a86d962984 | |||
| 6ade0952c7 | |||
| 517101f596 | |||
| 1bfc949466 | |||
| e97214ca50 | |||
| 9ee29aabe1 | |||
| 57ff9808c4 | |||
| 0f67f5c382 | |||
| b789252c9c | |||
| a413f321fe | |||
| d38b06224c | |||
| f2bd796c2a | |||
| bf31c4872f | |||
| 9ea9188fdf | |||
| 597393842a | |||
| b9fc9b3c19 | |||
| 49b8e12a01 | |||
| f20fb70336 | |||
| 934f8f0f20 | |||
| 945b8f2b4a | |||
| 82921fb53d | |||
| 59a0b00208 | |||
| 34f2f6e359 | |||
| 7fe47baab3 | |||
| 3c1453c16b | |||
| 4529924cce | |||
| 97ddd59dbd | |||
| b7b2522f6b | |||
| bd0e187525 | |||
| 634e5a8944 | |||
| 455b637c48 | |||
| 67e3530d16 | |||
| e257d526c3 | |||
| a066f061c7 | |||
| 29b4045817 | |||
| f798239f90 | |||
| f955086cc3 | |||
| cd20a23626 | |||
| 3c26beda1d | |||
| 54be209f4e | |||
| 114324f513 | |||
| d2de4ffa14 | |||
| d4483bb59f | |||
| 90bec92d1f | |||
| 4b3541e21d | |||
| 737e7a440f | |||
| 24874bb4be | |||
| e2d0e49fc7 | |||
| da5a34c2e4 | |||
| 3629cb8ee7 | |||
| 8233e0a5bd | |||
| eae7b3bd80 | |||
| 868367e052 | |||
| 6289cfaac4 | |||
| f6d4fef5e6 | |||
| b1b7ec4d50 | |||
| c0cd6de4f7 | |||
| 4437e81e04 | |||
| 6a12af1242 | |||
| 9879a83a10 | |||
| cce6b824de | |||
| ce1cb952e8 | |||
| c6812274e4 | |||
| 7cd7068dd7 | |||
| 48f0330568 | |||
| 66e1d17d28 | |||
| 7480494432 | |||
| 49c00bfbb7 | |||
| 201985dd0e | |||
| 1aee19997a | |||
| 3bc366bef4 | |||
| 4c83a1a04e | |||
| cfae28a869 | |||
| 44e6a72847 | |||
| 006fdc8280 | |||
| 895b5264f6 | |||
| 0b577af1ca | |||
| ff0b1bba7f | |||
| 0badd9e5b4 | |||
| c02064f0a5 | |||
| c1b82d8163 | |||
| 0d5fa7a98a | |||
| 968efe719a | |||
| 7a63ca8759 | |||
| a24866c2df | |||
| c666b11138 | |||
| 22f6198f60 | |||
| c99d01dffc | |||
| 8d0028a1de | |||
| bb9c2297c9 | |||
| 91fa5bd1eb | |||
| ac9609c40d | |||
| 0c4cb49c20 | |||
| 4be4100014 | |||
| 9f7c8c69f2 | |||
| c35f7d99f7 | |||
| 445950d02a | |||
| cf72cf2d8c | |||
| 0652a7321b | |||
| 4c8ba92856 | |||
| 09582d7597 | |||
| 8a9e9aa7b3 | |||
| b766e7b0ee | |||
| 92699e47f2 | |||
| 2aa9910d83 | |||
| 18b6398c64 | |||
| 47b68e4258 | |||
| 79b6d099ab | |||
| 604ebcde3b | |||
| b4b733a573 | |||
| 3bf083deb3 | |||
| 9d770632ce | |||
| 79afd174c9 | |||
| 13a0bf4fbe | |||
| f1e1d9804a | |||
| 546296ce71 | |||
| 954b2dd15c | |||
| a7b11d1e15 | |||
| 3660cf18cc | |||
| 078afaf7d7 | |||
| 3ab1eb7f01 | |||
| fbfdc9322b | |||
| ef68656bde | |||
| 0e04b853f6 | |||
| 63256e37b6 | |||
| a1b81e978b | |||
| 06c53e9d89 | |||
| ab0168b2ec | |||
| 473bb39c54 | |||
| a48ecd8c78 | |||
| 30398fc434 | |||
| 0ed7e4eac3 | |||
| 0d2999c7a8 | |||
| 75010ac6f0 | |||
| a748cc3032 | |||
| 28bb143880 | |||
| 4b6899d4af | |||
| a175fd7345 | |||
| 12bd473c0d | |||
| a967c224fe | |||
| 72a5f37232 | |||
| 5c081a8e2c | |||
| c0b69f64b8 | |||
| f7fe38f498 | |||
| 5ae949b4eb | |||
| cec6918c1a | |||
| 3df7a36c48 | |||
| 559e96f7ff | |||
| 6f568919e1 | |||
| c441739f68 | |||
| a43361bb98 | |||
| 620263db3e | |||
| dd096104cc | |||
| 191ae762ab | |||
| f866b7379c | |||
| aab6160d49 | |||
| e1dffe7c3a | |||
| 97ca6dc48e | |||
| 1d59e1da8c | |||
| 45c13a3d46 | |||
| 7e6b4fa4d0 | |||
| 186e89cd87 | |||
| a04eea6927 | |||
| f46939b7ec | |||
| 73d6511d9e | |||
| 17a8ab3211 | |||
| 0fd4c3b2f7 | |||
| 065ee48325 | |||
| 4a35cc25f0 | |||
| ceced11ae8 | |||
| 62084b3605 | |||
| a84b88e269 | |||
| fc626d36ba | |||
| 606a308046 | |||
| bed0f76dba | |||
| 8c4d04a7cd | |||
| bfbde0f7f3 | |||
| ba96aea2a6 | |||
| d9f1d6c033 | |||
| 1dac61adca | |||
| e008932389 | |||
| b81e5fb3ce | |||
| e2a08e7e73 | |||
| eb48728bc1 | |||
| c6255fa13b | |||
| 2a37d64dc9 | |||
| 8101672c3a | |||
| 453c344f7f | |||
| 9eceda0636 | |||
| f28b91499e | |||
| 8cab591a8b | |||
| 6ce6740b77 | |||
| 8a4a219a14 | |||
| a39d45d03c | |||
| bc85d93cf4 | |||
| 1e963106fe | |||
| a9f0e345db | |||
| 5353b479d9 | |||
| dbc6747c38 | |||
| 0edd1efe0d | |||
| 8e87f5b9e5 | |||
| 0633b2ca67 | |||
| c1953bdad3 | |||
| 578ba06aa3 | |||
| 0975881d3b | |||
| 8fc3b7c9c0 | |||
| 6ea6ebd80e | |||
| 744f8899f7 | |||
| 5c288a27dd | |||
| 74f18d5571 | |||
| d9be6ae2e9 | |||
| 59789bae7d | |||
| 521be5d44d | |||
| 6fb82bbbad | |||
| 90e546bcac | |||
| 147d59cba7 | |||
| 6a6fd3184e | |||
| c532cf9ecf | |||
| 8909fb16d6 | |||
| 44d6bde3ff | |||
| 56fa13279e | |||
| 5008128d57 | |||
| ed320f4a17 | |||
| de8292f6dd | |||
| 829a5b08c1 | |||
| 8e071a2568 | |||
| 7d84d0a021 | |||
| c5f75bfa15 | |||
| 99d01d707f | |||
| 3e1690c860 | |||
| a3f5630535 | |||
| 8d6744947e | |||
| 21b3c89974 | |||
| 9718881c7b | |||
| fcbbdc8a8d | |||
| f03bb36dbe | |||
| 97a950b145 | |||
| a0e445d1b1 | |||
| 65629548c9 | |||
| 6cfbf4533c | |||
| 5794dd7f8c | |||
| 48fa74e7a9 | |||
| 59d5110b8f | |||
| 051d79727b | |||
| 4cdbc7807b | |||
| feecee82db | |||
| 395c0d4697 | |||
| a963a8ca35 | |||
| aa059c6a4d | |||
| 2e03b662ea | |||
| 55a0aab548 | |||
| aaf5aebff7 | |||
| c1abeaff04 | |||
| 37d4543d24 | |||
| d95464df6f | |||
| 3f6e6d4c39 | |||
| c3176ab86a | |||
| 4dab5fc527 | |||
| d13e286609 | |||
| 8897842fc4 | |||
| a251a538b0 | |||
| 480a747dcf | |||
| af025f7304 | |||
| 21edd82177 | |||
| 8641885f86 | |||
| 64cc2416d1 | |||
| 2787e1d862 | |||
| a7c93627e2 | |||
| 514a121c15 | |||
| 6e5cfe69a8 | |||
| 00ce48b046 | |||
| 44929e7975 | |||
| da82fef0cb | |||
| efcac0b181 | |||
| 626f1c16e2 | |||
| 43480c2e3b | |||
| b91693a973 | |||
| 46e2f53018 | |||
| da8b4d00d8 | |||
| cf51928b3d | |||
| b7b7fd82eb | |||
| 3789e43f35 | |||
| 151ba2e567 | |||
| a325dcb423 | |||
| c8d0009dac | |||
| 79f5dce6dc | |||
| bc87077397 | |||
| 54f36e259f | |||
| acf67a6c81 | |||
| a77b65737e | |||
| 19c2963cf9 | |||
| a0ea8eeae3 | |||
| 6ad1ce4df5 | |||
| c53264872a | |||
| d9f2c0b266 |
+4
-1
@@ -1 +1,4 @@
|
||||
.idea
|
||||
*.pyc
|
||||
.*.
|
||||
confluent_client/man/man*
|
||||
.*.sw*
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/python
|
||||
import os
|
||||
import sys
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
try:
|
||||
sys.path.remove(path)
|
||||
except Exception:
|
||||
pass
|
||||
path = os.path.realpath(os.path.join(path, '..', 'confluent_server'))
|
||||
sys.path.append(path)
|
||||
|
||||
import confluent.config.attributes as attr
|
||||
import shutil
|
||||
|
||||
shutil.copyfile('doc/man/nodeattrib.ronn.tmpl', 'doc/man/nodeattrib.ronn')
|
||||
shutil.copyfile('doc/man/nodegroupattrib.ronn.tmpl', 'doc/man/nodegroupattrib.ronn')
|
||||
with open('doc/man/nodeattrib.ronn', 'a') as outf:
|
||||
for field in sorted(attr.node):
|
||||
outf.write('\n* `{0}`:\n {1}\n'.format(field, attr.node[field]['description']))
|
||||
with open('doc/man/nodegroupattrib.ronn', 'a') as outf:
|
||||
for field in sorted(attr.node):
|
||||
outf.write('\n* `{0}`:\n {1}\n'.format(field, attr.node[field]['description']))
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -43,6 +43,8 @@ argparser.add_option('-d', '--diff', action='store_true',
|
||||
'output group and others')
|
||||
argparser.add_option('-w', '--watch', action='store_true',
|
||||
help='Show intermediate results while running')
|
||||
argparser.add_option('-g', '--groupcount', action='store_true',
|
||||
help='Show count of output groups rather than the actual output')
|
||||
argparser.add_option('-s', '--skipcommon', action='store_true',
|
||||
help='Do not print most common result, only non modal '
|
||||
'groups, useful when combined with -d')
|
||||
@@ -69,6 +71,9 @@ def print_current():
|
||||
if options.diff:
|
||||
grouped.print_deviants(skipmodal=options.skipcommon, count=options.count,
|
||||
reverse=options.reverse, basenode=options.base)
|
||||
elif options.groupcount:
|
||||
grouped.generate_byoutput()
|
||||
print(len(grouped.byoutput))
|
||||
else:
|
||||
grouped.print_all(skipmodal=options.skipcommon,
|
||||
count=options.count,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2014 IBM Corporation
|
||||
@@ -76,6 +76,11 @@ import confluent.termhandler as termhandler
|
||||
import confluent.tlvdata as tlvdata
|
||||
import confluent.client as client
|
||||
|
||||
try:
|
||||
unicode
|
||||
except NameError:
|
||||
unicode = str
|
||||
|
||||
conserversequence = '\x05c' # ctrl-e, c
|
||||
clearpowermessage = False
|
||||
|
||||
@@ -89,6 +94,10 @@ except NameError:
|
||||
netserver = None
|
||||
laststate = {}
|
||||
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
class BailOut(Exception):
|
||||
def __init__(self, errorcode=0):
|
||||
@@ -195,9 +204,9 @@ def prompt():
|
||||
if os.environ.get('TERM', '') not in ('linux'):
|
||||
sys.stdout.write('\x1b]0;confetty: %s\x07' % target)
|
||||
try:
|
||||
return raw_input(target + ' -> ')
|
||||
return input(target + ' -> ')
|
||||
except KeyboardInterrupt:
|
||||
print ""
|
||||
print("")
|
||||
return ""
|
||||
except EOFError: # ctrl-d
|
||||
print("exit")
|
||||
@@ -295,8 +304,11 @@ currchildren = None
|
||||
|
||||
|
||||
def print_result(res):
|
||||
global exitcode
|
||||
if 'errorcode' in res or 'error' in res:
|
||||
print res['error']
|
||||
print(res['error'])
|
||||
if 'errorcode' in res:
|
||||
exitcode |= res['errorcode']
|
||||
return
|
||||
if 'databynode' in res:
|
||||
print_result(res['databynode'])
|
||||
@@ -309,9 +321,9 @@ def print_result(res):
|
||||
attrstr = '%s=%s' % (key, recurse_format(res[key]))
|
||||
elif not isinstance(res[key], dict):
|
||||
try:
|
||||
print '{0}: {1}'.format(key, res[key])
|
||||
print('{0}: {1}'.format(key, res[key]))
|
||||
except UnicodeEncodeError:
|
||||
print '{0}: {1}'.format(key, repr(res[key]))
|
||||
print('{0}: {1}'.format(key, repr(res[key])))
|
||||
continue
|
||||
elif 'value' in res[key] and res[key]['value'] is not None:
|
||||
attrstr = '%s="%s"' % (key, res[key]['value'])
|
||||
@@ -324,7 +336,7 @@ def print_result(res):
|
||||
else:
|
||||
sys.stdout.write('{0}: '.format(key))
|
||||
if isinstance(res[key], str) or isinstance(res[key], unicode):
|
||||
print res[key]
|
||||
print(res[key])
|
||||
else:
|
||||
print_result(res[key])
|
||||
continue
|
||||
@@ -423,10 +435,10 @@ def do_command(command, server):
|
||||
for res in session.read(targpath):
|
||||
if 'item' in res: # a link relation
|
||||
if type(res['item']) == dict:
|
||||
print res['item']["href"]
|
||||
print(res['item']["href"])
|
||||
else:
|
||||
for item in res['item']:
|
||||
print item["href"]
|
||||
print(item["href"])
|
||||
else: # generic attributes to list
|
||||
if 'error' in res:
|
||||
sys.stderr.write(res['error'] + '\n')
|
||||
@@ -851,7 +863,7 @@ def server_connect():
|
||||
passphrase = os.environ['CONFLUENT_PASSPHRASE']
|
||||
session.authenticate(username, passphrase)
|
||||
while not session.authenticated:
|
||||
username = raw_input("Name: ")
|
||||
username = input("Name: ")
|
||||
passphrase = getpass.getpass("Passphrase: ")
|
||||
session.authenticate(username, passphrase)
|
||||
|
||||
@@ -871,7 +883,7 @@ def main():
|
||||
global inconsole
|
||||
try:
|
||||
server_connect()
|
||||
except EOFError, KeyboardInterrupt:
|
||||
except (EOFError, KeyboardInterrupt) as _:
|
||||
raise BailOut(0)
|
||||
except socket.gaierror:
|
||||
sys.stderr.write('Could not connect to confluent\n')
|
||||
@@ -929,6 +941,7 @@ def main():
|
||||
updatestatus(data)
|
||||
continue
|
||||
if data is not None:
|
||||
data = client.stringify(data)
|
||||
if clearpowermessage:
|
||||
sys.stdout.write("\x1b[2J\x1b[;H")
|
||||
clearpowermessage = False
|
||||
@@ -952,7 +965,7 @@ def main():
|
||||
try:
|
||||
server_connect()
|
||||
connected = True
|
||||
except (socket.gaierror, socket.error):
|
||||
except Exception:
|
||||
pass
|
||||
if not connected:
|
||||
time.sleep(1)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
import optparse
|
||||
import signal
|
||||
import sys
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
import csv
|
||||
import optparse
|
||||
import signal
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
import csv
|
||||
import optparse
|
||||
import signal
|
||||
|
||||
@@ -1,19 +1,40 @@
|
||||
#!/bin/sh
|
||||
#!/usr/bin/python
|
||||
# This will take a given directory and make a 'big floppy image'
|
||||
# out of it, suitable for nodemedia upload.
|
||||
|
||||
if [ -z "$1" -o -z "$2" ]; then
|
||||
echo "Usage: $0 <directory> <imagefile>"
|
||||
exit 1
|
||||
fi
|
||||
# Get the needed payload side
|
||||
SIZE=$(du -sB 512 $1|awk '{print $1}')
|
||||
ENTRIES=$(find $1 |wc -l)
|
||||
# Also, each file and directory has overhead, pad size by 32kb per file,
|
||||
# which should be overkill but other values proved to be inadequate
|
||||
# A deeper understanding of VFAT would probably allow for more precise value
|
||||
SIZE=$((SIZE + ENTRIES * 64))
|
||||
dd if=/dev/zero of=$2 bs=512 count=$SIZE
|
||||
# Make a big single sided floppy with many many tracks, saves on complex math
|
||||
mformat -i $2 -d 1 -t $SIZE -s 1 -h 1 ::
|
||||
mcopy -i $2 -s $1/* ::
|
||||
import glob
|
||||
import os
|
||||
import subprocess
|
||||
import sys
|
||||
|
||||
def create_image(directory, image):
|
||||
ents = 0
|
||||
datasz = 512
|
||||
for dir in os.walk(sys.argv[1]):
|
||||
ents += 1
|
||||
for filen in dir[2]:
|
||||
ents += 1
|
||||
filename = os.path.join(dir[0], filen)
|
||||
currsz = os.path.getsize(filename)
|
||||
# assuming up to 65k cluster
|
||||
currsz = (currsz // 512 +1) * 512
|
||||
datasz += currsz
|
||||
datasz += ents * 32768
|
||||
datasz = datasz // 512 + 1
|
||||
with open(image, 'wb') as imgfile:
|
||||
imgfile.seek(datasz * 512 - 1)
|
||||
imgfile.write(b'\x00')
|
||||
subprocess.check_call(['mformat', '-i', image, '-d', '1', '-t',
|
||||
str(datasz), '-s', '1','-h', '1', '::'])
|
||||
cpycmd = ['mcopy', '-i', image, '-s']
|
||||
cpycmd.extend(glob.glob('{0}/*'.format(directory)))
|
||||
cpycmd.append('::')
|
||||
subprocess.check_call(cpycmd)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
if len(sys.argv) < 3:
|
||||
sys.stderr.write("Usage: {0} <directory> <imagefile>".format(
|
||||
sys.argv[0]))
|
||||
sys.exit(1)
|
||||
create_image(sys.argv[1], sys.argv[2])
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -50,6 +50,9 @@ argparser.add_option('-c', '--clear', action='store_true',
|
||||
help='Clear attributes')
|
||||
argparser.add_option('-p', '--prompt', action='store_true',
|
||||
help='Prompt for attribute values interactively')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Prompt if trying to set attributes on more '
|
||||
'than specified number of nodes')
|
||||
(options, args) = argparser.parse_args()
|
||||
|
||||
|
||||
@@ -87,6 +90,7 @@ if len(args) > 1:
|
||||
if oneval != twoval:
|
||||
print('Values did not match.')
|
||||
argassign[arg] = twoval
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
exitcode=client.updateattrib(session,args,nodetype, noderange, options, argassign)
|
||||
try:
|
||||
# setting user output to what the user inputs
|
||||
@@ -128,4 +132,4 @@ else:
|
||||
else:
|
||||
print(res['item']['href'].replace('/', ''))
|
||||
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
@@ -32,6 +32,8 @@ if path.startswith('/opt'):
|
||||
import confluent.client as client
|
||||
|
||||
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Number of nodes to affect before prompting for confirmation')
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
@@ -43,8 +45,10 @@ session = client.Command()
|
||||
exitcode = 0
|
||||
|
||||
errorNodes = set([])
|
||||
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
success = session.simple_noderange_command(noderange, 'configuration/management_controller/reset', 'reset', key='state', errnodes=errorNodes) # = 0 if successful
|
||||
if success != 0:
|
||||
sys.exit(success)
|
||||
|
||||
# Determine which nodes were successful and print them
|
||||
|
||||
@@ -56,7 +60,7 @@ for node in session.read('/noderange/{0}/nodes/'.format(noderange)):
|
||||
goodNodes = allNodes - errorNodes
|
||||
|
||||
for node in goodNodes:
|
||||
print node + ": BMC Reset Successful"
|
||||
print(node + ": BMC Reset Successful")
|
||||
|
||||
|
||||
sys.exit(success)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015 Lenovo
|
||||
@@ -42,6 +42,10 @@ argparser.add_option('-p', '--persist', dest='persist', action='store_true',
|
||||
default=False,
|
||||
help='Request the boot device be persistent rather than '
|
||||
'one time')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to boot, '
|
||||
'prompting if over the threshold')
|
||||
|
||||
(options, args) = argparser.parse_args()
|
||||
|
||||
@@ -54,8 +58,8 @@ except IndexError:
|
||||
sys.exit(1)
|
||||
client.check_globbing(noderange)
|
||||
bootdev = None
|
||||
if len(sys.argv) > 2:
|
||||
bootdev = sys.argv[2]
|
||||
if len(args) > 1:
|
||||
bootdev = args[1]
|
||||
if bootdev in ('net', 'pxe'):
|
||||
bootdev = 'network'
|
||||
session = client.Command()
|
||||
@@ -66,6 +70,7 @@ else:
|
||||
bootmode = 'uefi'
|
||||
|
||||
errnodes = set([])
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
rc = session.simple_noderange_command(noderange, '/boot/nextdevice', bootdev,
|
||||
bootmode=bootmode,
|
||||
persistent=options.persist,
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -54,6 +54,12 @@ argparser.add_option('-d', '--detail', dest='detail',
|
||||
action='store_true', default=False,
|
||||
help='Provide verbose information as available, such as '
|
||||
'help text and possible valid values')
|
||||
argparser.add_option('-e', '--extra', dest='extra',
|
||||
action='store_true', default=False,
|
||||
help='Access extra configuration. Extra configuration is generally '
|
||||
'reserved for unpopular or redundant options that may be slow to '
|
||||
'read. Notably the IMM category on Lenovo settings is considered '
|
||||
'to be extra configuration')
|
||||
argparser.add_option('-x', '--exclude', dest='exclude',
|
||||
action='store_true', default=False,
|
||||
help='Treat positional arguments as items to not '
|
||||
@@ -68,6 +74,10 @@ argparser.add_option('-r', '--restoredefault', default=False,
|
||||
help='Restore the configuration of the node '
|
||||
'to factory default for given component. '
|
||||
'Currently only uefi is supported')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to configure, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
|
||||
cfgpaths = {
|
||||
@@ -98,6 +108,9 @@ setmode = None
|
||||
assignment = {}
|
||||
queryparms = {}
|
||||
printsys = []
|
||||
printbmc = []
|
||||
printextbmc = []
|
||||
printallbmc = False
|
||||
setsys = {}
|
||||
forceset = False
|
||||
needval = None
|
||||
@@ -122,7 +135,7 @@ def _assign_value():
|
||||
|
||||
|
||||
def parse_config_line(arguments):
|
||||
global setmode, forceset, key, value, needval, candidate, path, attrib
|
||||
global setmode, printallbmc, forceset, key, value, needval, candidate, path, attrib
|
||||
for param in arguments:
|
||||
if param == 'show':
|
||||
continue # forgive muscle memory of pasu users
|
||||
@@ -154,6 +167,8 @@ def parse_config_line(arguments):
|
||||
if setmode != False:
|
||||
bailout('Cannot do set and query in same command')
|
||||
if '.' not in param:
|
||||
if param == 'bmc':
|
||||
printallbmc = True
|
||||
matchedparms = False
|
||||
for candidate in cfgpaths:
|
||||
if candidate.startswith('{0}.'.format(param)):
|
||||
@@ -169,10 +184,19 @@ def parse_config_line(arguments):
|
||||
del queryparms[path]
|
||||
except KeyError:
|
||||
pass
|
||||
if not matchedparms:
|
||||
if param.lower() == 'imm':
|
||||
printextbmc.append(param)
|
||||
options.extra = True
|
||||
elif not matchedparms:
|
||||
printsys.append(param)
|
||||
elif param not in cfgpaths:
|
||||
printsys.append(param)
|
||||
if param.startswith('bmc.'):
|
||||
printbmc.append(param.replace('bmc.', ''))
|
||||
elif param.lower().startswith('imm'):
|
||||
options.extra = True
|
||||
printextbmc.append(param)
|
||||
else:
|
||||
printsys.append(param)
|
||||
else:
|
||||
path, attrib = cfgpaths[param]
|
||||
path = '/noderange/{0}/{1}'.format(noderange, path)
|
||||
@@ -197,19 +221,29 @@ else:
|
||||
parse_config_line(args[1:])
|
||||
session = client.Command()
|
||||
rcode = 0
|
||||
if options.restoredefault and options.restoredefault.lower() in (
|
||||
if options.restoredefault:
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
if options.restoredefault.lower() in (
|
||||
'sys', 'system', 'uefi', 'bios'):
|
||||
for fr in session.update(
|
||||
'/noderange/{0}/configuration/system/clear'.format(noderange),
|
||||
{'clear': True}):
|
||||
rcode |= client.printerror(fr)
|
||||
sys.exit(rcode)
|
||||
elif options.restoredefault:
|
||||
sys.stderr.write(
|
||||
'Unrecognized component to restore defaults: {0}\n'.format(
|
||||
options.restoredefault))
|
||||
sys.exit(1)
|
||||
for fr in session.update(
|
||||
'/noderange/{0}/configuration/system/clear'.format(noderange),
|
||||
{'clear': True}):
|
||||
rcode |= client.printerror(fr)
|
||||
sys.exit(rcode)
|
||||
elif options.restoredefault.lower() in (
|
||||
'bmc', 'imm', 'xcc'):
|
||||
for fr in session.update(
|
||||
'/noderange/{0}/configuration/management_controller/clear'.format(noderange),
|
||||
{'clear': True}):
|
||||
rcode |= client.printerror(fr)
|
||||
sys.exit(rcode)
|
||||
else:
|
||||
sys.stderr.write(
|
||||
'Unrecognized component to restore defaults: {0}\n'.format(
|
||||
options.restoredefault))
|
||||
sys.exit(1)
|
||||
if setmode:
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
if options.exclude:
|
||||
sys.stderr.write('Cannot use exclude and assign at the same time\n')
|
||||
sys.exit(1)
|
||||
@@ -217,8 +251,12 @@ if setmode:
|
||||
attrnamebypath = {}
|
||||
for key in assignment:
|
||||
if key not in cfgpaths:
|
||||
path = 'configuration/system/all'
|
||||
attrib = key
|
||||
if key.startswith('bmc.'):
|
||||
path = 'configuration/management_controller/extended/all'
|
||||
attrib = key.replace('bmc.', '')
|
||||
else:
|
||||
path = 'configuration/system/all'
|
||||
attrib = key
|
||||
else:
|
||||
path, attrib = cfgpaths[key]
|
||||
if path not in updatebypath:
|
||||
@@ -250,6 +288,15 @@ else:
|
||||
NullOpt(), queryparms[path])
|
||||
if rc:
|
||||
sys.exit(rc)
|
||||
if printsys == 'all' or printextbmc or printbmc or printallbmc:
|
||||
if printbmc or not printextbmc:
|
||||
rcode = client.print_attrib_path(
|
||||
'/noderange/{0}/configuration/management_controller/extended/all'.format(noderange),
|
||||
session, printbmc, options, attrprefix='bmc.')
|
||||
if options.extra:
|
||||
rcode |= client.print_attrib_path(
|
||||
'/noderange/{0}/configuration/management_controller/extended/extra'.format(noderange),
|
||||
session, printextbmc, options)
|
||||
if printsys or options.exclude:
|
||||
if printsys == 'all':
|
||||
printsys = []
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015 Lenovo
|
||||
@@ -51,27 +51,28 @@ if options.tile:
|
||||
nodes.append(node)
|
||||
initial = True
|
||||
pane = 0
|
||||
sessname = 'nodeconsole_{0}'.format(os.getpid())
|
||||
for node in sortutil.natural_sort(nodes):
|
||||
panename = '{0}:{1}'.format(sessname, pane)
|
||||
if initial:
|
||||
initial = False
|
||||
subprocess.call(
|
||||
['tmux', 'new-session', '-d', '-s',
|
||||
'nodeconsole_{0}'.format(os.getpid()), '-x', '800', '-y',
|
||||
sessname, '-x', '800', '-y',
|
||||
'800', '{0} -m 5 start /nodes/{1}/console/session'.format(
|
||||
confettypath, node)])
|
||||
else:
|
||||
subprocess.call(['tmux', 'select-pane', '-t', str(pane)])
|
||||
subprocess.call(['tmux', 'set-option', 'pane-border-status', 'top'], stderr=null)
|
||||
pane += 1
|
||||
subprocess.call(['tmux', 'select-pane', '-t', sessname])
|
||||
subprocess.call(['tmux', 'set-option', '-t', panename, 'pane-border-status', 'top'], stderr=null)
|
||||
subprocess.call(
|
||||
['tmux', 'split', '-h',
|
||||
['tmux', 'split', '-h', '-t', sessname,
|
||||
'{0} -m 5 start /nodes/{1}/console/session'.format(
|
||||
confettypath, node)])
|
||||
subprocess.call(['tmux', 'select-layout', 'tiled'], stdout=null)
|
||||
subprocess.call(['tmux', 'select-pane', '-t', '0'])
|
||||
subprocess.call(['tmux', 'set-option', 'pane-border-status', 'top'], stderr=null)
|
||||
os.execlp('tmux', 'tmux', 'attach', '-t', 'nodeconsole_{0}'.format(
|
||||
os.getpid()))
|
||||
subprocess.call(['tmux', 'select-layout', '-t', sessname, 'tiled'], stdout=null)
|
||||
pane += 1
|
||||
subprocess.call(['tmux', 'select-pane', '-t', sessname])
|
||||
subprocess.call(['tmux', 'set-option', '-t', panename, 'pane-border-status', 'top'], stderr=null)
|
||||
os.execlp('tmux', 'tmux', 'attach', '-t', sessname)
|
||||
else:
|
||||
os.execl(confettypath, confettypath, 'start',
|
||||
'/nodes/{0}/console/session'.format(args[0]))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -55,4 +55,4 @@ for r in session.create('/noderange/', attribs):
|
||||
exitcode |= 1
|
||||
if 'created' in r:
|
||||
print('{0}: created'.format(r['created']))
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
Executable
+67
@@ -0,0 +1,67 @@
|
||||
#!/usr/bin/python3
|
||||
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
path = os.path.dirname(os.path.realpath(__file__))
|
||||
path = os.path.realpath(os.path.join(path, '..', 'lib', 'python'))
|
||||
if path.startswith('/opt'):
|
||||
sys.path.append(path)
|
||||
|
||||
import confluent.client as client
|
||||
|
||||
def armonce(nr, cli):
|
||||
nodes = set([])
|
||||
for rsp in cli.read('/noderange/{0}/attributes/current'.format(nr)):
|
||||
for node in rsp.get('databynode', {}):
|
||||
nodeinfo = rsp['databynode'][node]
|
||||
for attr in nodeinfo:
|
||||
if attr == 'deployment.apiarmed':
|
||||
curr = nodeinfo[attr].get('value', '')
|
||||
if curr == 'continuous':
|
||||
nodes.add(node)
|
||||
noderange = nr
|
||||
if nodes:
|
||||
noderange += ',-({0})'.format(','.join(nodes))
|
||||
for rsp in cli.update('/noderange/{0}/attributes/current'.format(noderange),
|
||||
{'deployment.apiarmed': 'once'}):
|
||||
pass
|
||||
|
||||
def setpending(nr, profile, cli):
|
||||
for rsp in cli.update('/noderange/{0}/attributes/current'.format(nr),
|
||||
{'deployment.pendingprofile': profile}):
|
||||
pass
|
||||
|
||||
|
||||
def main(args):
|
||||
ap = argparse.ArgumentParser(description='Deploy OS to nodes')
|
||||
ap.add_argument('-n', '--network', help='Initiate deployment over PXE', action='store_true')
|
||||
ap.add_argument('-m', '--maxnodes', help='Specifiy a maximum nodes to be deployed')
|
||||
ap.add_argument('noderange', help='Set of nodes to deploy')
|
||||
ap.add_argument('profile', help='Profile name to deploy')
|
||||
args = ap.parse_args(args)
|
||||
if not args.network:
|
||||
sys.stderr.write('Currently only network (-n) deployment is supported\n')
|
||||
return 1
|
||||
c = client.Command()
|
||||
c.stop_if_noderange_over(args.noderange, args.maxnodes)
|
||||
armonce(args.noderange, c)
|
||||
setpending(args.noderange, args.profile, c)
|
||||
errnodes = set([])
|
||||
rc = c.simple_noderange_command(args.noderange, '/boot/nextdevice', 'network',
|
||||
bootmode='uefi',
|
||||
persistent=False,
|
||||
errnodes=errnodes)
|
||||
if errnodes:
|
||||
sys.stderr.write(
|
||||
'Unable to set boot device for following nodes: {0}\n'.format(
|
||||
','.join(errnodes)))
|
||||
return 1
|
||||
rc |= c.simple_noderange_command(args.noderange, '/power/state', 'boot')
|
||||
return rc
|
||||
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
sys.exit(main(sys.argv[1:]))
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -92,6 +92,8 @@ def process_header(header):
|
||||
fields.append('hardwaremanagement.manager')
|
||||
elif datum in ('bmc gateway', 'xcc gateway', 'imm gateway'):
|
||||
fields.append('net.bmc.ipv4_gateway')
|
||||
elif datum in ('bmc_gateway', 'xcc_gateway', 'imm_gateway'):
|
||||
fields.append('net.bmc.ipv4_gateway')
|
||||
elif datum in ('bmcuser', 'username', 'user'):
|
||||
fields.append('secret.hardwaremanagementuser')
|
||||
elif datum in ('bmcpass', 'password', 'pass'):
|
||||
@@ -152,6 +154,7 @@ def import_csv(options, session):
|
||||
for field in fields:
|
||||
if field in unique_fields:
|
||||
unique_data[field] = set([])
|
||||
broken = False
|
||||
for record in records:
|
||||
currfields = list(fields)
|
||||
nodedatum = {}
|
||||
@@ -168,14 +171,16 @@ def import_csv(options, session):
|
||||
nodedatum[currfield] = datum
|
||||
if not datum_complete(nodedatum):
|
||||
sys.exit(1)
|
||||
if not search_record(nodedatum, options, session):
|
||||
if not search_record(nodedatum, options, session) and not broken:
|
||||
blocking_scan(session)
|
||||
if not search_record(nodedatum, options, session):
|
||||
sys.stderr.write(
|
||||
"Could not match the following data: " +
|
||||
repr(nodedatum) + '\n')
|
||||
sys.exit(1)
|
||||
broken = True
|
||||
nodedata.append(nodedatum)
|
||||
if broken:
|
||||
sys.exit(1)
|
||||
for datum in nodedata:
|
||||
maclist = search_record(datum, options, session)
|
||||
datum = datum_to_attrib(datum)
|
||||
@@ -232,10 +237,12 @@ def clear_discovery(options, session):
|
||||
else:
|
||||
print(repr(res))
|
||||
|
||||
def list_matching_macs(options, session, node=None):
|
||||
def list_matching_macs(options, session, node=None, checknode=True):
|
||||
path = '/discovery/'
|
||||
if node:
|
||||
path += 'by-node/{0}/'.format(node)
|
||||
elif checknode and options.node:
|
||||
path += 'by-node/{0}/'.format(options.node)
|
||||
if options.model:
|
||||
path += 'by-model/{0}/'.format(options.model)
|
||||
if options.serial:
|
||||
@@ -272,11 +279,11 @@ def assign_discovery(options, session, needid=True):
|
||||
abort = True
|
||||
if abort:
|
||||
sys.exit(1)
|
||||
matches = list_matching_macs(options, session, None if needid else options.node)
|
||||
matches = list_matching_macs(options, session, None if needid else options.node, False)
|
||||
if not matches:
|
||||
# Do a rescan to catch missing requested data
|
||||
blocking_scan(session)
|
||||
matches = list_matching_macs(options, session, None if needid else options.node)
|
||||
matches = list_matching_macs(options, session, None if needid else options.node, False)
|
||||
if not matches:
|
||||
sys.stderr.write("No matching discovery candidates found\n")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
# Copyright 2015-2019 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -38,6 +38,10 @@ if sys.version_info[0] < 3:
|
||||
|
||||
argparser = optparse.OptionParser(
|
||||
usage="Usage: %prog [options] noderange [clear]")
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to clear if clearing log, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
@@ -46,11 +50,11 @@ except IndexError:
|
||||
sys.exit(1)
|
||||
client.check_globbing(noderange)
|
||||
deletemode = False
|
||||
if len(sys.argv) > 3:
|
||||
if len(args) > 2:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
if len(sys.argv) == 3:
|
||||
if sys.argv[2] == 'clear':
|
||||
if len(args) == 2:
|
||||
if args[1] == 'clear':
|
||||
deletemode = True
|
||||
else:
|
||||
argparser.print_help()
|
||||
@@ -65,6 +69,8 @@ def format_event(evt):
|
||||
display = dt.strptime(evt['timestamp'], '%Y-%m-%dT%H:%M:%S')
|
||||
retparts.append(display.strftime('%m/%d/%Y %H:%M:%S'))
|
||||
dscparts = []
|
||||
if evt.get('log_id', None):
|
||||
retparts.append(evt['log_id'] + ':')
|
||||
if 'component_type' in evt and evt['component_type'] is not None:
|
||||
dscparts.append(evt['component_type'])
|
||||
if 'component' in evt and evt['component'] is not None:
|
||||
@@ -86,6 +92,7 @@ def format_event(evt):
|
||||
|
||||
if deletemode:
|
||||
func = session.delete
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
else:
|
||||
func = session.read
|
||||
for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
|
||||
@@ -102,4 +109,4 @@ for rsp in func('/noderange/{0}/events/hardware/log'.format(noderange)):
|
||||
if 'events' in thisdata:
|
||||
evtdata = thisdata['events']
|
||||
for evt in evtdata:
|
||||
print '{0}: {1}'.format(node, format_event(evt))
|
||||
print('{0}: {1}'.format(node, format_event(evt)))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2016-2017 Lenovo
|
||||
@@ -59,6 +59,10 @@ argparser = optparse.OptionParser(
|
||||
"%prog <noderange> [list][update [--backup <file>]]|[<components>]")
|
||||
argparser.add_option('-b', '--backup', action='store_true',
|
||||
help='Target a backup bank rather than primary')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='When updating, prompt if more than the specified '
|
||||
'number of servers will be affected')
|
||||
|
||||
(options, args) = argparser.parse_args()
|
||||
upfile = None
|
||||
try:
|
||||
@@ -95,6 +99,7 @@ def get_update_progress(session, url):
|
||||
|
||||
def update_firmware(session, filename):
|
||||
global exitcode
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
output = sq.ScreenPrinter(noderange, session)
|
||||
nodeurls = {}
|
||||
filename = os.path.abspath(filename)
|
||||
@@ -151,7 +156,7 @@ def show_firmware(session):
|
||||
for prefix in inv:
|
||||
firmware_shown = True
|
||||
printfirm(node, prefix, inv[prefix])
|
||||
if not firmware_shown:
|
||||
if not firmware_shown and not exitcode:
|
||||
argparser.print_help()
|
||||
|
||||
|
||||
@@ -163,4 +168,4 @@ try:
|
||||
update_firmware(session, upfile)
|
||||
except KeyboardInterrupt:
|
||||
print('')
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -97,7 +97,7 @@ if len(args) > 1:
|
||||
|
||||
requestargs=args[1:]
|
||||
except Exception as e:
|
||||
print str(e)
|
||||
print(str(e))
|
||||
|
||||
if exitcode != 0:
|
||||
sys.exit(exitcode)
|
||||
@@ -123,6 +123,6 @@ else:
|
||||
sys.stderr.write(res['error'] + '\n')
|
||||
exitcode = 1
|
||||
else:
|
||||
print res['item']['href'].replace('/', '')
|
||||
print(res['item']['href'].replace('/', ''))
|
||||
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -55,4 +55,4 @@ for r in session.create('/nodegroups/', attribs):
|
||||
exitcode |= 1
|
||||
if 'created' in r:
|
||||
print('{0}: created'.format(r['created']))
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -49,4 +49,4 @@ for r in session.delete('/nodegroups/{0}'.format(noderange)):
|
||||
exitcode |= 1
|
||||
if 'deleted' in r:
|
||||
print('{0}: deleted'.format(r['deleted']))
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
@@ -31,7 +31,7 @@ if path.startswith('/opt'):
|
||||
|
||||
import confluent.client as client
|
||||
|
||||
argparser = optparse.OptionParser(usage="Usage: %prog <noderange> [on|off]")
|
||||
argparser = optparse.OptionParser(usage="Usage: %prog <noderange> [on|off|blink]")
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
@@ -42,9 +42,6 @@ client.check_globbing(noderange)
|
||||
identifystate = None
|
||||
if len(sys.argv) > 2:
|
||||
identifystate = sys.argv[2]
|
||||
else:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
sys.exit(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2016-2017 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 Lenovo
|
||||
@@ -37,6 +37,10 @@ exitcode = 0
|
||||
argparser = optparse.OptionParser(
|
||||
usage="Usage: "
|
||||
"%prog <noderange> [list][install <file>|save <directory>|delete <name>]")
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to delete licenses from, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
upfile = None
|
||||
downdir = None
|
||||
@@ -50,8 +54,9 @@ try:
|
||||
downdir = args[2]
|
||||
elif args[1] == 'delete':
|
||||
delete = args[2]
|
||||
else:
|
||||
components = ['all']
|
||||
elif args[1] != 'list':
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
except IndexError:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
@@ -60,16 +65,16 @@ client.check_globbing(noderange)
|
||||
|
||||
def install_license(session, filename):
|
||||
global exitcode
|
||||
if not os.path.exists(filename):
|
||||
sys.stderr.write('Unable to locate requested file {0}\n'.format(
|
||||
filename))
|
||||
sys.exit(404)
|
||||
resource = '/noderange/{0}/configuration/' \
|
||||
'management_controller/licenses/'.format(noderange)
|
||||
filename = os.path.abspath(filename)
|
||||
instargs = {'filename': filename}
|
||||
for res in session.create(resource, instargs):
|
||||
pass # print(repr(res))
|
||||
for node in res.get('databynode', []):
|
||||
if 'error' in res['databynode'][node]:
|
||||
sys.stderr.write('{0}: {1}\n'.format(
|
||||
node, res['databynode'][node]['error']))
|
||||
sys.exit(res['databynode'][node].get('errorcode', 1))
|
||||
show_licenses(session)
|
||||
|
||||
|
||||
@@ -78,18 +83,16 @@ def save_licenses(session, dirname):
|
||||
resource = '/noderange/{0}/configuration/' \
|
||||
'management_controller/save_licenses'.format(noderange)
|
||||
filename = os.path.abspath(dirname)
|
||||
if not os.path.exists(filename):
|
||||
sys.stderr.write('Unable to locate specified directory {0}\n'.format(
|
||||
filename))
|
||||
sys.exit(404)
|
||||
instargs = {'dirname': filename}
|
||||
for res in session.create(resource, instargs):
|
||||
for node in res.get('databynode', {}):
|
||||
fname = res['databynode'][node].get('filename', None)
|
||||
if fname:
|
||||
print('{0}: Saved license to {1}'.format(node, fname))
|
||||
elif 'error' in res['databynode'][node]:
|
||||
sys.stderr.write('{0}: {1}\n'.format(node, res['databynode'][node]['error']))
|
||||
else:
|
||||
sys.stderr.write('{0}: {1}', node, repr(res['databynode'][node]))
|
||||
sys.stderr.write('{0}: {1}\n'.format(node, repr(res['databynode'][node])))
|
||||
|
||||
|
||||
def show_licenses(session):
|
||||
@@ -133,6 +136,7 @@ try:
|
||||
elif downdir:
|
||||
save_licenses(session, downdir)
|
||||
elif delete:
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
delete_license(session, delete)
|
||||
else:
|
||||
show_licenses(session)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2018 Lenovo
|
||||
@@ -188,4 +188,4 @@ def main():
|
||||
sys.exit(1)
|
||||
handler(noderange, media)
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
@@ -37,6 +37,11 @@ argparser = optparse.OptionParser(
|
||||
argparser.add_option('-p', '--showprevious', dest='previous',
|
||||
action='store_true', default=False,
|
||||
help='Show previous power state')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to change power state, '
|
||||
'prompting if over the threshold')
|
||||
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
@@ -72,4 +77,4 @@ if options.previous:
|
||||
# add dictionary to session
|
||||
session.add_precede_dict(prev)
|
||||
|
||||
sys.exit(session.simple_noderange_command(noderange, '/power/state', setstate))
|
||||
sys.exit(session.simple_noderange_command(noderange, '/power/state', setstate, promptover=options.maxnodes))
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2017 Lenovo
|
||||
@@ -35,6 +35,10 @@ import confluent.client as client
|
||||
argparser = optparse.OptionParser(
|
||||
usage='''\n %prog noderange
|
||||
\n ''')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to delete, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
if len(args) != 1:
|
||||
argparser.print_help()
|
||||
@@ -43,10 +47,11 @@ noderange = args[0]
|
||||
client.check_globbing(noderange)
|
||||
session = client.Command()
|
||||
exitcode = 0
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
for r in session.delete('/noderange/{0}'.format(noderange)):
|
||||
if 'error' in r:
|
||||
sys.stderr.write(r['error'] + '\n')
|
||||
exitcode |= 1
|
||||
if 'deleted' in r:
|
||||
print('{0}: deleted'.format(r['deleted']))
|
||||
sys.exit(exitcode)
|
||||
sys.exit(exitcode)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 Lenovo
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
@@ -32,6 +32,10 @@ if path.startswith('/opt'):
|
||||
import confluent.client as client
|
||||
|
||||
argparser = optparse.OptionParser(usage="Usage: %prog <noderange>")
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to reseat, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
try:
|
||||
noderange = args[0]
|
||||
@@ -43,7 +47,7 @@ session = client.Command()
|
||||
exitcode = 0
|
||||
|
||||
errorNodes = set([])
|
||||
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
success = session.simple_noderange_command(noderange, 'power/reseat', 'reseat', key='reseat', errnodes=errorNodes) # = 0 if successful
|
||||
|
||||
# Determine which nodes were successful and print them
|
||||
@@ -56,7 +60,7 @@ for node in session.read('/noderange/{0}/nodes/'.format(noderange)):
|
||||
goodNodes = allNodes - errorNodes
|
||||
|
||||
for node in goodNodes:
|
||||
print node + ": Reseat successful"
|
||||
print(node + ": Reseat successful")
|
||||
|
||||
|
||||
sys.exit(success)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2016-2017 Lenovo
|
||||
@@ -42,6 +42,10 @@ def run():
|
||||
argparser = optparse.OptionParser(
|
||||
usage="Usage: %prog location noderange:location",
|
||||
)
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to run rsync to, '
|
||||
'prompting if over the threshold')
|
||||
argparser.add_option('-f', '-c', '--count', type='int', default=168,
|
||||
help='Number of nodes to concurrently rsync')
|
||||
# among other things, FD_SETSIZE limits. Besides, spawning too many
|
||||
@@ -55,7 +59,7 @@ def run():
|
||||
noderange, targpath = args[-1].split(':', 1)
|
||||
client.check_globbing(noderange)
|
||||
c = client.Command()
|
||||
cmdstr = " ".join(args[:-1])
|
||||
cmdstr = ' '.join(args[:-1])
|
||||
cmdstr = 'rsync -av --info=progress2 ' + cmdstr
|
||||
cmdstr += ' {node}:' + targpath
|
||||
|
||||
@@ -64,15 +68,17 @@ def run():
|
||||
pipedesc = {}
|
||||
pendingexecs = deque()
|
||||
exitcode = 0
|
||||
|
||||
c.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
for exp in c.create('/noderange/{0}/attributes/expression'.format(noderange),
|
||||
{'expression': cmdstr}):
|
||||
{'expression': cmdstr}):
|
||||
if 'error' in exp:
|
||||
sys.stderr.write(exp['error'] + '\n')
|
||||
exitcode |= exp.get('errorcode', 1)
|
||||
ex = exp.get('databynode', ())
|
||||
for node in ex:
|
||||
cmd = ex[node]['value'].encode('utf-8')
|
||||
cmd = ex[node]['value']
|
||||
if not isinstance(cmd, bytes) and not isinstance(cmd, str):
|
||||
cmd = cmd.encode('utf-8')
|
||||
cmdv = shlex.split(cmd)
|
||||
if currprocs < concurrentprocs:
|
||||
currprocs += 1
|
||||
@@ -98,7 +104,7 @@ def run():
|
||||
if desc['type'] == 'stdout':
|
||||
if node not in pernodeout:
|
||||
pernodeout[node] = ''
|
||||
pernodeout[node] += data
|
||||
pernodeout[node] += client.stringify(data)
|
||||
if '\n' in pernodeout[node]:
|
||||
currout, pernodeout[node] = pernodeout[node].split('\n', 1)
|
||||
if currout:
|
||||
@@ -117,7 +123,7 @@ def run():
|
||||
output.set_output(node, 'error!')
|
||||
if node not in nodeerrs:
|
||||
nodeerrs[node] = ''
|
||||
nodeerrs[node] += data
|
||||
nodeerrs[node] += client.stringify(data)
|
||||
else:
|
||||
pop = desc['popen']
|
||||
ret = pop.poll()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2016-2017 Lenovo
|
||||
@@ -46,6 +46,10 @@ def run():
|
||||
help='Number of commands to run at a time')
|
||||
argparser.add_option('-n', '--nonodeprefix', action='store_true',
|
||||
help='Do not prefix output with node names')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to run the command with, '
|
||||
'prompting if over the threshold')
|
||||
# among other things, FD_SETSIZE limits. Besides, spawning too many
|
||||
# processes can be unkind for the unaware on memory pressure and such...
|
||||
argparser.disable_interspersed_args()
|
||||
@@ -63,7 +67,7 @@ def run():
|
||||
pipedesc = {}
|
||||
pendingexecs = deque()
|
||||
exitcode = 0
|
||||
|
||||
c.stop_if_noderange_over(args[0], options.maxnodes)
|
||||
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
|
||||
{'expression': cmdstr}):
|
||||
if 'error' in exp:
|
||||
@@ -71,7 +75,9 @@ def run():
|
||||
exitcode |= exp.get('errorcode', 1)
|
||||
ex = exp.get('databynode', ())
|
||||
for node in ex:
|
||||
cmd = ex[node]['value'].encode('utf-8')
|
||||
cmd = ex[node]['value']
|
||||
if not isinstance(cmd, bytes) and not isinstance(cmd, str):
|
||||
cmd = cmd.encode('utf-8')
|
||||
cmdv = shlex.split(cmd)
|
||||
if currprocs < concurrentprocs:
|
||||
currprocs += 1
|
||||
@@ -95,6 +101,7 @@ def run():
|
||||
pernodeout[node] = []
|
||||
pernodeout[node].append(data)
|
||||
else:
|
||||
data = client.stringify(data)
|
||||
if options.nonodeprefix:
|
||||
sys.stderr.write(data)
|
||||
else:
|
||||
@@ -112,6 +119,7 @@ def run():
|
||||
run_cmdv(node, cmdv, all, pipedesc)
|
||||
for node in sortutil.natural_sort(pernodeout):
|
||||
for line in pernodeout[node]:
|
||||
line = client.stringify(line)
|
||||
if options.nonodeprefix:
|
||||
sys.stdout.write(line)
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015-2017 Lenovo
|
||||
@@ -149,8 +149,11 @@ def sensorpass(showout=True, appendtime=False):
|
||||
if appendtime:
|
||||
showval += ' @' + time.strftime(
|
||||
'%Y-%m-%dT%H:%M:%S')
|
||||
print(u'{0}: {1}:{2}'.format(
|
||||
node, sensedata['name'], showval))
|
||||
printval = u'{0}: {1}:{2}'.format(
|
||||
node, sensedata['name'], showval)
|
||||
if not isinstance(printval, str):
|
||||
printval = printval.encode('utf-8')
|
||||
print(printval)
|
||||
sys.stdout.flush()
|
||||
return resultdata
|
||||
|
||||
@@ -158,7 +161,7 @@ def sensorpass(showout=True, appendtime=False):
|
||||
def format_csv(csvwriter, orderedsensors, resdata, showtime=True):
|
||||
for nodekey in resdata:
|
||||
if showtime:
|
||||
if showtime.is_integer():
|
||||
if isinstance(showtime, int):
|
||||
rowdata = [time.strftime('%Y-%m-%dT%H:%M:%S'), nodekey]
|
||||
else:
|
||||
rowdata = [time.strftime('%Y-%m-%dT%H:%M:%S.') +
|
||||
@@ -199,7 +202,11 @@ def main():
|
||||
orderedsensors.append(name)
|
||||
orderedsensors.sort()
|
||||
for name in orderedsensors:
|
||||
headernames.append(sensorheaders[name])
|
||||
headername = sensorheaders[name]
|
||||
if (not isinstance(headername, str) and
|
||||
not isinstance(headername, bytes)):
|
||||
headername = headername.encode('utf-8')
|
||||
headernames.append(headername)
|
||||
if options.csv:
|
||||
linebyline = False
|
||||
csvwriter = csv.writer(sys.stdout)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2015 Lenovo
|
||||
@@ -43,7 +43,10 @@ argparser.add_option('-p', '--persist', dest='persist', action='store_true',
|
||||
argparser.add_option('-u', '--uefi', dest='uefi', action='store_true',
|
||||
default=True,
|
||||
help='Request UEFI style boot (rather than BIOS)')
|
||||
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to modify next boot device, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
|
||||
try:
|
||||
@@ -63,6 +66,7 @@ if options.biosmode:
|
||||
bootmode = 'bios'
|
||||
else:
|
||||
bootmode = 'uefi'
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
sys.exit(session.simple_noderange_command(noderange, '/boot/nextdevice', bootdev,
|
||||
bootmode=bootmode,
|
||||
persistent=options.persist))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2016-2017 Lenovo
|
||||
@@ -46,6 +46,12 @@ def run():
|
||||
help='Number of commands to run at a time')
|
||||
argparser.add_option('-n', '--nonodeprefix', action='store_true',
|
||||
help='Do not prefix output with node names')
|
||||
argparser.add_option('-p', '--port', type='int', default=0,
|
||||
help='Specify a custom port for ssh')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to run remote ssh command to, '
|
||||
'prompting if over the threshold')
|
||||
# among other things, FD_SETSIZE limits. Besides, spawning too many
|
||||
# processes can be unkind for the unaware on memory pressure and such...
|
||||
argparser.disable_interspersed_args()
|
||||
@@ -64,7 +70,7 @@ def run():
|
||||
pendingexecs = deque()
|
||||
exitcode = 0
|
||||
|
||||
|
||||
c.stop_if_noderange_over(args[0], options.maxnodes)
|
||||
for exp in c.create('/noderange/{0}/attributes/expression'.format(args[0]),
|
||||
{'expression': cmdstr}):
|
||||
if 'error' in exp:
|
||||
@@ -72,8 +78,13 @@ def run():
|
||||
exitcode |= exp.get('errorcode', 1)
|
||||
ex = exp.get('databynode', ())
|
||||
for node in ex:
|
||||
cmd = ex[node]['value'].encode('utf-8')
|
||||
cmdv = ['ssh', node, cmd]
|
||||
cmd = ex[node]['value']
|
||||
if not isinstance(cmd, str) and not isinstance(cmd, bytes):
|
||||
cmd = cmd.encode('utf-8')
|
||||
if options.port:
|
||||
cmdv = ['ssh', '-p', '{0}'.format(options.port), node, cmd]
|
||||
else:
|
||||
cmdv = ['ssh', node, cmd]
|
||||
if currprocs < concurrentprocs:
|
||||
currprocs += 1
|
||||
run_cmdv(node, cmdv, all, pipedesc)
|
||||
@@ -96,6 +107,7 @@ def run():
|
||||
pernodeout[node] = []
|
||||
pernodeout[node].append(data)
|
||||
else:
|
||||
data = client.stringify(data)
|
||||
if options.nonodeprefix:
|
||||
sys.stderr.write(data)
|
||||
else:
|
||||
@@ -113,6 +125,7 @@ def run():
|
||||
run_cmdv(node, cmdv, all, pipedesc)
|
||||
for node in sortutil.natural_sort(pernodeout):
|
||||
for line in pernodeout[node]:
|
||||
line = client.stringify(line)
|
||||
if options.nonodeprefix:
|
||||
sys.stdout.write(line)
|
||||
else:
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2018 Lenovo
|
||||
@@ -63,10 +63,16 @@ def _print_cfg(scfg):
|
||||
sys.stderr.write(e['error'] + '\n')
|
||||
exitcode = e.get('errorcode', 1)
|
||||
for node in e.get('databynode', {}):
|
||||
curr = e['databynode'][node]
|
||||
if 'error' in curr:
|
||||
if 'no available drives' in curr['error']:
|
||||
curr['error'] += ' (drives must be in unconfigured state to be available, they must not be in jbod or online state)'
|
||||
sys.stderr.write('{0}: {1}\n'.format(node, curr['error']))
|
||||
exitcode = curr.get('errorcode', 1)
|
||||
continue
|
||||
if node not in storagebynode:
|
||||
storagebynode[node] = {'disks': [], 'arrays': [],
|
||||
'volumes': []}
|
||||
curr = e['databynode'][node]
|
||||
storagebynode[node][curr['type'] + 's'].append(curr)
|
||||
for node in storagebynode:
|
||||
for disk in sorted(storagebynode[node]['disks'],
|
||||
@@ -108,6 +114,7 @@ def createstorage(noderange, options, args):
|
||||
sys.stderr.write('-r and -d are required arguments to create array\n')
|
||||
sys.exit(1)
|
||||
session = client.Command()
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
names = options.name
|
||||
if names is None:
|
||||
names = ''.join(args)
|
||||
@@ -132,6 +139,7 @@ def deletestorage(noderange, options, args):
|
||||
else:
|
||||
names = options.name
|
||||
session = client.Command()
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
for rsp in session.delete(
|
||||
'/noderange/{0}/configuration/storage/volumes/{1}'.format(
|
||||
noderange, names)):
|
||||
@@ -162,6 +170,7 @@ def setdisk(noderange, options, args):
|
||||
sys.stderr.write('diskset requires valid state as argument (hotspare, jbod, unconfigured)\n')
|
||||
sys.exit(1)
|
||||
session = client.Command()
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
scfg = session.update('/noderange/{0}/configuration/storage/disks/{1}'.format(noderange, names), {'state': args[0]})
|
||||
_print_cfg(scfg)
|
||||
|
||||
@@ -202,6 +211,10 @@ def main():
|
||||
help='Comma separated list of stripsizes to use when creating volumes. '
|
||||
'This value is in kilobytes. The default behavior is to allow the '
|
||||
'storage controller to decide.')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to configure storage on, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
if len(args) == 1:
|
||||
args.append('show')
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2018 Lenovo
|
||||
@@ -64,7 +64,7 @@ def printerror(res, node=None):
|
||||
|
||||
|
||||
|
||||
def download_servicedata(noderange, media):
|
||||
def download_servicedata(noderange, media, options):
|
||||
global exitcode
|
||||
session = client.Command()
|
||||
output = sq.ScreenPrinter(noderange, session)
|
||||
@@ -73,6 +73,7 @@ def download_servicedata(noderange, media):
|
||||
upargs = {'filename': filename}
|
||||
noderrs = {}
|
||||
nodeurls = {}
|
||||
session.stop_if_noderange_over(noderange, options.maxnodes)
|
||||
for res in session.create(resource, upargs):
|
||||
if 'created' not in res:
|
||||
for nodename in res.get('databynode', ()):
|
||||
@@ -121,6 +122,10 @@ def main():
|
||||
'management server (the confluent server if running remote, '
|
||||
'and the collective.manager if in collective)\n'
|
||||
'\n\nSee `man %prog` for more info.\n')
|
||||
argparser.add_option('-m', '--maxnodes', type='int',
|
||||
help='Specify a maximum number of '
|
||||
'nodes to download diagnostic data from, '
|
||||
'prompting if over the threshold')
|
||||
(options, args) = argparser.parse_args()
|
||||
media = None
|
||||
try:
|
||||
@@ -142,6 +147,6 @@ def main():
|
||||
except KeyError:
|
||||
argparser.print_help()
|
||||
sys.exit(1)
|
||||
handler(noderange, media)
|
||||
handler(noderange, media, options)
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
main()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2019 Lenovo
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# vim: tabstop=4 shiftwidth=4 softtabstop=4
|
||||
|
||||
# Copyright 2014 IBM Corporation
|
||||
# Copyright 2015-2018 Lenovo
|
||||
# Copyright 2015-2019 Lenovo
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -39,6 +39,19 @@ _attraliases = {
|
||||
'bmcpass': 'secret.hardwaremanagementpassword',
|
||||
}
|
||||
|
||||
try:
|
||||
input = raw_input
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
def stringify(instr):
|
||||
# Normalize unicode and bytes to 'str', correcting for
|
||||
# current python version
|
||||
if isinstance(instr, bytes) and not isinstance(instr, str):
|
||||
return instr.decode('utf-8')
|
||||
elif not isinstance(instr, bytes) and not isinstance(instr, str):
|
||||
return instr.encode('utf-8')
|
||||
return instr
|
||||
|
||||
class Tabulator(object):
|
||||
def __init__(self, headers):
|
||||
@@ -107,7 +120,10 @@ def printerror(res, node=None):
|
||||
|
||||
|
||||
def cprint(txt):
|
||||
print(txt)
|
||||
try:
|
||||
print(txt)
|
||||
except UnicodeEncodeError:
|
||||
print(txt.encode('utf8'))
|
||||
sys.stdout.flush()
|
||||
|
||||
def _parseserver(string):
|
||||
@@ -207,7 +223,7 @@ class Command(object):
|
||||
return rc
|
||||
|
||||
def simple_noderange_command(self, noderange, resource, input=None,
|
||||
key=None, errnodes=None, **kwargs):
|
||||
key=None, errnodes=None, promptover=None, **kwargs):
|
||||
try:
|
||||
self._currnoderange = noderange
|
||||
rc = 0
|
||||
@@ -223,6 +239,7 @@ class Command(object):
|
||||
noderange, resource)):
|
||||
rc = self.handle_results(ikey, rc, res, errnodes)
|
||||
else:
|
||||
self.stop_if_noderange_over(noderange, promptover)
|
||||
kwargs[ikey] = input
|
||||
for res in self.update('/noderange/{0}/{1}'.format(
|
||||
noderange, resource), kwargs):
|
||||
@@ -232,6 +249,33 @@ class Command(object):
|
||||
except KeyboardInterrupt:
|
||||
cprint('')
|
||||
return 0
|
||||
|
||||
def stop_if_noderange_over(self, noderange, maxnodes):
|
||||
if maxnodes is None:
|
||||
return
|
||||
nsize = self.get_noderange_size(noderange)
|
||||
if nsize > maxnodes:
|
||||
if nsize == 1:
|
||||
nodename = list(self.read(
|
||||
'/noderange/{0}/nodes/'.format(noderange)))[0].get('item', {}).get('href', None)
|
||||
nodename = nodename[:-1]
|
||||
p = input('Command is about to affect node {0}, continue (y/n)? '.format(nodename))
|
||||
else:
|
||||
p = input('Command is about to affect {0} nodes, continue (y/n)? '.format(nsize))
|
||||
if p.lower() != 'y':
|
||||
sys.stderr.write('Aborting at user request\n')
|
||||
sys.exit(1)
|
||||
raise Exception("Aborting at user request")
|
||||
|
||||
|
||||
def get_noderange_size(self, noderange):
|
||||
numnodes = 0
|
||||
for node in self.read('/noderange/{0}/nodes/'.format(noderange)):
|
||||
if node.get('item', {}).get('href', None):
|
||||
numnodes += 1
|
||||
else:
|
||||
raise Exception("Error trying to size noderange {0}".format(noderange))
|
||||
return numnodes
|
||||
|
||||
def simple_nodegroups_command(self, noderange, resource, input=None, key=None, **kwargs):
|
||||
try:
|
||||
@@ -332,12 +376,8 @@ class Command(object):
|
||||
if fingerprint == khf[hostid]:
|
||||
return
|
||||
else:
|
||||
try:
|
||||
replace = raw_input(
|
||||
"MISMATCHED CERTIFICATE DATA, ACCEPT NEW? (y/n):")
|
||||
except NameError:
|
||||
replace = input(
|
||||
"MISMATCHED CERTIFICATE DATA, ACCEPT NEW? (y/n):")
|
||||
replace = input(
|
||||
"MISMATCHED CERTIFICATE DATA, ACCEPT NEW? (y/n):")
|
||||
if replace not in ('y', 'Y'):
|
||||
raise Exception("BAD CERTIFICATE")
|
||||
cprint('Adding new key for %s:%s' % (server, port))
|
||||
@@ -389,8 +429,12 @@ def printattributes(session, requestargs, showtype, nodetype, noderange, options
|
||||
path = '/{0}/{1}/attributes/{2}'.format(nodetype, noderange, showtype)
|
||||
return print_attrib_path(path, session, requestargs, options)
|
||||
|
||||
def _sort_attrib(k):
|
||||
if isinstance(k[1], dict) and k[1].get('sortid', None) is not None:
|
||||
return k[1]['sortid']
|
||||
return k[0]
|
||||
|
||||
def print_attrib_path(path, session, requestargs, options, rename=None):
|
||||
def print_attrib_path(path, session, requestargs, options, rename=None, attrprefix=None):
|
||||
exitcode = 0
|
||||
seenattributes = set([])
|
||||
for res in session.read(path):
|
||||
@@ -399,9 +443,7 @@ def print_attrib_path(path, session, requestargs, options, rename=None):
|
||||
exitcode = 1
|
||||
continue
|
||||
for node in sorted(res['databynode']):
|
||||
for attr, val in sorted(
|
||||
res['databynode'][node].items(),
|
||||
key=lambda k: k[1].get('sortid', k[0]) if isinstance(k[1], dict) else k[0]):
|
||||
for attr, val in sorted(res['databynode'][node].items(), key=_sort_attrib):
|
||||
if attr == 'error':
|
||||
sys.stderr.write('{0}: Error: {1}\n'.format(node, val))
|
||||
continue
|
||||
@@ -413,6 +455,8 @@ def print_attrib_path(path, session, requestargs, options, rename=None):
|
||||
printattr = rename.get(attr, attr)
|
||||
else:
|
||||
printattr = attr
|
||||
if attrprefix:
|
||||
printattr = attrprefix + printattr
|
||||
currattr = res['databynode'][node][attr]
|
||||
if show_attr(attr, requestargs, seenattributes, options):
|
||||
if 'value' in currattr:
|
||||
|
||||
@@ -25,6 +25,11 @@ try:
|
||||
except NameError:
|
||||
unicode = str
|
||||
|
||||
try:
|
||||
range = xrange
|
||||
except NameError:
|
||||
pass
|
||||
|
||||
def decodestr(value):
|
||||
ret = None
|
||||
try:
|
||||
@@ -40,7 +45,7 @@ def decodestr(value):
|
||||
|
||||
def unicode_dictvalues(dictdata):
|
||||
for key in dictdata:
|
||||
if isinstance(dictdata[key], str):
|
||||
if isinstance(dictdata[key], bytes):
|
||||
dictdata[key] = decodestr(dictdata[key])
|
||||
elif isinstance(dictdata[key], datetime):
|
||||
dictdata[key] = dictdata[key].strftime('%Y-%m-%dT%H:%M:%S')
|
||||
@@ -51,7 +56,7 @@ def unicode_dictvalues(dictdata):
|
||||
|
||||
|
||||
def _unicode_list(currlist):
|
||||
for i in xrange(len(currlist)):
|
||||
for i in range(len(currlist)):
|
||||
if isinstance(currlist[i], str):
|
||||
currlist[i] = decodestr(currlist[i])
|
||||
elif isinstance(currlist[i], dict):
|
||||
@@ -66,7 +71,7 @@ def send(handle, data):
|
||||
data = data.encode('utf-8')
|
||||
except AttributeError:
|
||||
pass
|
||||
if isinstance(data, str) or isinstance(data, unicode):
|
||||
if isinstance(data, bytes) or isinstance(data, unicode):
|
||||
# plain text, e.g. console data
|
||||
tl = len(data)
|
||||
if tl == 0:
|
||||
|
||||
@@ -24,10 +24,18 @@ a confluent server.
|
||||
%setup -n %{name}-%{version} -n %{name}-%{version}
|
||||
|
||||
%build
|
||||
python setup.py build
|
||||
%if "%{dist}" == ".el8"
|
||||
python3 setup.py build
|
||||
%else
|
||||
python2 setup.py build
|
||||
%endif
|
||||
|
||||
%install
|
||||
python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
|
||||
%if "%{dist}" == ".el8"
|
||||
python3 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
|
||||
%else
|
||||
python2 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-scripts=/opt/confluent/bin --install-purelib=/opt/confluent/lib/python
|
||||
%endif
|
||||
|
||||
|
||||
%clean
|
||||
|
||||
@@ -19,6 +19,7 @@ alias nodebmcreset='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export
|
||||
alias nodeboot='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeboot'
|
||||
alias nodeconfig='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeconfig'
|
||||
alias nodeconsole='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeconsole'
|
||||
alias nodedeploy='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodedeploy'
|
||||
alias nodedefine='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodedefine'
|
||||
alias nodeeventlog='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodeeventlog'
|
||||
alias nodefirmware='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export CURRENT_CMDLINE; nodefirmware'
|
||||
@@ -46,9 +47,8 @@ alias nodelicense='CURRENT_CMDLINE=$(HISTTIMEFORMAT= builtin history 1); export
|
||||
_confluent_get_args()
|
||||
{
|
||||
CMPARGS=($COMP_LINE)
|
||||
NUMARGS=${#CMPARGS[@]}
|
||||
if [ "${COMP_WORDS[-1]}" == '' ]; then
|
||||
NUMARGS=$((NUMARGS+1))
|
||||
NUMARGS=$((COMP_CWORD+1))
|
||||
if [ "${COMP_WORDS[COMP_CWORD]}" == '' ]; then
|
||||
CMPARGS+=("")
|
||||
fi
|
||||
GENNED=""
|
||||
@@ -75,7 +75,7 @@ function _confluent_generic_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS -ge 3 ] && [ ! -z "$GENNED" ]; then
|
||||
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
fi
|
||||
if [ $NUMARGS -lt 3 ]; then
|
||||
_confluent_nr_completion
|
||||
@@ -84,7 +84,7 @@ function _confluent_generic_completion()
|
||||
}
|
||||
_confluent_nodeidentify_completion()
|
||||
{
|
||||
COMP_CANDIDATES=("on,off -h")
|
||||
COMP_CANDIDATES=("on,off,blink -h")
|
||||
_confluent_generic_completion
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ _confluent_nodemedia_completion()
|
||||
return
|
||||
fi
|
||||
if [ $NUMARGS -ge 3 ] && [ ! -z "$GENNED" ]; then
|
||||
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -W "$GENNED" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return;
|
||||
fi
|
||||
if [ $NUMARGS -lt 3 ]; then
|
||||
@@ -124,7 +124,7 @@ _confluent_nodefirmware_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS == 3 ]; then
|
||||
COMPREPLY=($(compgen -W "list update" -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -W "list update" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return;
|
||||
fi
|
||||
if [ $NUMARGS -gt 3 ] && [ ${CMPARGS[2]} == 'update' ]; then
|
||||
@@ -138,11 +138,39 @@ _confluent_nodefirmware_completion()
|
||||
fi
|
||||
}
|
||||
|
||||
_confluent_osimage_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS == 2 ]; then
|
||||
COMPREPLY=($(compgen -W "initialize import" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return
|
||||
elif [ ${CMPARGS[1]} == 'initialize' ]; then
|
||||
COMPREPLY=($(compgen -W "-h -u -s -t -i" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
elif [ ${CMPARGS[1]} == 'import' ]; then
|
||||
compopt -o default
|
||||
COMPREPLY=()
|
||||
return
|
||||
fi
|
||||
}
|
||||
|
||||
_confluent_nodedeploy_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS -gt 2 ]; then
|
||||
COMPREPLY=($(compgen -W "-n $(confetty show /deployment/profiles|sed -e 's/\///')" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
return
|
||||
fi
|
||||
if [ $NUMARGS -lt 3 ]; then
|
||||
_confluent_nr_completion
|
||||
return;
|
||||
fi
|
||||
}
|
||||
|
||||
_confluent_nodeshell_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS == 3 ]; then
|
||||
COMPREPLY=($(compgen -c -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -c -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return
|
||||
fi
|
||||
if [ $NUMARGS -gt 3 ]; then
|
||||
@@ -160,7 +188,7 @@ _confluent_nodelicense_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS == 3 ]; then
|
||||
COMPREPLY=($(compgen -W "install list save delete" -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -W "install list save delete" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return;
|
||||
fi
|
||||
if [ $NUMARGS == 4 ] && [ ${CMPARGS[2]} == 'install' ]; then
|
||||
@@ -183,7 +211,7 @@ _confluent_nodesupport_completion()
|
||||
{
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS == 3 ]; then
|
||||
COMPREPLY=($(compgen -W "servicedata" -- ${COMP_WORDS[-1]}))
|
||||
COMPREPLY=($(compgen -W "servicedata" -- ${COMP_WORDS[COMP_CWORD]}))
|
||||
return;
|
||||
fi
|
||||
if [ $NUMARGS == 4 ] && [ ${CMPARGS[2]} == 'servicedata' ]; then
|
||||
@@ -210,41 +238,36 @@ _confluent_nn_completion()
|
||||
if [ $NUMARGS -gt 2 ]; then
|
||||
return;
|
||||
fi
|
||||
INPUT=${COMP_WORDS[-1]}
|
||||
INPUT=${COMP_WORDS[COMP_CWORD]}
|
||||
INPUT=${INPUT##*,-}
|
||||
INPUT=${INPUT##*,}
|
||||
INPUT=${INPUT##*@}
|
||||
PREFIX=""
|
||||
if [ "$INPUT" != "${COMP_WORDS[-1]}" ]; then
|
||||
PREFIX=${COMP_WORDS[-1]}
|
||||
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
|
||||
PREFIX=${COMP_WORDS[COMP_CWORD]}
|
||||
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
|
||||
fi
|
||||
|
||||
COMPREPLY=($(compgen -W "$(nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[-1]}"))
|
||||
COMPREPLY=($(compgen -W "$(nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
}
|
||||
_confluent_nr_completion()
|
||||
{
|
||||
CMPARGS=($COMP_LINE)
|
||||
NUMARGS=${#CMPARGS[@]}
|
||||
if [ "${COMP_WORDS[-1]}" == '' ]; then
|
||||
NUMARGS=$((NUMARGS+1))
|
||||
fi
|
||||
_confluent_get_args
|
||||
if [ $NUMARGS -gt 2 ]; then
|
||||
return;
|
||||
fi
|
||||
INPUT=${COMP_WORDS[-1]}
|
||||
INPUT=${COMP_WORDS[COMP_CWORD]}
|
||||
INPUT=${INPUT##*,-}
|
||||
INPUT=${INPUT##*,}
|
||||
INPUT=${INPUT##*@}
|
||||
PREFIX=""
|
||||
if [ "$INPUT" != "${COMP_WORDS[-1]}" ]; then
|
||||
PREFIX=${COMP_WORDS[-1]}
|
||||
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
|
||||
PREFIX=${COMP_WORDS[COMP_CWORD]}
|
||||
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
|
||||
fi
|
||||
|
||||
#COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/;nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[-1]}"))
|
||||
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/;nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[-1]}"))
|
||||
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/;nodelist | sed -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
}
|
||||
_confluent_ng_completion()
|
||||
{
|
||||
@@ -252,17 +275,17 @@ _confluent_ng_completion()
|
||||
if [ $NUMARGS -gt 2 ]; then
|
||||
return;
|
||||
fi
|
||||
INPUT=${COMP_WORDS[-1]}
|
||||
INPUT=${COMP_WORDS[COMP_CWORD]}
|
||||
INPUT=${INPUT##*,-}
|
||||
INPUT=${INPUT##*,}
|
||||
INPUT=${INPUT##*@}
|
||||
PREFIX=""
|
||||
if [ "$INPUT" != "${COMP_WORDS[-1]}" ]; then
|
||||
PREFIX=${COMP_WORDS[-1]}
|
||||
if [ "$INPUT" != "${COMP_WORDS[COMP_CWORD]}" ]; then
|
||||
PREFIX=${COMP_WORDS[COMP_CWORD]}
|
||||
PREFIX=$(echo $PREFIX | sed -e 's/,[^,@-]*$/,/' -e 's/,-[^,@]*$/,-/' -e 's/@[^,@]*/@/')
|
||||
fi
|
||||
|
||||
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/)" -- "${COMP_WORDS[-1]}"))
|
||||
COMPREPLY=($(compgen -W "$(confetty show /nodegroups|sed -e 's/\///' -e s/^/$PREFIX/)" -- "${COMP_WORDS[COMP_CWORD]}"))
|
||||
}
|
||||
complete -F _confluent_nodeattrib_completion nodeattrib
|
||||
complete -F _confluent_nodeattrib_completion nodegroupattrib
|
||||
@@ -272,12 +295,14 @@ complete -F _confluent_nr_completion nodeconfig
|
||||
complete -F _confluent_nn_completion nodeconsole
|
||||
complete -F _confluent_nr_completion nodeeventlog
|
||||
complete -F _confluent_nodefirmware_completion nodefirmware
|
||||
complete -F _confluent_nodedeploy_completion nodedeploy
|
||||
complete -F _confluent_osimage_completion osimage
|
||||
complete -F _confluent_ng_completion nodegroupattrib
|
||||
complete -F _confluent_ng_completion nodegroupremove
|
||||
complete -F _confluent_nr_completion nodehealth
|
||||
complete -F _confluent_nodeidentify_completion nodeidentify
|
||||
complete -F _confluent_nr_completion nodeinventory
|
||||
complete -F _confluent_nr_completion nodelist
|
||||
complete -F _confluent_nodeattrib_completion nodelist
|
||||
complete -F _confluent_nodemedia_completion nodemedia
|
||||
complete -F _confluent_nodepower_completion nodepower
|
||||
complete -F _confluent_nr_completion noderemove
|
||||
|
||||
+2
@@ -100,3 +100,5 @@ See nodegroupattrib(8) command on how to manage attributes on a group level.
|
||||
## SEE ALSO
|
||||
|
||||
nodegroupattrib(8), nodeattribexpressions(5)
|
||||
|
||||
## ATTRIBUTES
|
||||
@@ -22,6 +22,11 @@ given as a node expression, as documented in the man page for nodeattribexpressi
|
||||
If combined with `-x`, will show all differing values except those indicated
|
||||
by `-x`
|
||||
|
||||
* `-e`, `--extra`:
|
||||
Read settings that are generally not needed, but may be slow to retrieve.
|
||||
Notably this includes the IMM category of Lenovo systems. The most popular
|
||||
IMM settings are available through faster 'bmc' attributes.
|
||||
|
||||
* `-x`, `--exclude`:
|
||||
Rather than listing only the specified configuration parameters, list all
|
||||
attributes except for the specified ones
|
||||
|
||||
@@ -23,6 +23,9 @@ data may be filtered by various parameters, as denoted in the options below.
|
||||
**nodediscover assign** performs manual discovery, assigning an entry to a node
|
||||
identity or, using `-i`, using a csv file to assign nodes all at once. For
|
||||
example, a spreadsheet of serial numbers to desired node names could be used.
|
||||
Note that if you see that the host is unreachable, it may be due to the IP
|
||||
address on the endpoint having changed since last detected. In such a case, it
|
||||
may help to **clear** and try **assign** again.
|
||||
|
||||
**nodediscover rescan** requests the server to do an active sweep for new
|
||||
devices. Generally every effort is made to passively detect devices as they
|
||||
|
||||
@@ -13,7 +13,11 @@ nodefirmware(8) -- Report firmware information on confluent nodes
|
||||
will retrieve all firmware, but can be directed to fetch specific firmware by
|
||||
calling out the name of the firmware (e.g. uefi or xcc) or request reading only
|
||||
core firmware firmware by using the word 'core', which is generally a quicker
|
||||
operation.
|
||||
operation. Different hardwaremanagement.method indicated plugins may have
|
||||
different capabilities available. For example, the 'core' distinction may
|
||||
not be relevant to redfish. Additionally, the Lenovo XCC makes certain
|
||||
information available over IPMI that is not otherwise available (for example
|
||||
the FPGA version where applicable).
|
||||
|
||||
In the update form, it accepts a single file and attempts to update it using
|
||||
the out of band facilities. Firmware updates can end in one of three states:
|
||||
|
||||
+2
@@ -41,3 +41,5 @@ the attributes are set on the node versus a group to which a node belongs.
|
||||
## SEE ALSO
|
||||
|
||||
nodeattrib(8), nodeattribexpressions(5)
|
||||
|
||||
## ATTRIBUTES
|
||||
@@ -3,7 +3,7 @@ nodeidentify(8) -- Control the identify LED of confluent nodes
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`nodidentify <noderange> [on|off]`
|
||||
`nodidentify <noderange> [on|off|blink]`
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
@@ -13,6 +13,7 @@ options are supported:
|
||||
|
||||
* `on`: Turn on the identify LED
|
||||
* `off`: Turn off the identify LED
|
||||
* `blink`: Set the identify LED to blink (when supported by the system)
|
||||
|
||||
## EXAMPLES:
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@ The attribute name may use a wildcard:
|
||||
Commas can be used to indicate multiple nodes, and can mix and match any of the above primitives. The following can be a valid single noderange, combining any and all members of each comma separated component
|
||||
`n1,n2,rack1,storage,location.rack=9,~s1..,n20-n30`
|
||||
|
||||
Exclusions can be done by prepending a ‘-‘ before a portion of a noderange:
|
||||
Exclusions can be done by prepending a '-' before a portion of a noderange:
|
||||
`rack1,-n2`
|
||||
`compute,-rack1`
|
||||
`compute,-location.row=12`
|
||||
@@ -54,7 +54,7 @@ To indicate nodes that match multiple selections at once (set intersection), the
|
||||
For complex expressions, () may be used to indicate order of expanding the noderange to be explicit
|
||||
`rack1,-(console.logging=full@compute)`
|
||||
|
||||
Noderange syntax can also indicate ‘pagination’, or separating the nodes into well defined chunks. > is used to indicate how many nodes to display at a time, and < is used to indicate how many nodes to skip into a noderange:
|
||||
Noderange syntax can also indicate 'pagination', or separating the nodes into well defined chunks. > is used to indicate how many nodes to display at a time, and < is used to indicate how many nodes to skip into a noderange:
|
||||
`rack1>3<6`
|
||||
|
||||
The above would show the seventh through ninth nodes of the rack1 group. Like all other noderange operations, this may be combined with any of the above, but must appear as the very last operation. Ordering is done with a natural sort.
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
nodersync(8) -- Run rsync in parallel against a noderange
|
||||
=========================================================================
|
||||
|
||||
## SYNOPSIS
|
||||
|
||||
`nodersync <file/directorylist> <noderange>:<destination>`
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
Supervises execution of rsync to push files or a directory tree to the specified
|
||||
noderange. This will present progress as percentage for all nodes.
|
||||
|
||||
## OPTIONS
|
||||
|
||||
* `-m`:
|
||||
Specify maximum number of nodes for noderange max.
|
||||
|
||||
* `-c`:
|
||||
Specify how many rsync executions to do concurrently. If noderange
|
||||
exceeds the count, then excess nodes will wait until one of the
|
||||
active count completes.
|
||||
@@ -7,7 +7,7 @@ nodesupport(8) -- Utilities for interacting with vendor support
|
||||
|
||||
## DESCRIPTION
|
||||
|
||||
`nodesupport` provides capabilities associated with interactiong with support.
|
||||
`nodesupport` provides capabilities associated with interacting with support.
|
||||
Currently it only has the `servicedata` subcommand. `servicedata` takes
|
||||
an argument that is either a directory name (that can be used for a single node
|
||||
or multiple nodes) or a file name (only to be used with single node noderange).
|
||||
@@ -16,6 +16,9 @@ connects to the managed system, so it will download to the remote system if runn
|
||||
remotely and will download to the collective.manager indicated system if
|
||||
running in collective mode.
|
||||
|
||||
Note that due to vendor filename requirements, any filename may have vendor
|
||||
specific suffixes added to any file produced.
|
||||
|
||||
## EXAMPLES
|
||||
|
||||
* Download support data from a single node to a specific filename
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
#!/bin/sh
|
||||
cd `dirname $0`
|
||||
python3 addattribs.py || python2 addattribs.py
|
||||
cd `dirname $0`/doc/man
|
||||
mkdir -p ../../man/man1
|
||||
mkdir -p ../../man/man5
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
|
||||
# This is a sample python script for going through all observed mac addresses
|
||||
# and assuming they are BMC related and printing nodeattrib commands
|
||||
|
||||
@@ -22,10 +22,10 @@ This provides the modules common for both client and server
|
||||
%setup -n %{name}-%{version} -n %{name}-%{version}
|
||||
|
||||
%build
|
||||
python setup.py build
|
||||
python2 setup.py build
|
||||
|
||||
%install
|
||||
python setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-purelib=/opt/confluent/lib/python --install-scripts=/opt/confluent/bin
|
||||
python2 setup.py install --single-version-externally-managed -O1 --root=$RPM_BUILD_ROOT --record=INSTALLED_FILES --install-purelib=/opt/confluent/lib/python --install-scripts=/opt/confluent/bin
|
||||
|
||||
%clean
|
||||
rm -rf $RPM_BUILD_ROOT
|
||||
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
VERSION=`git describe|cut -d- -f 1`
|
||||
NUMCOMMITS=`git describe|cut -d- -f 2`
|
||||
if [ "$NUMCOMMITS" != "$VERSION" ]; then
|
||||
VERSION=$VERSION.dev$NUMCOMMITS.g`git describe|cut -d- -f 3`
|
||||
fi
|
||||
sed -e "s/#VERSION#/$VERSION/" confluent_osdeploy.spec.tmpl > confluent_osdeploy.spec
|
||||
cd ..
|
||||
tar Jcvf confluent_osdeploy.tar.xz confluent_osdeploy
|
||||
mv confluent_osdeploy.tar.xz ~/rpmbuild/SOURCES/
|
||||
cd -
|
||||
rpmbuild -ba confluent_osdeploy.spec
|
||||
@@ -0,0 +1,47 @@
|
||||
Name: confluent_osdeploy-x86_64
|
||||
Version: #VERSION#
|
||||
Release: 1
|
||||
Summary: OS Deployment support for confluent
|
||||
|
||||
License: Apache2
|
||||
URL: http://hpc.lenovo.com/
|
||||
Source0: confluent_osdeploy.tar.xz
|
||||
BuildArch: noarch
|
||||
Requires: confluent_ipxe mtools
|
||||
BuildRoot: /tmp
|
||||
|
||||
%description
|
||||
This contains support utilities for enabling deployment of x86_64 architecture systems
|
||||
|
||||
|
||||
%define debug_package %{nil}
|
||||
|
||||
%prep
|
||||
%setup -n confluent_osdeploy
|
||||
|
||||
%build
|
||||
mkdir -p opt/confluent/bin
|
||||
cd utils
|
||||
make all
|
||||
cp copernicus clortho autocons ../opt/confluent/bin
|
||||
cd ..
|
||||
for os in el8 suse15 ubuntu20.04; do
|
||||
mkdir ${os}out
|
||||
cd ${os}out
|
||||
cp -a ../opt .
|
||||
cp -a ../${os}/initramfs/* .
|
||||
find . | cpio -H newc -o > ../addons.cpio
|
||||
mv ../addons.cpio .
|
||||
cd ..
|
||||
done
|
||||
|
||||
%install
|
||||
for os in el8 suse15 ubuntu20.04; do
|
||||
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs
|
||||
mkdir -p %{buildroot}/opt/confluent/lib/osdeploy/$os/profiles
|
||||
cp ${os}out/addons.cpio %{buildroot}/opt/confluent/lib/osdeploy/$os/initramfs
|
||||
cp -a $os/profiles/* %{buildroot}/opt/confluent/lib/osdeploy/$os/profiles
|
||||
done
|
||||
|
||||
%files
|
||||
/opt/confluent/lib/osdeploy
|
||||
@@ -0,0 +1,15 @@
|
||||
#!/bin/bash
|
||||
echo -n "" >> /tmp/net.ifaces
|
||||
cat /tls/*.0 >> /etc/pki/tls/certs/ca-bundle.crt
|
||||
if ! grep console= /proc/cmdline >& /dev/null; then
|
||||
autocons=$(/opt/confluent/bin/autocons)
|
||||
if [ -n "$autocons" ]; then
|
||||
echo console=$autocons |sed -e 's!/dev/!!' >> /tmp/01-autocons.conf
|
||||
autocons=${autocons%,*}
|
||||
echo $autocons > /tmp/01-autocons.devnode
|
||||
echo "Detected firmware specified console at $(cat /tmp/01-autocons.conf)" > $autocons
|
||||
echo "Initializing auto detected console when installer starts" > $autocons
|
||||
fi
|
||||
fi
|
||||
. /lib/anaconda-lib.sh
|
||||
wait_for_kickstart
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/bin/sh
|
||||
[ -e /tmp/confluent.initq ] && return 0
|
||||
echo -n "" > /tmp/confluent.initq
|
||||
cd /sys/class/net
|
||||
for currif in *; do
|
||||
ip link set $currif up
|
||||
done
|
||||
cd -
|
||||
while ! grep MANAGER /tmp/confluent.info >& /dev/null; do
|
||||
/opt/confluent/bin/copernicus -t > /tmp/confluent.info
|
||||
done
|
||||
read ifidx <<EOF
|
||||
$(grep ^MANAGER /tmp/confluent.info|grep fe80|sed -e s/.*%//)
|
||||
EOF
|
||||
read mgr << EOF
|
||||
$(grep ^MANAGER /tmp/confluent.info|grep fe80|awk '{print $2}')
|
||||
EOF
|
||||
mgridx=${mgr#*%}
|
||||
ifname=$(ip link |grep ^$ifidx:|awk '{print $2}')
|
||||
ifname=${ifname%:}
|
||||
echo $ifname > /tmp/net.ifaces
|
||||
nodename=$(grep ^NODENAME /tmp/confluent.info|awk '{print $2}')
|
||||
#TODO: blkid --label <whatever> to find mounted api
|
||||
|
||||
if [ -z "$apikey" ]; then
|
||||
apikey=$(/opt/confluent/bin/clortho $nodename $mgr)
|
||||
fi
|
||||
oum=$(umask)
|
||||
umask 0077
|
||||
echo $apikey > /etc/confluent.apikey
|
||||
umask $oum
|
||||
mgr="[$mgr]"
|
||||
curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/deploycfg > /tmp/confluent.deploycfg
|
||||
|
||||
dnsdomain=$(grep ^dnsdomain: /tmp/confluent.deploycfg)
|
||||
dnsdomain=${dnsdomain#dnsdomain: }
|
||||
hostname=$nodename
|
||||
if [ ! -z "$dnsdomain" ] && [ "$dnsdomain" != "null" ]; then
|
||||
hostname=$hostname.$dnsdomain
|
||||
fi
|
||||
mgr=$(grep ^deploy_server: /tmp/confluent.deploycfg)
|
||||
mgr=${mgr#deploy_server: }
|
||||
profilename=$(grep ^profile: /tmp/confluent.deploycfg)
|
||||
profilename=${profilename#profile: }
|
||||
proto=$(grep ^protocol: /tmp/confluent.deploycfg)
|
||||
proto=${proto#protocol: }
|
||||
textconsole=$(grep ^textconsole: /tmp/confluent.deploycfg)
|
||||
textconsole=${textconsole#textconsole: }
|
||||
if [ $textconsole = "true" ] && ! grep console= /proc/cmdline > /dev/null; then
|
||||
autocons=$(cat /tmp/01-autocons.devnode)
|
||||
if [ ! -z "$autocons" ]; then
|
||||
echo Auto-configuring installed system to use text console
|
||||
echo Auto-configuring installed system to use text console > $autocons
|
||||
cp /tmp/01-autocons.conf /etc/cmdline.d/
|
||||
else
|
||||
echo "Unable to automatically detect requested text console"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo inst.repo=$proto://$mgr/confluent-public/os/$profilename/distribution >> /etc/cmdline.d/01-confluent.conf
|
||||
echo inst.ks=$proto://$mgr/confluent-public/os/$profilename/kickstart >> /etc/cmdline.d/01-confluent.conf
|
||||
kickstart=$proto://$mgr/confluent-public/os/$profilename/kickstart
|
||||
root=anaconda-net:$proto://$mgr/confluent-public/os/$profilename/distribution
|
||||
export kickstart
|
||||
export root
|
||||
autoconfigmethod=$(grep ipv4_method /tmp/confluent.deploycfg)
|
||||
autoconfigmethod=${autoconfigmethod#ipv4_method: }
|
||||
if [ "$autoconfigmethod" = "dhcp" ]; then
|
||||
echo ip=$ifname:dhcp >> /etc/cmdline.d/01-confluent.conf
|
||||
else
|
||||
v4addr=$(grep ^ipv4_address: /tmp/confluent.deploycfg)
|
||||
v4addr=${v4addr#ipv4_address: }
|
||||
v4gw=$(grep ^ipv4_gateway: /tmp/confluent.deploycfg)
|
||||
v4gw=${v4gw#ipv4_gateway: }
|
||||
if [ "$v4gw" = "null" ]; then
|
||||
v4gw=""
|
||||
fi
|
||||
v4nm=$(grep ipv4_netmask: /tmp/confluent.deploycfg)
|
||||
v4nm=${v4nm#ipv4_netmask: }
|
||||
echo ip=$v4addr::$v4gw:$v4nm:$hostname:$ifname:none >> /etc/cmdline.d/01-confluent.conf
|
||||
fi
|
||||
nameserversec=0
|
||||
while read -r entry; do
|
||||
if [ $nameserversec = 1 ]; then
|
||||
if [[ $entry == "-"* ]] && [[ $entry != "- ''" ]]; then
|
||||
echo nameserver=${entry#- } >> /etc/cmdline.d/01-confluent.conf
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
nameserversec=0
|
||||
if [ "${entry%:*}" = "nameservers" ]; then
|
||||
nameserversec=1
|
||||
continue
|
||||
fi
|
||||
done < /tmp/confluent.deploycfg
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/bash
|
||||
BUNDLENAME=/sysroot/etc/pki/tls/certs/ca-bundle.crt
|
||||
while [ -h $BUNDLENAME ]; do
|
||||
BUNDLENAME=/sysroot/$(readlink $BUNDLENAME)
|
||||
done
|
||||
|
||||
cat /etc/pki/tls/certs/ca-bundle.crt > $BUNDLENAME
|
||||
mkdir -p /sysroot/etc/confluent/
|
||||
cp -a /tls /sysroot/etc/confluent
|
||||
sed -i 's/install::/install:*:/' /sysroot/etc/shadow
|
||||
sed -i 's/root::/root:*:/' /sysroot/etc/shadow
|
||||
mkdir -p /sysroot/root/.ssh
|
||||
chmod 700 /sysroot/root/.ssh
|
||||
cat /ssh/*.rootpubkey > /sysroot/root/.ssh/authorized_keys
|
||||
chmod 600 /sysroot/root/.ssh/authorized_keys
|
||||
mkdir -p /sysroot/etc/ssh/
|
||||
for i in /ssh/*.ca; do
|
||||
echo '@cert-authority *' $(cat $i) >> /sysroot/etc/ssh/ssh_known_hosts
|
||||
done
|
||||
cp /etc/confluent.apikey /sysroot/etc/
|
||||
cp /etc/confluent.apikey /sysroot/etc/confluent/
|
||||
cp /tmp/confluent.deploycfg /tmp/confluent.info /sysroot/etc/
|
||||
cp /tmp/confluent.deploycfg /tmp/confluent.info /sysroot/etc/confluent
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
sed -i 's/centos/CentOS/; s/rhel/Red Hat Enterprise Linux/' $2/profile.yaml
|
||||
ln -s $1/images/pxeboot/vmlinuz $2/boot/kernel && \
|
||||
ln -s $1/images/pxeboot/initrd.img $2/boot/initramfs/distribution
|
||||
mkdir -p $2/boot/efi/boot && \
|
||||
ln -s $1/EFI/BOOT/BOOTX64.EFI $1/EFI/BOOT/grubx64.efi $2/boot/efi/boot/
|
||||
|
||||
@@ -0,0 +1,65 @@
|
||||
# In this OS profile, data is largely filled in during the %pre
|
||||
# phase, rather than the kickstart actually having the content.
|
||||
# None of the files shall be replaced during an upgrade in
|
||||
# /var/lib/confluent/public/os/<profile>, so customization should
|
||||
# be done by modifying files in /var/lib/confluent/public/os/<profile>
|
||||
|
||||
# /tmp/rootpw will provide a 'rootpw' line, either locking password if not configured
|
||||
# or the crypted form.
|
||||
%include /tmp/rootpw
|
||||
|
||||
# timezone is fetched from confluent server, which provides the
|
||||
# timezone that the management server itself is in by default.
|
||||
%include /tmp/timezone
|
||||
|
||||
# similar to timezone, confluent is asked to provide the
|
||||
# deployment servers language info and replicate that
|
||||
# to the deployment target.
|
||||
%include /tmp/langinfo
|
||||
|
||||
# The default partition scheme is applied to a single drive, using
|
||||
# the getinstalldisk script to make a best guess as to the most
|
||||
# appropriate device. See pre.sh and getinstalldisk to customize
|
||||
# the automatic behavior, or comment out/delete the
|
||||
# following line and provide your own manual partition plan
|
||||
# instead
|
||||
%include /tmp/partitioning
|
||||
|
||||
reboot
|
||||
|
||||
%packages
|
||||
@^minimal-environment
|
||||
chrony
|
||||
rsync
|
||||
python3
|
||||
%end
|
||||
|
||||
%pre
|
||||
profile=$(grep ^profile: /etc/confluent.deploycfg |awk '{print $2}')
|
||||
mgr=$(grep deploy_server /etc/confluent.deploycfg |awk '{print $2}')
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/pre.sh > /tmp/preinst.sh
|
||||
. /tmp/preinst.sh
|
||||
%end
|
||||
|
||||
%post --nochroot
|
||||
mkdir -p /mnt/sysimage/etc/confluent
|
||||
profile=$(grep ^profile: /etc/confluent.deploycfg |awk '{print $2}')
|
||||
mgr=$(grep deploy_server /etc/confluent.deploycfg |awk '{print $2}')
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/prechroot.sh > /tmp/postinst.sh
|
||||
. /tmp/postinst.sh
|
||||
|
||||
# Hook firstboot.sh
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/firstboot.service > /mnt/sysimage/etc/systemd/system/firstboot.service
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/firstboot.sh > /mnt/sysimage/etc/confluent/firstboot.sh
|
||||
chmod +x /mnt/sysimage/etc/confluent/firstboot.sh
|
||||
%end
|
||||
|
||||
%post
|
||||
systemctl enable firstboot
|
||||
chgrp ssh_keys /etc/ssh/ssh*key
|
||||
restorecon /etc/ssh/ssh*key /root/.shosts /etc/ssh/shosts.equiv /etc/ssh/ssh_config.d/* /etc/confluent/firstboot.sh
|
||||
profile=$(grep ^profile: /etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
mgr=$(grep deploy_server /etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/post.sh > /tmp/postinst.sh
|
||||
. /tmp/postinst.sh
|
||||
%end
|
||||
@@ -0,0 +1,2 @@
|
||||
label: %%DISTRO%% %%VERSION%% %%ARCH%% (Default Profile)
|
||||
kernelargs: quiet
|
||||
@@ -0,0 +1,11 @@
|
||||
[Unit]
|
||||
Description=First Boot Process
|
||||
Requires=network-online.target
|
||||
After=network-online.target
|
||||
|
||||
[Service]
|
||||
ExecStart=/etc/confluent/firstboot.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
|
||||
apikey=$(cat /etc/confluent/confluent.apikey)
|
||||
mgr=$(grep deploy_server /etc/confluent/confluent.deploycfg|awk '{print $2}')
|
||||
curl --capath /etc/confluent/tls -X POST -d 'status: complete' -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/updatestatus
|
||||
systemctl disable firstboot
|
||||
rm /etc/systemd/system/firstboot.service
|
||||
@@ -0,0 +1,14 @@
|
||||
run_remote() {
|
||||
cd $(mktemp -d)
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/$1 > $1
|
||||
chmod +x $1
|
||||
./$1
|
||||
cd -
|
||||
}
|
||||
|
||||
run_remote_python() {
|
||||
cd $(mktemp -d)
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/$1 > $1
|
||||
/usr/libexec/platform-python $1
|
||||
cd -
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
class DiskInfo(object):
|
||||
def __init__(self, devname):
|
||||
self.name = devname
|
||||
self.wwn = None
|
||||
self.path = None
|
||||
self.model = ''
|
||||
self.size = 0
|
||||
self.driver = None
|
||||
self.mdcontainer = ''
|
||||
devnode = '/dev/{0}'.format(devname)
|
||||
qprop = subprocess.check_output(
|
||||
['udevadm', 'info', '--query=property', devnode])
|
||||
if not isinstance(qprop, str):
|
||||
qprop = qprop.decode('utf8')
|
||||
for prop in qprop.split('\n'):
|
||||
if '=' not in prop:
|
||||
continue
|
||||
k, v = prop.split('=', 1)
|
||||
if k == 'DEVTYPE' and v != 'disk':
|
||||
raise Exception('Not a disk')
|
||||
elif k == 'DM_NAME':
|
||||
raise Exception('Device Mapper')
|
||||
elif k == 'ID_MODEL':
|
||||
self.model = v
|
||||
elif k == 'DEVPATH':
|
||||
self.path = v
|
||||
elif k == 'ID_WWN':
|
||||
self.wwn = v
|
||||
elif k == 'MD_CONTAINER':
|
||||
self.mdcontainer = v
|
||||
attrs = subprocess.check_output(['udevadm', 'info', '-a', devnode])
|
||||
if not isinstance(attrs, str):
|
||||
attrs = attrs.decode('utf8')
|
||||
for attr in attrs.split('\n'):
|
||||
if '==' not in attr:
|
||||
continue
|
||||
k, v = attr.split('==', 1)
|
||||
k = k.strip()
|
||||
if k == 'ATTRS{size}':
|
||||
self.size = v.replace('"', '')
|
||||
elif (k == 'DRIVERS' and not self.driver
|
||||
and v not in ('"sd"', '""')):
|
||||
self.driver = v.replace('"', '')
|
||||
if not self.driver and 'imsm' not in self.mdcontainer:
|
||||
raise Exception("No driver detected")
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
|
||||
return 0
|
||||
if 'imsm' in self.mdcontainer:
|
||||
return 1
|
||||
if self.driver == 'ahci':
|
||||
return 2
|
||||
if self.driver.startswith('megaraid'):
|
||||
return 3
|
||||
if self.driver.startswith('mpt'):
|
||||
return 4
|
||||
return 99
|
||||
|
||||
def __repr__(self):
|
||||
return repr({
|
||||
'name': self.name,
|
||||
'path': self.path,
|
||||
'wwn': self.wwn,
|
||||
'driver': self.driver,
|
||||
'size': self.size,
|
||||
'model': self.model,
|
||||
})
|
||||
|
||||
|
||||
def main():
|
||||
disks = []
|
||||
for disk in sorted(os.listdir('/sys/class/block')):
|
||||
try:
|
||||
disk = DiskInfo(disk)
|
||||
disks.append(disk)
|
||||
except Exception as e:
|
||||
print("Skipping {0}: {1}".format(disk, str(e)))
|
||||
nd = [x.name for x in sorted(disks, key=lambda x: x.priority)]
|
||||
if nd:
|
||||
open('/tmp/installdisk', 'w').write(nd[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
# need to copy over ssh key info
|
||||
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
|
||||
export mgr profile nodename
|
||||
. /etc/confluent/functions
|
||||
|
||||
# This script will execute in the installed system, but using the installer kernel prior to reboot.
|
||||
# This is an appropriate place to run post install activities that do not require the actual installed
|
||||
# kernel to run. For example adding drivers that would be needed for first boot to run cleanly.
|
||||
# If, for example, there is a post script that has a dependency on a driver or filesystem that
|
||||
# cannot work until booting into the installer, use firstboot.sh instead
|
||||
|
||||
# run_remote will download and execute from /var/lib/confluent/public/<os>/scripts/ directory
|
||||
# run_remote_python will use the appropriate python interpreter path to run the specified script
|
||||
|
||||
# Add content as below:
|
||||
|
||||
# run_remote example.sh
|
||||
# run_remote_python example.py
|
||||
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This runs prior to the installer beginning. This is used to rewrite the
|
||||
# scripted install file, merging data from confluennt and identifying
|
||||
# the most appropriate install source.
|
||||
|
||||
# If you want to use a more custom partition plan, the easiest
|
||||
# method is to edit the kicktstart file and comment out or
|
||||
# delete %include /tmp/partitioning
|
||||
|
||||
nodename=$(grep ^NODENAME /etc/confluent.info|awk '{print $2}')
|
||||
locale=$(grep ^locale: /etc/confluent.deploycfg)
|
||||
locale=${locale#locale: }
|
||||
keymap=$(grep ^keymap: /etc/confluent.deploycfg)
|
||||
keymap=${keymap#keymap: }
|
||||
echo lang $locale > /tmp/langinfo
|
||||
echo keyboard --vckeymap=$keymap >> /tmp/langinfo
|
||||
tz=$(grep ^timezone: /etc/confluent.deploycfg)
|
||||
tz=${tz#timezone: }
|
||||
echo timezone $tz --utc > /tmp/timezone
|
||||
rootpw=$(grep ^rootpassword /etc/confluent.deploycfg | awk '{print $2}')
|
||||
if [ "$rootpw" = null ]; then
|
||||
echo "rootpw --lock" > /tmp/rootpw
|
||||
else
|
||||
echo "rootpw --iscrypted $rootpw" > /tmp/rootpw
|
||||
fi
|
||||
for pubkey in /etc/ssh/ssh_host*key.pub; do
|
||||
certfile=${pubkey/.pub/-cert.pub}
|
||||
curl -f -X POST -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent.apikey)" -d @$pubkey https://$mgr/confluent-api/self/sshcert > $certfile
|
||||
echo HostCertificate $certfile >> /etc/ssh/sshd_config.anaconda
|
||||
done
|
||||
/usr/sbin/sshd -f /etc/ssh/sshd_config.anaconda
|
||||
if [ -f "/run/install/cmdline.d/01-autocons.conf" ]; then
|
||||
consoledev=$(cat /run/install/cmdline.d/01-autocons.conf | sed -e 's!console=!/dev/!' -e 's/,.*//')
|
||||
tmux a <> $consoledev >&0 2>&1 &
|
||||
fi
|
||||
export mgr profile nodename
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/functions > /tmp/functions
|
||||
. /tmp/functions
|
||||
run_remote_python getinstalldisk
|
||||
if [ -e /tmp/installdisk ]; then
|
||||
echo clearpart --all --initlabel >> /tmp/partitioning
|
||||
echo ignoredisk --only-use $(cat /tmp/installdisk) >> /tmp/partitioning
|
||||
echo autopart --nohome >> /tmp/partitioning
|
||||
fi
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script runs after install is complete, but inside the installer
|
||||
# environment. This is useful for carrying work done in pre/during the
|
||||
# installer into the installed environment.
|
||||
|
||||
# It is almost certainly more useful to use post.sh or firstboot.sh
|
||||
# for customization, which will run in a more normal mechanism
|
||||
|
||||
nodename=$(grep ^NODENAME /etc/confluent.info|awk '{print $2}')
|
||||
export mgr profile nodename
|
||||
cp -a /etc/confluent /mnt/sysimage/etc
|
||||
cp /tmp/functions /mnt/sysimage/etc/confluent/
|
||||
. /tmp/functions
|
||||
|
||||
# Preserve the ssh setup work done for the installer
|
||||
# by copying into the target system and setting up
|
||||
# host based authentication
|
||||
run_remote setupssh.sh
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
grep HostCert /etc/ssh/sshd_config.anaconda >> /mnt/sysimage/etc/ssh/sshd_config
|
||||
echo HostbasedAuthentication yes >> /mnt/sysimage/etc/ssh/sshd_config
|
||||
echo HostbasedUsesNameFromPacketOnly yes >> /mnt/sysimage/etc/ssh/sshd_config
|
||||
echo IgnoreRhosts no >> /mnt/sysimage/etc/ssh/sshd_config
|
||||
sshconf=/etc/ssh/ssh_config
|
||||
if [ -d /mnt/sysimage/etc/ssh/ssh_config.d/ ]; then
|
||||
sshconf=/mnt/sysimage/etc/ssh/ssh_config.d/01-confluent.conf
|
||||
fi
|
||||
echo 'Host *' >> $sshconf
|
||||
echo ' HostbasedAuthentication yes' >> $sshconf
|
||||
echo ' EnableSSHKeysign yes' >> $sshconf
|
||||
echo ' HostbasedKeyTypes *ed25519*' >> $sshconf
|
||||
|
||||
cp /etc/ssh/ssh_host_* /mnt/sysimage/etc/ssh/
|
||||
mkdir /mnt/sysimage/root/.ssh/
|
||||
chmod 700 /mnt/sysimage/root/.ssh/
|
||||
cp /root/.ssh/authorized_keys /mnt/sysimage/root/.ssh/
|
||||
chmod 600 /mnt/sysimage/root/.ssh/authorized_keys
|
||||
cp /etc/ssh/ssh_known_hosts /mnt/sysimage/etc/ssh/
|
||||
curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /etc/confluent.apikey)" https://$mgr/confluent-api/self/nodelist > /tmp/allnodes
|
||||
cp /tmp/allnodes /mnt/sysimage/etc/ssh/shosts.equiv
|
||||
cp /tmp/allnodes /mnt/sysimage/root/.shosts
|
||||
@@ -0,0 +1 @@
|
||||
Install: exec:/opt/confluent/bin/suseagent
|
||||
@@ -0,0 +1,106 @@
|
||||
#!/bin/bash
|
||||
echo "Installing certificates"
|
||||
echo '<authorized_keys xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns" config:type="list">' > /tmp/rootkeys.xml
|
||||
for pub in /ssh/*.rootpubkey; do
|
||||
echo '<listentry>'$(cat $pub)'</listentry>' >> /tmp/rootkeys.xml
|
||||
done
|
||||
echo '</authorized_keys>' >> /tmp/rootkeys.xml
|
||||
/usr/bin/cp /tls/*.0 /var/lib/ca-certificates/openssl/
|
||||
/usr/bin/cp /tls/*.0 /etc/ssl/certs/
|
||||
echo "LineMode: 1" > /etc/linuxrc.d/01-confluent
|
||||
autocons=""
|
||||
if ! grep console /proc/cmdline > /dev/null; then
|
||||
autocons=$(/opt/confluent/bin/autocons)
|
||||
if [ ! -z "$autocons" ]; then
|
||||
echo "Serial console detected from firmmware: $autocons" > ${autocons%,*}
|
||||
fi
|
||||
fi
|
||||
cd /sys/class/net
|
||||
for nic in *; do
|
||||
ip link set $nic up
|
||||
done
|
||||
echo -n "Discovering confluent..."
|
||||
/opt/confluent/bin/copernicus -t > /tmp/confluent.info
|
||||
while ! grep MANAGER: /tmp/confluent.info > /dev/null; do
|
||||
/opt/confluent/bin/copernicus -t > /tmp/confluent.info
|
||||
done
|
||||
nodename=$(grep ^NODENAME: /tmp/confluent.info | head -n 1 | sed -e 's/NODENAME: //')
|
||||
echo "done ($nodename)"
|
||||
echo "Hostname: $nodename" >> /etc/linuxrc.d/01-confluent
|
||||
mgr=$(grep ^MANAGER: /tmp/confluent.info | head -n 1 | sed -e 's/MANAGER: //')
|
||||
echo -n "Acquiring configuration from $mgr..."
|
||||
bootifidx=${mgr#*%}
|
||||
for nic in *; do
|
||||
if [ "$(cat $nic/ifindex)" = "$bootifidx" ]; then
|
||||
bootif=$nic
|
||||
fi
|
||||
done
|
||||
cd -
|
||||
echo "NetDevice: $bootif" >> /etc/linuxrc.d/01-confluent
|
||||
/opt/confluent/bin/clortho $nodename $mgr > /tmp/confluent.apikey
|
||||
mgr="[$mgr]"
|
||||
curl -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /tmp/confluent.apikey)" https://$mgr/confluent-api/self/deploycfg > /tmp/confluent.deploycfg
|
||||
dnsdomain=$(grep ^dnsdomain: /tmp/confluent.deploycfg)
|
||||
dnsdomain=${dnsdomain#dnsdomain: }
|
||||
if [ ! -z "$dnsdomain" ] && [ "$dnsdomain" != "null" ]; then
|
||||
echo "Domain: $dnsdomain" >> /etc/linuxrc.d/01-confluent
|
||||
fi
|
||||
textconsole=$(grep ^textconsole: /tmp/confluent.deploycfg)
|
||||
textconsole=${textconsole#textconsole: }
|
||||
if [ "$textconsole" = "true" ] && ! grep console= /proc/cmdline > /dev/null && [ ! -z "$autocons" ]; then
|
||||
echo "Serial console autodetected and enabled, will be available upon install completion" > ${autocons%,*}
|
||||
echo "The installer will run in text mode on the graphics console. When ssh is available," > ${autocons%,*}
|
||||
echo "install progress may be checked by using ssh to access and run the screendump command" > ${autocons%,*}
|
||||
echo "Install time serial console would require the profile to have console=${autocons#/dev/}" > ${autocons%,*}
|
||||
echo "specified in the kernel command line arguments" > ${autocons%,*}
|
||||
sed -e s'/$/ 'console=${autocons#*/dev/}/ /proc/cmdline > /etc/fakecmdline
|
||||
mount -o bind /etc/fakecmdline /proc/cmdline
|
||||
echo "ConsoleDevice: ${autocons%,*}" >> /etc/linuxrc.d/01-confluent
|
||||
fi
|
||||
|
||||
tz=$(grep timezone: /tmp/confluent.deploycfg | awk '{print $2}')
|
||||
echo "<timezone>${tz}</timezone>" > /tmp/timezone
|
||||
autoconfigmethod=$(grep ipv4_method /tmp/confluent.deploycfg)
|
||||
autoconfigmethod=${autoconfigmethod#ipv4_method: }
|
||||
if [ "$autoconfigmethod" = "dhcp" ]; then
|
||||
echo "DHCP: 1" >> /etc/linuxrc.d/01-confluent
|
||||
else
|
||||
v4addr=$(grep ^ipv4_address: /tmp/confluent.deploycfg)
|
||||
v4addr=${v4addr#ipv4_address: }
|
||||
v4gw=$(grep ^ipv4_gateway: /tmp/confluent.deploycfg)
|
||||
v4gw=${v4gw#ipv4_gateway: }
|
||||
v4nm=$(grep ipv4_netmask: /tmp/confluent.deploycfg)
|
||||
v4nm=${v4nm#ipv4_netmask: }
|
||||
echo "HostIP: $v4addr" >> /etc/linuxrc.d/01-confluent
|
||||
echo "Netmask: $v4nm" >> /etc/linuxrc.d/01-confluent
|
||||
if [ "$v4gw" != "null" ]; then
|
||||
echo "Gateway: $v4gw" >> /etc/linuxrc.d/01-confluent
|
||||
fi
|
||||
nameserversec=0
|
||||
while read -r entry; do
|
||||
if [ $nameserversec = 1 ]; then
|
||||
if [[ $entry == "-"* ]]; then
|
||||
echo Nameserver: ${entry#- } >> /etc/linuxrc.d/01-confluent
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
nameserversec=0
|
||||
if [ ${entry%:*} = "nameservers" ]; then
|
||||
nameserversec=1
|
||||
continue
|
||||
fi
|
||||
done < /tmp/confluent.deploycfg
|
||||
fi
|
||||
echo done
|
||||
mgr=$(grep ^deploy_server: /tmp/confluent.deploycfg)
|
||||
mgr=${mgr#deploy_server: }
|
||||
profilename=$(grep ^profile: /tmp/confluent.deploycfg)
|
||||
profilename=${profilename#profile: }
|
||||
proto=$(grep ^protocol: /tmp/confluent.deploycfg)
|
||||
proto=${proto#protocol: }
|
||||
|
||||
echo "<media_url>${proto}://${mgr}/confluent-public/os/${profilename}/product</media_url>" > /tmp/pkgurl
|
||||
|
||||
echo "AutoYaST: $proto://$mgr/confluent-public/os/$profilename/autoyast" >> /etc/linuxrc.d/01-confluent
|
||||
echo "Install: $proto://$mgr/confluent-public/os/$profilename/distribution/1" >> /etc/linuxrc.d/01-confluent
|
||||
exec /init
|
||||
@@ -0,0 +1,135 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE profile SYSTEM "/usr/share/YaST2/include/autoinstall/profile.dtd">
|
||||
<profile xmlns="http://www.suse.com/1.0/yast2ns" xmlns:config="http://www.suse.com/1.0/configns" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||
<general>
|
||||
<self_update config:type="boolean">false</self_update>
|
||||
<clock>
|
||||
<hwclock>UTC</hwclock>
|
||||
<xi:include href="file:///tmp/timezone"/>
|
||||
</clock>
|
||||
<mode>
|
||||
<confirm config:type="boolean">false</confirm>
|
||||
</mode>
|
||||
</general>
|
||||
%%IFSLE%%
|
||||
<add-on>
|
||||
<add_on_products config:type="list">
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>sle-module-basesystem</product><product_dir>/Module-Basesystem</product_dir></listentry>
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>sle-module-hpc</product><product_dir>/Module-HPC</product_dir></listentry>
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>sle-module-server-applications</product><product_dir>/Module-Server-Applications</product_dir></listentry>
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>sle-module-containers</product><product_dir>/Module-Containers</product_dir></listentry>
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>SLE_HPC</product><product_dir>/Product-HPC</product_dir></listentry>
|
||||
<listentry><xi:include href="file:///tmp/pkgurl"/><product>Legacy-Module</product><product_dir>/Module-Legacy</product_dir></listentry>
|
||||
</add_on_products>
|
||||
</add-on>
|
||||
%%ENDIFSLE%%
|
||||
<software>
|
||||
%%IFSLE%%
|
||||
<products config:type="list">
|
||||
<product>SLE_HPC</product>
|
||||
</products>
|
||||
%%ENDIFSLE%%
|
||||
<patterns config:type="list">
|
||||
<pattern>base</pattern>
|
||||
</patterns>
|
||||
<packages config:type="list">
|
||||
<package>openssl</package>
|
||||
<package>chrony</package>
|
||||
<package>rsync</package>
|
||||
<package>screen</package>
|
||||
<package>vim</package>
|
||||
<package>binutils</package>
|
||||
<package>pciutils</package>
|
||||
<package>usbutils</package>
|
||||
<package>nfs-client</package>
|
||||
<package>ethtool</package>
|
||||
</packages>
|
||||
</software>
|
||||
<partitioning config:type="list">
|
||||
<drive>
|
||||
<device>%%INSTDISK%%</device>
|
||||
<initialize config:type="boolean">true</initialize>
|
||||
<use>all</use>
|
||||
<partitions config:type="list">
|
||||
<partition>
|
||||
<filesystem config:type="symbol">xfs</filesystem>
|
||||
<mount>/</mount>
|
||||
<size>max</size>
|
||||
</partition>
|
||||
<partition>
|
||||
<mount>swap</mount>
|
||||
<size>auto</size>
|
||||
</partition>
|
||||
<partition>
|
||||
<mount>/boot</mount>
|
||||
<size>500M</size>
|
||||
</partition>
|
||||
</partitions>
|
||||
</drive>
|
||||
</partitioning>
|
||||
<users config:type="list">
|
||||
<user>
|
||||
<username>root</username>
|
||||
<user_password>%%ROOTPASSWORD%%</user_password>
|
||||
<encrypted config:type="boolean">true</encrypted>
|
||||
<xi:include href="file:///tmp/rootkeys.xml"/>
|
||||
</user>
|
||||
</users>
|
||||
<networking>
|
||||
<dns>
|
||||
<hostname>%%NODENAME%%</hostname>
|
||||
</dns>
|
||||
<keep_install_network config:type="boolean">true</keep_install_network>
|
||||
</networking>
|
||||
<services-manager>
|
||||
<services>
|
||||
<enable config:type="list">
|
||||
<service>sshd</service>
|
||||
</enable>
|
||||
</services>
|
||||
</services-manager>
|
||||
<scripts>
|
||||
<pre-scripts config:type="list">
|
||||
<script>
|
||||
<filename>preinstall.sh</filename>
|
||||
<interpreter>shell</interpreter>
|
||||
<source>
|
||||
<![CDATA[
|
||||
#!/bin/sh
|
||||
mgr=$(grep ^deploy_server /tmp/confluent.deploycfg|awk '{print $2}')
|
||||
profile=$(grep ^profile: /tmp/confluent.deploycfg|sed -e 's/^profile: //')
|
||||
proto=$(grep ^protocol: /tmp/confluent.deploycfg |awk '{print $2}')
|
||||
curl $proto://$mgr/confluent-public/os/$profile/scripts/pre.sh > /tmp/pre.sh
|
||||
. /tmp/pre.sh
|
||||
]]>
|
||||
</source>
|
||||
</script>
|
||||
</pre-scripts>
|
||||
<chroot-scripts config:type="list">
|
||||
<script>
|
||||
<filename>chroot.sh</filename>
|
||||
<interpreter>shell</interpreter>
|
||||
<source>
|
||||
<![CDATA[
|
||||
#!/bin/sh
|
||||
mgr=$(grep ^deploy_server /tmp/confluent.deploycfg|awk '{print $2}')
|
||||
profile=$(grep ^profile: /tmp/confluent.deploycfg|sed -e 's/^profile: //')
|
||||
proto=$(grep ^protocol: /tmp/confluent.deploycfg |awk '{print $2}')
|
||||
curl $proto://$mgr/confluent-public/os/$profile/scripts/post.sh > /tmp/post.sh
|
||||
. /tmp/post.sh
|
||||
curl $proto://$mgr/confluent-public/os/$profile/scripts/firstboot.sh > /mnt/etc/confluent/firstboot.sh
|
||||
chmod +x /mnt/etc/confluent/firstboot.sh
|
||||
]]>
|
||||
</source>
|
||||
</script>
|
||||
</chroot-scripts>
|
||||
<init-scripts config:type="list">
|
||||
<script>
|
||||
<filename>post.sh</filename>
|
||||
<interpreter>shell</interpreter>
|
||||
<location>file:///etc/confluent/firstboot.sh</location>
|
||||
</script>
|
||||
</init-scripts>
|
||||
|
||||
</scripts>
|
||||
</profile>
|
||||
@@ -0,0 +1,20 @@
|
||||
#!/bin/sh
|
||||
discnum=$(basename $1)
|
||||
if [ "$discnum" != 1 ]; then exit 0; fi
|
||||
if [ -e $2/boot/kernel ]; then exit 0; fi
|
||||
if ls $1/Product-* >& /dev/null; then
|
||||
ln -s $1 $2/product
|
||||
else
|
||||
ln -s ${1%1}2 $2/product
|
||||
fi
|
||||
sed -i 's/sle 15/SUSE Linux Enterprise 15/; s/opensuse_leap/openSUSE Leap/' $2/profile.yaml
|
||||
ln -s $1/boot/x86_64/loader/linux $2/boot/kernel && \
|
||||
ln -s $1/boot/x86_64/loader/initrd $2/boot/initramfs/distribution && \
|
||||
mkdir -p $2/boot/efi/boot && \
|
||||
ln -s $1/EFI/BOOT/bootx64.efi $1/EFI/BOOT/grub.efi $2/boot/efi/boot/
|
||||
profile=$(basename $2)
|
||||
if [[ $profile =~ ^sle.* ]]; then
|
||||
sed -i 's/%%IFSLE%%//;s/%%ENDIFSLE%%//' $2/autoyast
|
||||
else
|
||||
sed -i 's/%%IFSLE%%/<!--/;s/%%ENDIFSLE%%/-->/' $2/autoyast
|
||||
fi
|
||||
@@ -0,0 +1,2 @@
|
||||
label: %%DISTRO%% %%VERSION%% %%ARCH%% (Default Profile)
|
||||
kernelargs: quiet
|
||||
@@ -0,0 +1,10 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script runs at the end of the final boot, updating status
|
||||
|
||||
nodename=$(grep ^NODENAME /etc/confluent/confluent.info|awk '{print $2}')
|
||||
mgr=$(grep ^deploy_server /etc/confluent/confluent.deploycfg|awk '{print $2}')
|
||||
profile=$(grep ^profile: /etc/confluent/confluent.deploycfg|sed -e 's/^rootpassword: //')
|
||||
proto=$(grep ^protocol: /etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
apikey=$(cat /etc/confluent/confluent.apikey)
|
||||
curl --capath /etc/confluent/tls -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" -f -X POST -d "status: complete" https://$mgr/confluent-api/self/updatestatus
|
||||
@@ -0,0 +1,88 @@
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
class DiskInfo(object):
|
||||
def __init__(self, devname):
|
||||
self.name = devname
|
||||
self.wwn = None
|
||||
self.path = None
|
||||
self.model = ''
|
||||
self.size = 0
|
||||
self.driver = None
|
||||
self.mdcontainer = ''
|
||||
devnode = '/dev/{0}'.format(devname)
|
||||
qprop = subprocess.check_output(
|
||||
['udevadm', 'info', '--query=property', devnode])
|
||||
if not isinstance(qprop, str):
|
||||
qprop = qprop.decode('utf8')
|
||||
for prop in qprop.split('\n'):
|
||||
if '=' not in prop:
|
||||
continue
|
||||
k, v = prop.split('=', 1)
|
||||
if k == 'DEVTYPE' and v != 'disk':
|
||||
raise Exception('Not a disk')
|
||||
elif k == 'DM_NAME':
|
||||
raise Exception('Device Mapper')
|
||||
elif k == 'ID_MODEL':
|
||||
self.model = v
|
||||
elif k == 'DEVPATH':
|
||||
self.path = v
|
||||
elif k == 'ID_WWN':
|
||||
self.wwn = v
|
||||
elif k == 'MD_CONTAINER':
|
||||
self.mdcontainer = v
|
||||
attrs = subprocess.check_output(['udevadm', 'info', '-a', devnode])
|
||||
if not isinstance(attrs, str):
|
||||
attrs = attrs.decode('utf8')
|
||||
for attr in attrs.split('\n'):
|
||||
if '==' not in attr:
|
||||
continue
|
||||
k, v = attr.split('==', 1)
|
||||
k = k.strip()
|
||||
if k == 'ATTRS{size}':
|
||||
self.size = v.replace('"', '')
|
||||
elif (k == 'DRIVERS' and not self.driver
|
||||
and v not in ('"sd"', '""')):
|
||||
self.driver = v.replace('"', '')
|
||||
if not self.driver and 'imsm' not in self.mdcontainer:
|
||||
raise Exception("No driver detected")
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
|
||||
return 0
|
||||
if 'imsm' in self.mdcontainer:
|
||||
return 1
|
||||
if self.driver == 'ahci':
|
||||
return 2
|
||||
if self.driver.startswith('megaraid'):
|
||||
return 3
|
||||
if self.driver.startswith('mpt'):
|
||||
return 4
|
||||
return 99
|
||||
|
||||
def __repr__(self):
|
||||
return repr({
|
||||
'name': self.name,
|
||||
'path': self.path,
|
||||
'wwn': self.wwn,
|
||||
'driver': self.driver,
|
||||
'size': self.size,
|
||||
'model': self.model,
|
||||
})
|
||||
|
||||
|
||||
def main():
|
||||
disks = []
|
||||
for disk in sorted(os.listdir('/sys/class/block')):
|
||||
try:
|
||||
disk = DiskInfo(disk)
|
||||
disks.append(disk)
|
||||
except Exception as e:
|
||||
print("Skipping {0}: {1}".format(disk, str(e)))
|
||||
nd = [x.name for x in sorted(disks, key=lambda x: x.priority)]
|
||||
if nd:
|
||||
open('/tmp/installdisk', 'w').write(nd[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,49 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script runs when install is finished, but while the installer
|
||||
# is still running, with the to-be-booted system mounted in /mnt
|
||||
|
||||
# Carry over install-time ssh material into installed system
|
||||
mkdir -p /mnt/root/.ssh/
|
||||
chmod 700 /mnt/root/.ssh/
|
||||
cp /root/.ssh/authorized_keys /mnt/root/.ssh/
|
||||
chmd 600 /mnt/root/.ssh/authorized_keys
|
||||
cp /etc/ssh/*key* /mnt/etc/ssh/
|
||||
for i in /etc/ssh/*-cert.pub; do
|
||||
echo HostCertificate $i >> /mnt/etc/ssh/sshd_config
|
||||
done
|
||||
for i in /ssh/*.ca; do
|
||||
echo '@cert-authority *' $(cat $i) >> /mnt/etc/ssh/ssh_known_hosts
|
||||
done
|
||||
# Enable ~/.shosts, for the sake of root user, who is forbidden from using shosts.equiv
|
||||
echo IgnoreRhosts no >> /mnt/etc/ssh/sshd_config
|
||||
echo HostbasedAuthentication yes >> /mnt/etc/ssh/sshd_config
|
||||
echo HostbasedUsesNameFromPacketOnly yes >> /mnt/etc/ssh/sshd_config
|
||||
echo Host '*' >> /mnt/etc/ssh/ssh_config
|
||||
echo " HostbasedAuthentication yes" >> /mnt/etc/ssh/ssh_config
|
||||
echo " EnableSSHKeysign yes" >> /mnt/etc/ssh/ssh_config
|
||||
# Limit the attempts of using host key. This prevents client from using 3 or 4
|
||||
# authentication attempts through host based attempts
|
||||
echo " HostbasedKeyTypes *ed25519*" >> /mnt/etc/ssh/ssh_config
|
||||
|
||||
# In SUSE platform, setuid for ssh-keysign is required for host based,
|
||||
# and also must be opted into.
|
||||
echo /usr/lib/ssh/ssh-keysign root:root 4711 >> /mnt/etc/permissions.local
|
||||
chmod 4711 /mnt/usr/lib/ssh/ssh-keysign
|
||||
|
||||
# Download list of nodes from confluent, and put it into shosts.equiv (for most users) and .shosts (for root)
|
||||
nodename=$(grep ^NODENAME /tmp/confluent.info|awk '{print $2}')
|
||||
curl -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /tmp/confluent.apikey)" https://$mgr/confluent-api/self/nodelist > /tmp/allnodes
|
||||
cp /tmp/allnodes /mnt/root/.shosts
|
||||
cp /tmp/allnodes /mnt/etc/ssh/shosts.equiv
|
||||
|
||||
# carry over deployment configuration and api key for OS install action
|
||||
mkdir -p /mnt/etc/confluent
|
||||
chmod 700 /mnt/etc/confluent
|
||||
chmod 600 /tmp/confluent.*
|
||||
cp /tmp/confluent.* /mnt/etc/confluent/
|
||||
cp -a /tls /mnt/etc/confluent/
|
||||
cp -a /tls/* /mnt/var/lib/ca-certificates/openssl
|
||||
cp -a /tls/* /mnt/var/lib/ca-certificates/pem
|
||||
cp -a /tls/*.pem /mnt/etc/pki/trust/anchors
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
#!/bin/sh
|
||||
|
||||
# This script runs before the installer executes, and sets up ssh during install as well
|
||||
# as rewriting the autoyast file with any substitutions prior to it being evaluated for real
|
||||
|
||||
nodename=$(grep ^NODENAME /tmp/confluent.info|awk '{print $2}')
|
||||
rootpw=$(grep rootpassword: /tmp/confluent.deploycfg|sed -e 's/^rootpassword: //')
|
||||
if [ "$rootpw" = "null" ]; then
|
||||
rootpw="!"
|
||||
fi
|
||||
|
||||
mkdir ~/.ssh
|
||||
cat /ssh/*.rootpubkey > ~/.ssh/authorized_keys
|
||||
ssh-keygen -A
|
||||
for i in /etc/ssh/ssh_host*key.pub; do
|
||||
certname=${i/.pub/-cert.pub}
|
||||
curl -f -X POST -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $(cat /tmp/confluent.apikey)" -d @$i https://$mgr/confluent-api/self/sshcert > $certname
|
||||
echo HostKey ${i%.pub} >> /etc/ssh/sshd_config
|
||||
echo HostCertificate $certname >> /etc/ssh/sshd_config
|
||||
done
|
||||
/usr/sbin/sshd
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/getinstalldisk > /tmp/getinstalldisk
|
||||
python3 /tmp/getinstalldisk
|
||||
sed -e s!%%INSTDISK%%!/dev/$(cat /tmp/installdisk)! -e s!%%NODENAME%%!$nodename! -e "s?%%ROOTPASSWORD%%?${rootpw}?" /tmp/profile/autoinst.xml > /tmp/profile/modified.xml
|
||||
@@ -0,0 +1,8 @@
|
||||
if ! grep console= /proc/cmdline > /dev/null; then
|
||||
/opt/confluent/bin/autocons > /custom-installation/autocons.info
|
||||
cons=$(cat /custom-installation/autocons.info)
|
||||
if [ ! -z "$cons" ]; then
|
||||
echo "Auto-detected serial console: $cons" > ${cons%,*}
|
||||
fi
|
||||
fi
|
||||
echo /scripts/init-premount/confluent >> /scripts/init-premount/ORDER
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
cd /root
|
||||
cat /tls/*.0 > /root/etc/ssl/certs/ca-certificates.crt
|
||||
mkdir -p /root/custom-installation/ssh
|
||||
mkdir -p /root/custom-installation/tls
|
||||
cp /ssh/* /root/custom-installation/ssh
|
||||
cp /tls/* /root/custom-installation/tls
|
||||
NODENAME=$(grep ^NODENAME: /custom-installation/confluent/confluent.info|awk '{print $2}')
|
||||
MGR=$(grep ^MANAGER: /custom-installation/confluent/confluent.info|head -n 1| awk '{print $2}')
|
||||
oum=$(umask)
|
||||
umask 077
|
||||
chroot . custom-installation/confluent/bin/clortho $NODENAME $MGR > /root/custom-installation/confluent/confluent.apikey
|
||||
MGR=[$MGR]
|
||||
deploycfg=/root/custom-installation/confluent/confluent.deploycfg
|
||||
chroot . usr/bin/curl -f -H "CONFLUENT_NODENAME: $NODENAME" -H "CONFLUENT_APIKEY: $(cat /root//custom-installation/confluent/confluent.apikey)" https://${MGR}/confluent-api/self/deploycfg > $deploycfg
|
||||
umask $oum
|
||||
nic=$(grep ^MANAGER /custom-installation/confluent/confluent.info|grep fe80::|sed -e s/.*%//|head -n 1)
|
||||
nic=$(ip link |grep ^$nic:|awk '{print $2}')
|
||||
DEVICE=${nic%:}
|
||||
ipv4m=$(grep ^ipv4_method $deploycfg|awk '{print$2}')
|
||||
. /scripts/functions
|
||||
if [ "$ipv4m" = "dhcp" ]; then
|
||||
IP=dhcp
|
||||
configure_networking
|
||||
elif [ "$ipv4m" = "static" ]; then
|
||||
v4addr=$(grep ^ipv4_address: $deploycfg)
|
||||
v4addr=${v4addr#ipv4_address: }
|
||||
v4gw=$(grep ^ipv4_gateway: $deploycfg)
|
||||
v4gw=${v4gw#ipv4_gateway: }
|
||||
if [ "$v4gw" = "null" ]; then
|
||||
v4gw=""
|
||||
fi
|
||||
v4nm=$(grep ipv4_netmask: $deploycfg)
|
||||
v4nm=${v4nm#ipv4_netmask: }
|
||||
dnsdomain=$(grep ^dnsdomain: $deploycfg)
|
||||
dnsdomain=${dnsdomain#dnsdomain: }
|
||||
if [ "$dnsdomain" = "null" ]; then dnsdomain=""; fi
|
||||
dns=$(grep -A1 ^nameservers: $deploycfg|head -n 2|tail -n 1|sed -e 's/^- //'|sed -e "s/''//")
|
||||
{
|
||||
echo "DEVICE='$DEVICE'"
|
||||
echo "PROTO='none'"
|
||||
echo "IPV4PROTO='none'"
|
||||
echo "IPV4ADDR='$v4addr'"
|
||||
echo "IPV4NETMASK='$v4nm'"
|
||||
echo "IPV4BROADCAST='$v4nm'"
|
||||
echo "IPV4GATEWAY='$v4gw'"
|
||||
echo "IPV4DNS1='$dns'"
|
||||
echo "HOSTNAME='$NODENAME'"
|
||||
echo "DNSDOMAIN='$dnsdomain'"
|
||||
echo "DOMAINSEARCH='$dnsdomain'"
|
||||
} > "/run/net-$DEVICE.conf"
|
||||
configure_networking
|
||||
else
|
||||
IP=off
|
||||
fi
|
||||
ipv4s=$(grep ^deploy_server $deploycfg|awk '{print $2}')
|
||||
osprofile=$(cat /custom-installation/confluent/osprofile)
|
||||
fcmdline="$(cat /custom-installation/confluent/cmdline.orig) autoinstall ds=nocloud-net;s=https://${ipv4s}/confluent-public/os/${osprofile}/autoinstall/"
|
||||
if [ -f /custom-installation/autocons.info ]; then
|
||||
cons=$(cat /custom-installation/autocons.info)
|
||||
fi
|
||||
if [ ! -z "$cons" ]; then
|
||||
echo "Installation will proceed on graphics console, autoconsole not supported during autoinstall phase" > ${cons%,*}
|
||||
echo "Progress can be checked by using ssh to access and running the screendump command" > ${cons%,*}
|
||||
#fcmdline="$fcmdline console=${cons#/dev/}"
|
||||
fi
|
||||
echo $fcmdline > /custom-installation/confluent/fakecmdline
|
||||
/scripts/casper-bottom/58server_network
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
deploycfg=/custom-installation/confluent/confluent.deploycfg
|
||||
mgr=$(grep ^deploy_server $deploycfg|awk '{print $2}')
|
||||
profile=$(grep ^profile: $deploycfg|awk '{print $2}')
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/post.sh > /tmp/post.sh
|
||||
. /tmp/post.sh
|
||||
@@ -0,0 +1,6 @@
|
||||
#!/bin/bash
|
||||
deploycfg=/custom-installation/confluent/confluent.deploycfg
|
||||
mgr=$(grep ^deploy_server $deploycfg|awk '{print $2}')
|
||||
profile=$(grep ^profile: $deploycfg|awk '{print $2}')
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/pre.sh > /tmp/pre.sh
|
||||
. /tmp/pre.sh
|
||||
@@ -0,0 +1,30 @@
|
||||
cd /sys/class/net
|
||||
for nic in *; do
|
||||
ip link set $nic up
|
||||
done
|
||||
mkdir -p /custom-installation
|
||||
cp -a /opt/confluent /custom-installation
|
||||
touch /custom-installation/confluent/confluent.info
|
||||
while ! grep NODENAME /custom-installation/confluent/confluent.info; do
|
||||
/opt/confluent/bin/copernicus -t > /custom-installation/confluent/confluent.info
|
||||
done
|
||||
MGR="[$(grep MANAGER: /custom-installation/confluent/confluent.info | head -n 1 | awk '{print $2}')]"
|
||||
osprofile=$(sed -e 's/.*osprofile=//' -e 's/ .*//' /proc/cmdline)
|
||||
cat /proc/cmdline > /custom-installation/confluent/cmdline.orig
|
||||
if [ -f /custom-installation/autocons.info ]; then
|
||||
cons=$(cat /custom-installation/autocons.info)
|
||||
fi
|
||||
if [ ! -z "$cons" ]; then
|
||||
echo "Preparing to deploy $osprofile from $MGR" > ${cons%,*}
|
||||
fi
|
||||
echo "Preparing to deploy $osprofile from $MGR"
|
||||
echo $osprofile > /custom-installation/confluent/osprofile
|
||||
echo URL=http://${MGR}/confluent-public/os/$osprofile/distribution/install.iso >> /conf/param.conf
|
||||
fcmdline="$(cat /custom-installation/confluent/cmdline.orig) url=http://${MGR}/confluent-public/os/$osprofile/distribution/install.iso"
|
||||
if [ ! -z "$cons" ]; then
|
||||
fcmdline="$fcmdline console=${cons#/dev/}"
|
||||
fi
|
||||
echo $fcmdline > /custom-installation/confluent/fakecmdline
|
||||
mount -o bind /custom-installation/confluent/fakecmdline /proc/cmdline
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
#cloud-config
|
||||
autoinstall:
|
||||
version: 1
|
||||
early-commands:
|
||||
- /custom-installation/pre.sh
|
||||
late-commands:
|
||||
- /custom-installation/post.sh
|
||||
ssh:
|
||||
install-server: true
|
||||
storage:
|
||||
layout:
|
||||
name: lvm
|
||||
match:
|
||||
path: "%%INSTALLDISK%%"
|
||||
user-data:
|
||||
runcmd:
|
||||
- /etc/confluent/firstboot.sh
|
||||
@@ -0,0 +1,7 @@
|
||||
#!/bin/sh
|
||||
sed -i 's/label: ubuntu/label: Ubuntu/' $2/profile.yaml && \
|
||||
ln -s $1/casper/vmlinuz $2/boot/kernel && \
|
||||
ln -s $1/casper/initrd $2/boot/initramfs/distribution && \
|
||||
mkdir -p $2/boot/efi/boot && \
|
||||
ln -s $1/EFI/BOOT/* $2/boot/efi/boot
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
label: %%DISTRO%% %%VERSION%% %%ARCH%% (Default Profile)
|
||||
kernelargs: quiet osprofile=%%PROFILE%%
|
||||
@@ -0,0 +1,14 @@
|
||||
#!/bin/bash
|
||||
echo "Confluent first boot is running"
|
||||
cp -a /etc/confluent/ssh/* /etc/ssh/
|
||||
systemctl restart sshd
|
||||
rootpw=$(grep ^rootpassword: /etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
if [ ! -z "$rootpw" -a "$rootpw" != "null" ]; then
|
||||
echo root:$rootpw | chpasswd -e
|
||||
fi
|
||||
nodename=$(grep ^NODENAME: /etc/confluent/confluent.info | awk '{print $2}')
|
||||
apikey=$(cat /etc/confluent/confluent.apikey)
|
||||
mgr=$(grep ^deploy_server: /etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
hostnamectl set-hostname $(grep ^NODENAME: /etc/confluent/confluent.info | awk '{print $2}')
|
||||
touch /etc/cloud/cloud-init.disabled
|
||||
curl --capath /etc/confluent/tls -f -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" -X POST -d "status: complete" https://$mgr/confluent-api/self/updatestatus
|
||||
@@ -0,0 +1,88 @@
|
||||
import subprocess
|
||||
import os
|
||||
|
||||
class DiskInfo(object):
|
||||
def __init__(self, devname):
|
||||
self.name = devname
|
||||
self.wwn = None
|
||||
self.path = None
|
||||
self.model = ''
|
||||
self.size = 0
|
||||
self.driver = None
|
||||
self.mdcontainer = ''
|
||||
devnode = '/dev/{0}'.format(devname)
|
||||
qprop = subprocess.check_output(
|
||||
['udevadm', 'info', '--query=property', devnode])
|
||||
if not isinstance(qprop, str):
|
||||
qprop = qprop.decode('utf8')
|
||||
for prop in qprop.split('\n'):
|
||||
if '=' not in prop:
|
||||
continue
|
||||
k, v = prop.split('=', 1)
|
||||
if k == 'DEVTYPE' and v != 'disk':
|
||||
raise Exception('Not a disk')
|
||||
elif k == 'DM_NAME':
|
||||
raise Exception('Device Mapper')
|
||||
elif k == 'ID_MODEL':
|
||||
self.model = v
|
||||
elif k == 'DEVPATH':
|
||||
self.path = v
|
||||
elif k == 'ID_WWN':
|
||||
self.wwn = v
|
||||
elif k == 'MD_CONTAINER':
|
||||
self.mdcontainer = v
|
||||
attrs = subprocess.check_output(['udevadm', 'info', '-a', devnode])
|
||||
if not isinstance(attrs, str):
|
||||
attrs = attrs.decode('utf8')
|
||||
for attr in attrs.split('\n'):
|
||||
if '==' not in attr:
|
||||
continue
|
||||
k, v = attr.split('==', 1)
|
||||
k = k.strip()
|
||||
if k == 'ATTRS{size}':
|
||||
self.size = v.replace('"', '')
|
||||
elif (k == 'DRIVERS' and not self.driver
|
||||
and v not in ('"sd"', '""')):
|
||||
self.driver = v.replace('"', '')
|
||||
if not self.driver and 'imsm' not in self.mdcontainer:
|
||||
raise Exception("No driver detected")
|
||||
|
||||
@property
|
||||
def priority(self):
|
||||
if self.model.lower() in ('thinksystem_m.2_vd', 'thinksystem m.2'):
|
||||
return 0
|
||||
if 'imsm' in self.mdcontainer:
|
||||
return 1
|
||||
if self.driver == 'ahci':
|
||||
return 2
|
||||
if self.driver.startswith('megaraid'):
|
||||
return 3
|
||||
if self.driver.startswith('mpt'):
|
||||
return 4
|
||||
return 99
|
||||
|
||||
def __repr__(self):
|
||||
return repr({
|
||||
'name': self.name,
|
||||
'path': self.path,
|
||||
'wwn': self.wwn,
|
||||
'driver': self.driver,
|
||||
'size': self.size,
|
||||
'model': self.model,
|
||||
})
|
||||
|
||||
|
||||
def main():
|
||||
disks = []
|
||||
for disk in sorted(os.listdir('/sys/class/block')):
|
||||
try:
|
||||
disk = DiskInfo(disk)
|
||||
disks.append(disk)
|
||||
except Exception as e:
|
||||
print("Skipping {0}: {1}".format(disk, str(e)))
|
||||
nd = [x.name for x in sorted(disks, key=lambda x: x.priority)]
|
||||
if nd:
|
||||
open('/tmp/installdisk', 'w').write(nd[0])
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
cp -a /root/.ssh /target/root/
|
||||
mkdir -p /target/etc/confluent/ssh/sshd_config.d/
|
||||
chmod 700 /target/etc/confluent
|
||||
cp /custom-installation/confluent/* /target/etc/confluent/
|
||||
cp -a /custom-installation/tls /target/etc/confluent/
|
||||
chmod go-rwx /etc/confluent/*
|
||||
for i in /custom-installation/ssh/*.ca; do
|
||||
echo '@cert-authority *' $(cat $i) >> /target/etc/ssh/ssh_known_hosts
|
||||
done
|
||||
|
||||
cp -a /etc/ssh/ssh_host* /target/etc/confluent/ssh/
|
||||
cp -a /etc/ssh/sshd_config.d/confluent.conf /target/etc/confluent/ssh/sshd_config.d/
|
||||
sshconf=/target/etc/ssh/ssh_config
|
||||
if [ -d /target/etc/ssh/ssh_config.d/ ]; then
|
||||
sshconf=/target/etc/ssh/ssh_config.d/01-confluent.conf
|
||||
fi
|
||||
echo 'Host *' >> $sshconf
|
||||
echo ' HostbasedAuthentication yes' >> $sshconf
|
||||
echo ' EnableSSHKeysign yes' >> $sshconf
|
||||
echo ' HostbasedKeyTypes *ed25519*' >> $sshconf
|
||||
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/firstboot.sh > /target/etc/confluent/firstboot.sh
|
||||
chmod +x /target/etc/confluent/firstboot.sh
|
||||
cp /tmp/allnodes /target/root/.shosts
|
||||
cp /tmp/allnodes /target/etc/ssh/shosts.equiv
|
||||
textcons=$(grep ^textconsole: /target/etc/confluent/confluent.deploycfg |awk '{print $2}')
|
||||
if [ "$textcons" = "true" ] && ! grep console= /proc/cmdline > /dev/null; then
|
||||
cons=""
|
||||
if [ -f /custom-installation/autocons.info ]; then
|
||||
cons=$(cat /custom-installation/autocons.info)
|
||||
fi
|
||||
if [ ! -z "$cons" ]; then
|
||||
sed -i 's/GRUB_CMDLINE_LINUX="\([^"]*\)"/GRUB_CMDLINE_LINUX="\1 console='${cons#/dev/}'"/' /target/etc/default/grub
|
||||
mount -o bind /dev /target/dev
|
||||
mount -o bind /proc /target/proc
|
||||
mount -o bind /sys /target/sys
|
||||
chroot /target update-grub
|
||||
umount /target/sys /target/dev /target/proc
|
||||
fi
|
||||
fi
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
#!/bin/bash
|
||||
cat /custom-installation/ssh/*.rootpubkey > /root/.ssh/authorized_keys
|
||||
nodename=$(grep ^NODENAME: /custom-installation/confluent/confluent.info|awk '{print $2}')
|
||||
apikey=$(cat /custom-installation/confluent/confluent.apikey)
|
||||
for pubkey in /etc/ssh/ssh_host*key.pub; do
|
||||
certfile=${pubkey/.pub/-cert.pub}
|
||||
keyfile=${pubkey%.pub}
|
||||
curl -f -X POST -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" -d @$pubkey https://$mgr/confluent-api/self/sshcert > $certfile
|
||||
echo HostKey $keyfile >> /etc/ssh/sshd_config.d/confluent.conf
|
||||
echo HostCertificate $certfile >> /etc/ssh/sshd_config.d/confluent.conf
|
||||
done
|
||||
echo HostbasedAuthentication yes >> /etc/ssh/sshd_config.d/confluent.conf
|
||||
echo HostbasedUsesNameFromPacketOnly yes >> /etc/ssh/sshd_config.d/confluent.conf
|
||||
echo IgnoreRhosts no >> /etc/ssh/sshd_config.d/confluent.conf
|
||||
systemctl restart sshd
|
||||
curl -f X POST -H "CONFLUENT_NODENAME: $nodename" -H "CONFLUENT_APIKEY: $apikey" https://$mgr/confluent-api/self/nodelist > /tmp/allnodes
|
||||
curl -f https://$mgr/confluent-public/os/$profile/scripts/getinstalldisk > /custom-installation/getinstalldisk
|
||||
python3 /custom-installation/getinstalldisk
|
||||
sed -i s!%%INSTALLDISK%%!/dev/$(cat /tmp/installdisk)! /autoinstall.yaml
|
||||
@@ -0,0 +1,16 @@
|
||||
CC := gcc
|
||||
CFLAGS := -Os
|
||||
TARGETS := copernicus autocons
|
||||
|
||||
all: $(TARGETS) clortho
|
||||
|
||||
clortho: clortho.c
|
||||
$(CC) $(CFLAGS) -o $@ $^ -lcrypt
|
||||
strip -s $@
|
||||
|
||||
$(TARGETS): % : %.c
|
||||
$(CC) $(CFLAGS) -o $@ $^
|
||||
strip -s $@
|
||||
|
||||
clean:
|
||||
rm $(TARGETS) clortho
|
||||
@@ -25,6 +25,7 @@ int main(int argc, char* argv[]) {
|
||||
int currspeed;
|
||||
speed_t cspeed;
|
||||
char buff[128];
|
||||
char* offset;
|
||||
uint64_t address;
|
||||
spcr = open("/sys/firmware/acpi/tables/SPCR", O_RDONLY);
|
||||
if (spcr < 0) {
|
||||
@@ -38,6 +39,7 @@ int main(int argc, char* argv[]) {
|
||||
if (buff[40] != 1) exit(0); //IO only
|
||||
address = *(uint64_t *)(buff + 44);
|
||||
currspeed = buff[58];
|
||||
offset = buff + 10;
|
||||
if (address == COM1) {
|
||||
strncpy(buff, "/dev/ttyS0", 128);
|
||||
} else if (address == COM2) {
|
||||
@@ -51,14 +53,16 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
if (currspeed == SPEED9600) {
|
||||
cspeed = B9600;
|
||||
strcpy(offset, ",9600");
|
||||
} else if (currspeed == SPEED19200) {
|
||||
cspeed = B19200;
|
||||
strcpy(offset, ",19200");
|
||||
} else if (currspeed == SPEED57600) {
|
||||
cspeed = B57600;
|
||||
strcpy(offset, ",57600");
|
||||
} else if (currspeed == SPEED115200) {
|
||||
cspeed = B115200;
|
||||
} else if (currspeed == SPEED115200) {
|
||||
cspeed = 0;
|
||||
strcpy(offset, ",115200");
|
||||
} else {
|
||||
exit(0);
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/* Copyright 2019 Lenovo */
|
||||
#include <arpa/inet.h>
|
||||
#include <crypt.h>
|
||||
#include <net/if.h>
|
||||
#include <netdb.h>
|
||||
#include <sys/socket.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/time.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAXPACKET 1024
|
||||
|
||||
static const char cryptalpha[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789./";
|
||||
|
||||
unsigned char* genpasswd(int len) {
|
||||
unsigned char * passwd;
|
||||
int urandom, ret;
|
||||
passwd = calloc(len + 1, sizeof(char));
|
||||
urandom = open("/dev/urandom", O_RDONLY);
|
||||
ret = read(urandom, passwd, len);
|
||||
close(urandom);
|
||||
for (urandom = 0; urandom < len; urandom++) {
|
||||
passwd[urandom] = cryptalpha[passwd[urandom] >> 2];
|
||||
}
|
||||
return passwd;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
int sock, ret;
|
||||
char slen;
|
||||
unsigned char currlen, currtype;
|
||||
unsigned char* passwd;
|
||||
unsigned char* cryptedpass;
|
||||
unsigned char* macaddr;
|
||||
struct timeval timeout;
|
||||
struct addrinfo hints;
|
||||
struct addrinfo *addrs;
|
||||
struct addrinfo *curr;
|
||||
struct sockaddr_in net4bind;
|
||||
struct sockaddr_in6 net6bind;
|
||||
unsigned char buffer[MAXPACKET];
|
||||
memset(&hints, 0, sizeof(struct addrinfo));
|
||||
memset(&net4bind, 0, sizeof(struct sockaddr_in));
|
||||
memset(&net6bind, 0, sizeof(struct sockaddr_in6));
|
||||
memset(&buffer, 0, MAXPACKET);
|
||||
memset(&timeout, 0, sizeof(struct timeval));
|
||||
timeout.tv_sec = 10;
|
||||
net4bind.sin_port = htons(302);
|
||||
net6bind.sin6_port = htons(302);
|
||||
net6bind.sin6_family = AF_INET6;
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
passwd = genpasswd(32);
|
||||
memset(buffer, 0, MAXPACKET);
|
||||
strncpy(buffer, "$5$", 3);
|
||||
cryptedpass = genpasswd(8);
|
||||
strncpy(buffer + 3, cryptedpass, 8);
|
||||
free(cryptedpass);
|
||||
cryptedpass = crypt(passwd, buffer);
|
||||
if (argc < 3) {
|
||||
fprintf(stderr, "Missing node name and manager\n");
|
||||
exit(1);
|
||||
}
|
||||
sock = getaddrinfo(argv[2], "13001", &hints, &addrs);
|
||||
if (sock != 0) {
|
||||
fprintf(stderr, "Error trying to resolve %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
for (curr = addrs; curr != NULL; curr = curr->ai_next) {
|
||||
sock = socket(curr->ai_family, curr->ai_socktype, curr->ai_protocol);
|
||||
if (sock < 0) continue;
|
||||
setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int));
|
||||
if (curr->ai_family == AF_INET) {
|
||||
bind(sock, (struct sockaddr*)&net4bind, sizeof(struct sockaddr_in));
|
||||
} else if (curr->ai_family == AF_INET6) {
|
||||
bind(sock, (struct sockaddr*)&net6bind, sizeof(struct sockaddr_in6));
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
if (connect(sock, curr->ai_addr, curr->ai_addrlen) == 0) break;
|
||||
}
|
||||
if (curr == NULL) {
|
||||
fprintf(stderr, "Unable to reach %s\n", argv[2]);
|
||||
exit(1);
|
||||
}
|
||||
setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, &timeout, sizeof(timeout));
|
||||
freeaddrinfo(addrs);
|
||||
ret = read(sock, buffer, 8);
|
||||
if (memcmp(buffer, "\xc2\xd1-\xa8\x80\xd8j\xba", 8) != 0) {
|
||||
fprintf(stderr, "Unrecognized server\n");
|
||||
exit(1);
|
||||
}
|
||||
slen = strlen(argv[1]) & 0xff;
|
||||
dprintf(sock, "\x01%c%s", slen, argv[1]);
|
||||
ret = write(sock, "\x00\x00", 2);
|
||||
memset(buffer, 0, MAXPACKET);
|
||||
ret = read(sock, buffer, 2);
|
||||
while (buffer[0] != 255) {
|
||||
currtype = buffer[0];
|
||||
currlen = buffer[1];
|
||||
memset(buffer, 0, MAXPACKET);
|
||||
if (currlen) {
|
||||
ret = read(sock, buffer, currlen); // Max is 255, well under MAX_PACKET
|
||||
}
|
||||
if (currtype == 2) {
|
||||
dprintf(sock, "\x03%c", currlen);
|
||||
ret = write(sock, buffer, currlen);
|
||||
slen = strlen(cryptedpass) & 0xff;
|
||||
dprintf(sock, "\x04%c%s", slen, cryptedpass);
|
||||
ret = write(sock, "\x00\x00", 2);
|
||||
} else if (currtype == 5) {
|
||||
printf("%s", passwd);
|
||||
printf("\n");
|
||||
exit(0);
|
||||
}
|
||||
buffer[0] = 255;
|
||||
ret = read(sock, buffer, 2);
|
||||
}
|
||||
fprintf(stderr, "Password was not accepted\n");
|
||||
exit(1);
|
||||
}
|
||||
@@ -48,8 +48,7 @@ int add_macs(char* destination, int maxsize) {
|
||||
} else if (lla->sll_hatype == ARPHRD_ETHER) {
|
||||
snprintf(macaddr, 32, "/mac=%02x:%02x:%02x:%02x:%02x:%02x",
|
||||
lla->sll_addr[0], lla->sll_addr[1], lla->sll_addr[2],
|
||||
lla->sll_addr[3], lla->sll_addr[4], lla->sll_addr[5],
|
||||
lla->sll_addr[6]
|
||||
lla->sll_addr[3], lla->sll_addr[4], lla->sll_addr[5]
|
||||
);
|
||||
} else {
|
||||
continue;
|
||||
@@ -68,10 +67,16 @@ int main(int argc, char* argv[]) {
|
||||
struct sockaddr_in6 addr, dst;
|
||||
struct sockaddr_in addr4, dst4;
|
||||
char msg[1024];
|
||||
char *nodenameidx;
|
||||
char nodename[1024];
|
||||
char lastnodename[1024];
|
||||
char lastmsg[1024];
|
||||
char last6msg[1024];
|
||||
int ifidx, offset;
|
||||
fd_set rfds;
|
||||
struct timeval tv;
|
||||
int settime = 0;
|
||||
int setusec = 500000;
|
||||
socklen_t dstsize, dst4size;
|
||||
dstsize = sizeof(dst);
|
||||
dst4size = sizeof(dst4);
|
||||
@@ -80,6 +85,10 @@ int main(int argc, char* argv[]) {
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
memset(&dst, 0, sizeof(dst));
|
||||
memset(&dst4, 0, sizeof(dst4));
|
||||
memset(nodename, 0, 1024);
|
||||
memset(lastnodename, 0, 1024);
|
||||
memset(lastmsg, 0, 1024);
|
||||
memset(last6msg, 0, 1024);
|
||||
addr.sin6_family = AF_INET6;
|
||||
addr.sin6_addr = in6addr_any;
|
||||
addr.sin6_port = htons(190);
|
||||
@@ -94,10 +103,6 @@ int main(int argc, char* argv[]) {
|
||||
inet_pton(AF_INET, "239.255.255.250", &dst4.sin_addr);
|
||||
strncpy(msg, "M-SEARCH * HTTP/1.1\r\nST: urn:xcat.org:service:confluent:", 1024);
|
||||
offset = strnlen(msg, 1024);
|
||||
if (argc > 1) {
|
||||
snprintf(msg + offset, 1024 - offset, "/node=%s", argv[1]);
|
||||
offset = strnlen(msg, 1024);
|
||||
}
|
||||
add_uuid(msg + offset, 1024 - offset);
|
||||
offset = strnlen(msg, 1024);
|
||||
add_macs(msg + offset, 1024 - offset);
|
||||
@@ -134,30 +139,100 @@ int main(int argc, char* argv[]) {
|
||||
FD_ZERO(&rfds);
|
||||
FD_SET(n4, &rfds);
|
||||
FD_SET(ns, &rfds);
|
||||
tv.tv_sec = 10;
|
||||
tv.tv_usec = 0;
|
||||
tv.tv_sec = 2;
|
||||
tv.tv_usec = 500000;
|
||||
ifidx = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
|
||||
while (ifidx) {
|
||||
if (ifidx == -1) perror("Unable to select");
|
||||
if (ifidx) {
|
||||
if (FD_ISSET(n4, &rfds)) {
|
||||
recvfrom(n4, msg, 1024, 0, (struct sockaddr *)&dst4, &dst4size);
|
||||
memset(msg, 0, 1024);
|
||||
/* Deny packet access to the last 24 bytes to assure null */
|
||||
recvfrom(n4, msg, 1000, 0, (struct sockaddr *)&dst4, &dst4size);
|
||||
if (nodenameidx = strstr(msg, "NODENAME: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
nodenameidx = strstr(nodename, "\r");
|
||||
if (nodenameidx) { nodenameidx[0] = 0; }
|
||||
if (strncmp(lastnodename, nodename, 1024) != 0) {
|
||||
printf("NODENAME: %s\n", nodename);
|
||||
strncpy(lastnodename, nodename, 1024);
|
||||
}
|
||||
}
|
||||
if (nodenameidx = strstr(msg, "CURRTIME: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
if (nodenameidx = strstr(nodename, "\r")) {
|
||||
nodenameidx[0] = 0;
|
||||
}
|
||||
settime = strtol(nodename, NULL, 10);
|
||||
}
|
||||
if (nodenameidx = strstr(msg, "CURRMSECS: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
if (nodenameidx = strstr(nodename, "\r")) {
|
||||
nodenameidx[0] = 0;
|
||||
}
|
||||
setusec = strtol(nodename, NULL, 10) * 1000;
|
||||
}
|
||||
memset(msg, 0, 1024);
|
||||
inet_ntop(dst4.sin_family, &dst4.sin_addr, msg, dst4size);
|
||||
/* Take measure from printing out the same ip twice in a row */
|
||||
if (strncmp(lastmsg, msg, 1024) != 0) {
|
||||
printf("%s\n", msg);
|
||||
sendto(n4, "PING", 4, 0, (const struct sockaddr *)&dst4, dst4size);
|
||||
printf("MANAGER: %s\n", msg);
|
||||
strncpy(lastmsg, msg, 1024);
|
||||
}
|
||||
}
|
||||
if (FD_ISSET(ns, &rfds)) {
|
||||
recvfrom(ns, msg, 1024, 0, (struct sockaddr *)&dst, &dstsize);
|
||||
memset(msg, 0, 1024);
|
||||
/* Deny packet access to the last 24 bytes to assure null */
|
||||
recvfrom(ns, msg, 1000, 0, (struct sockaddr *)&dst, &dstsize);
|
||||
if (nodenameidx = strstr(msg, "NODENAME: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
nodenameidx = strstr(nodename, "\r");
|
||||
if (nodenameidx) { nodenameidx[0] = 0; }
|
||||
if (strncmp(lastnodename, nodename, 1024) != 0) {
|
||||
printf("NODENAME: %s\n", nodename);
|
||||
strncpy(lastnodename, nodename, 1024);
|
||||
}
|
||||
}
|
||||
if (nodenameidx = strstr(msg, "CURRTIME: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
if (nodenameidx = strstr(nodename, "\r")) {
|
||||
nodenameidx[0] = 0;
|
||||
}
|
||||
settime = strtol(nodename, NULL, 10);
|
||||
}
|
||||
if (nodenameidx = strstr(msg, "CURRMSECS: ")) {
|
||||
nodenameidx += 10;
|
||||
strncpy(nodename, nodenameidx, 1024);
|
||||
if (nodenameidx = strstr(nodename, "\r")) {
|
||||
nodenameidx[0] = 0;
|
||||
}
|
||||
setusec = strtol(nodename, NULL, 10) * 1000;
|
||||
}
|
||||
memset(msg, 0, 1024);
|
||||
inet_ntop(dst.sin6_family, &dst.sin6_addr, msg, dstsize);
|
||||
if (strncmp(lastmsg, msg, 1024) != 0) {
|
||||
printf("%s\n", msg);
|
||||
strncpy(lastmsg, msg, 1024);
|
||||
if (strncmp(last6msg, msg, 1024) != 0) {
|
||||
sendto(ns, "PING", 4, 0, (const struct sockaddr *)&dst, dstsize);
|
||||
printf("MANAGER: %s", msg);
|
||||
if (strncmp(msg, "fe80::", 6) == 0) {
|
||||
printf("%%%u", dst.sin6_scope_id);
|
||||
}
|
||||
printf("\n");
|
||||
strncpy(last6msg, msg, 1024);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (settime && argc > 1 && strcmp(argv[1], "-t") == 0) {
|
||||
tv.tv_sec = settime;
|
||||
tv.tv_usec = setusec;
|
||||
settimeofday(&tv, NULL);
|
||||
settime = 0;
|
||||
}
|
||||
tv.tv_sec = 0;
|
||||
tv.tv_usec = 500000;
|
||||
FD_SET(n4, &rfds);
|
||||
@@ -1,8 +1,9 @@
|
||||
#!/usr/bin/env python
|
||||
#!/usr/bin/python2
|
||||
|
||||
import argparse
|
||||
import errno
|
||||
import os
|
||||
import pwd
|
||||
import socket
|
||||
import subprocess
|
||||
import sys
|
||||
@@ -22,7 +23,7 @@ except NameError:
|
||||
pass
|
||||
|
||||
def make_certificate():
|
||||
umask = os.umask(0077)
|
||||
umask = os.umask(0o77)
|
||||
try:
|
||||
os.makedirs('/etc/confluent/cfg')
|
||||
except OSError as e:
|
||||
@@ -40,6 +41,12 @@ def make_certificate():
|
||||
'/etc/confluent/srvcert.pem -subj /CN='
|
||||
'{0}'.format(socket.gethostname()).split(' ')):
|
||||
raise Exception('Error generating certificate')
|
||||
try:
|
||||
uid = pwd.getpwnam('confluent').pw_uid
|
||||
os.chown('/etc/confluent/privkey.pem', uid, -1)
|
||||
os.chown('/etc/confluent/srvcert.pem', uid, -1)
|
||||
except KeyError:
|
||||
pass
|
||||
print('Certificate generated successfully')
|
||||
os.umask(umask)
|
||||
|
||||
@@ -61,7 +68,7 @@ def join_collective(server, invitation):
|
||||
make_certificate()
|
||||
s = client.Command().connection
|
||||
while not invitation:
|
||||
invitation = raw_input('Paste the invitation here: ')
|
||||
invitation = input('Paste the invitation here: ')
|
||||
tlvdata.send(s, {'collective': {'operation': 'join',
|
||||
'invitation': invitation,
|
||||
'server': server}})
|
||||
@@ -69,12 +76,28 @@ def join_collective(server, invitation):
|
||||
res = res.get('collective',
|
||||
{'status': 'Unknown response: ' + repr(res)})
|
||||
print(res.get('status', res.get('error', repr(res))))
|
||||
if 'error' in res:
|
||||
sys.exit(1)
|
||||
|
||||
def delete_member(name):
|
||||
s = client.Command().connection
|
||||
tlvdata.send(s, {'collective': {'operation': 'delete',
|
||||
'member': name}})
|
||||
res = tlvdata.recv(s)
|
||||
res = res.get('collective',
|
||||
{'status': 'Unknown response: ' + repr(res)})
|
||||
print(res.get('status', res.get('error', repr(res))))
|
||||
if 'error' in res:
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def show_collective():
|
||||
s = client.Command().connection
|
||||
tlvdata.send(s, {'collective': {'operation': 'show'}})
|
||||
res = tlvdata.recv(s)
|
||||
if 'error' in res:
|
||||
print(res['error'])
|
||||
return
|
||||
if 'error' in res['collective']:
|
||||
print(res['collective']['error'])
|
||||
return
|
||||
@@ -104,6 +127,8 @@ def main():
|
||||
'collective member. Run collective invite -h for more information')
|
||||
ic.add_argument('name', help='Name of server to invite to join the '
|
||||
'collective')
|
||||
dc = sp.add_parser('delete', help='Delete a member of a collective')
|
||||
dc.add_argument('name', help='Name of server to delete from collective')
|
||||
jc = sp.add_parser('join', help='Join a collective. Run collective join -h for more information')
|
||||
jc.add_argument('server', help='Existing collective member that ran invite and generated a token')
|
||||
jc.add_argument('-i', help='Invitation provided by runniing invite on an '
|
||||
@@ -117,6 +142,8 @@ def main():
|
||||
join_collective(cmdset.server, cmdset.i)
|
||||
elif cmdset.command == 'show':
|
||||
show_collective()
|
||||
elif cmdset.command == 'delete':
|
||||
delete_member(cmdset.name)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user