Wei Zhou 87284f03f0
Upgrade to JRE17 and Upgrade System VMs/VRs to Python3 and Debian 12 (#8497)
* Update to 4.20.0

* Update to python3

* Upgrade to JRE 17

* Upgrade to Debian 12.4.0

* VR: upgrade to python3

for f in `find systemvm/ -name *.py`;do
    if grep "print " $f >/dev/null;then
        2to3-2.7 -w $f
    else
        2to3-2.7 -p -w $f
    fi
done

* java: Use JRE17 in cloudstack packages and systemvmtemplate

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>

* Add --add-opens to JAVA_OPTS in systemd config

* Add --add-opens to JAVA_OPTS in systemd config for usage

* python3: fix "TypeError: a bytes-like object is required, not 'str'"

* python3: fix "ValueError: must have exactly one of create/read/write/append mode"

* Add --add-exports=java.base/sun.security.x509=ALL-UNNAMED for management server

* Use pip3 instead of pip for centos8

* python3: fix "TypeError: write() argument must be str, not bytes"

```
root@r-1037-VM:~# /opt/cloud/bin/passwd_server_ip.py 10.1.1.1
Traceback (most recent call last):
  File "/opt/cloud/bin/passwd_server_ip.py", line 201, in <module>
    serve()
  File "/opt/cloud/bin/passwd_server_ip.py", line 187, in serve
    initToken()
  File "/opt/cloud/bin/passwd_server_ip.py", line 60, in initToken
    f.write(secureToken)
TypeError: write() argument must be str, not bytes
root@r-1037-VM:~#
```

* Python3: fix "name 'file' is not defined"

```
root@r-1037-VM:~# /opt/cloud/bin/passwd_server_ip.py 10.1.1.1
Traceback (most recent call last):
  File "/opt/cloud/bin/passwd_server_ip.py", line 201, in <module>
    serve()
  File "/opt/cloud/bin/passwd_server_ip.py", line 188, in serve
    loadPasswordFile()
  File "/opt/cloud/bin/passwd_server_ip.py", line 67, in loadPasswordFile
    with file(getPasswordFile()) as f:
NameError: name 'file' is not defined
```

* python3: fix "TypeError: write() argument must be str, not bytes" (two more files)

* Upgrade jaxb version

* python3: fix more "TypeError: a bytes-like object is required, not str"

* python3: fix "Failed to update password server"

Failed to update password server due to: POST data should be bytes, an iterable of bytes, or a file object. It cannot be of type str.

* python3: fix "bad duration value: ikelifetime=24.0h"

Jan 15 13:57:20 systemvm ipsec[3080]: # bad duration value: ikelifetime=24.0h

* python3: fix password server "invalid save_password token"

* test: incease retries in test_vpc_vpn.py

* python3: fix passwd_server_ip.py

see error below
```
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]: ----------------------------------------
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]: Exception occurred during processing of request from ('10.1.1.129', 32782)
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]: Traceback (most recent call last):
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/socketserver.py", line 650, in process_request_thread
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self.finish_request(request, client_address)
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/socketserver.py", line 360, in finish_request
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self.RequestHandlerClass(request, client_address, self)
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/socketserver.py", line 720, in __init__
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self.handle()
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/http/server.py", line 427, in handle
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self.handle_one_request()
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/http/server.py", line 415, in handle_one_request
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     method()
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/opt/cloud/bin/passwd_server_ip.py", line 120, in do_GET
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self.wfile.write(password)
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:   File "/usr/lib/python3.9/socketserver.py", line 799, in write
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]:     self._sock.sendall(b)
Jan 15 18:51:21 systemvm passwd_server_ip.py[1507]: TypeError: a bytes-like object is required, not 'str'
```

* python3: fix self.cl.get_router_password in Redundant VRs

```
File "/opt/cloud/bin/cs/CsDatabag.py", line 154, in get_router_password
    md5.update(passwd)
TypeError: Unicode-objects must be encoded before hashing"]
```

* scripts: mark multipath scripts as executable

* systemvm template: remove hyperv packages and do not export

* VR: update default RAM size of System VMs/VRs to 512MiB

Before
```
mysql> select id,name,cpu,speed,ram_size,unique_name,system_use from service_offering where name like "System%";
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
| id | name                                                     | cpu  | speed | ram_size | unique_name                      | system_use |
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
|  3 | System Offering For Software Router                      |    1 |   500 |      256 | Cloud.Com-SoftwareRouter         |          1 |
|  4 | System Offering For Software Router - Local Storage      |    1 |   500 |      256 | Cloud.Com-SoftwareRouter-Local   |          1 |
|  5 | System Offering For Internal LB VM                       |    1 |   256 |      256 | Cloud.Com-InternalLBVm           |          1 |
|  6 | System Offering For Internal LB VM - Local Storage       |    1 |   256 |      256 | Cloud.Com-InternalLBVm-Local     |          1 |
|  7 | System Offering For Console Proxy                        |    1 |   500 |     1024 | Cloud.com-ConsoleProxy           |          1 |
|  8 | System Offering For Console Proxy - Local Storage        |    1 |   500 |     1024 | Cloud.com-ConsoleProxy-Local     |          1 |
|  9 | System Offering For Secondary Storage VM                 |    1 |   500 |      512 | Cloud.com-SecondaryStorage       |          1 |
| 10 | System Offering For Secondary Storage VM - Local Storage |    1 |   500 |      512 | Cloud.com-SecondaryStorage-Local |          1 |
| 11 | System Offering For Elastic LB VM                        |    1 |   128 |      128 | Cloud.Com-ElasticLBVm            |          1 |
| 12 | System Offering For Elastic LB VM - Local Storage        |    1 |   128 |      128 | Cloud.Com-ElasticLBVm-Local      |          1 |
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
10 rows in set (0.00 sec)
```

New value
```
mysql> select id,name,cpu,speed,ram_size,unique_name,system_use from service_offering where name like "System%";
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
| id | name                                                     | cpu  | speed | ram_size | unique_name                      | system_use |
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
|  3 | System Offering For Software Router                      |    1 |   500 |      512 | Cloud.Com-SoftwareRouter         |          1 |
|  4 | System Offering For Software Router - Local Storage      |    1 |   500 |      512 | Cloud.Com-SoftwareRouter-Local   |          1 |
|  5 | System Offering For Internal LB VM                       |    1 |   256 |      512 | Cloud.Com-InternalLBVm           |          1 |
|  6 | System Offering For Internal LB VM - Local Storage       |    1 |   256 |      512 | Cloud.Com-InternalLBVm-Local     |          1 |
|  7 | System Offering For Console Proxy                        |    1 |   500 |     1024 | Cloud.com-ConsoleProxy           |          1 |
|  8 | System Offering For Console Proxy - Local Storage        |    1 |   500 |     1024 | Cloud.com-ConsoleProxy-Local     |          1 |
|  9 | System Offering For Secondary Storage VM                 |    1 |   500 |      512 | Cloud.com-SecondaryStorage       |          1 |
| 10 | System Offering For Secondary Storage VM - Local Storage |    1 |   500 |      512 | Cloud.com-SecondaryStorage-Local |          1 |
| 11 | System Offering For Elastic LB VM                        |    1 |   128 |      512 | Cloud.Com-ElasticLBVm            |          1 |
| 12 | System Offering For Elastic LB VM - Local Storage        |    1 |   128 |      512 | Cloud.Com-ElasticLBVm-Local      |          1 |
+----+----------------------------------------------------------+------+-------+----------+----------------------------------+------------+
10 rows in set (0.01 sec)
```

* debian12: fix test_network_ipv6 and test_vpc_ipv6

* python3: remove duplicated imports

* debian12: failed to start Apache2 server (SSLCipherSuite @SECLEVEL=0)

error message
```
[Sat Jan 20 22:51:14.595143 2024] [ssl:emerg] [pid 10200:tid 140417063888768] AH02562: Failed to configure certificate cloudinternal.com:443:0 (with chain), check /etc/ssl/certs/cert_apache.crt
[Sat Jan 20 22:51:14.595234 2024] [ssl:emerg] [pid 10200:tid 140417063888768] SSL Library Error: error:0A00018E:SSL routines::ca md too weak
AH00016: Configuration Failed
```

openssl version
```
root@s-167-VM:~# openssl version -a
OpenSSL 3.0.11 19 Sep 2023 (Library: OpenSSL 3.0.11 19 Sep 2023)
built on: Mon Oct 23 17:52:22 2023 UTC
platform: debian-amd64
options:  bn(64,64)
compiler: gcc -fPIC -pthread -m64 -Wa,--noexecstack -Wall -fzero-call-used-regs=used-gpr -DOPENSSL_TLS_SECURITY_LEVEL=2 -Wa,--noexecstack -g -O2 -ffile-prefix-map=/build/reproducible-path/openssl-3.0.11=. -fstack-protector-strong -Wformat -Werror=format-security -DOPENSSL_USE_NODELETE -DL_ENDIAN -DOPENSSL_PIC -DOPENSSL_BUILDING_OPENSSL -DNDEBUG -Wdate-time -D_FORTIFY_SOURCE=2
OPENSSLDIR: "/usr/lib/ssl"
ENGINESDIR: "/usr/lib/x86_64-linux-gnu/engines-3"
MODULESDIR: "/usr/lib/x86_64-linux-gnu/ossl-modules"
Seeding source: os-specific
CPUINFO: OPENSSL_ia32cap=0x80202001478bfffd:0x0
```

certificate
```
root@s-167-VM:~# keytool -printcert -rfc -file /usr/local/cloud/systemvm/certs/realhostip.crt
-----BEGIN CERTIFICATE-----
MIIFZTCCBE2gAwIBAgIHKBCduBUoKDANBgkqhkiG9w0BAQUFADCByjELMAkGA1UE
BhMCVVMxEDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAY
BgNVBAoTEUdvRGFkZHkuY29tLCBJbmMuMTMwMQYDVQQLEypodHRwOi8vY2VydGlm
aWNhdGVzLmdvZGFkZHkuY29tL3JlcG9zaXRvcnkxMDAuBgNVBAMTJ0dvIERhZGR5
IFNlY3VyZSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTERMA8GA1UEBRMIMDc5Njky
ODcwHhcNMTIwMjAzMDMzMDQwWhcNMTcwMjA3MDUxMTIzWjBZMRkwFwYDVQQKDBAq
LnJlYWxob3N0aXAuY29tMSEwHwYDVQQLDBhEb21haW4gQ29udHJvbCBWYWxpZGF0
ZWQxGTAXBgNVBAMMECoucmVhbGhvc3RpcC5jb20wggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQCDT9AtEfs+s/I8QXp6rrCw0iNJ0+GgsybNHheU+JpL39LM
TZykCrZhZnyDvwdxCoOfE38Sa32baHKNds+y2SHnMNsOkw8OcNucHEBX1FIpOBGp
h9D6xC+umx9od6xMWETUv7j6h2u+WC3OhBM8fHCBqIiAol31/IkcqDxxsHlQ8S/o
CfTlXJUY6Yn628OA1XijKdRnadV0hZ829cv/PZKljjwQUTyrd0KHQeksBH+YAYSo
2JUl8ekNLsOi8/cPtfojnltzRI1GXi0ZONs8VnDzJ0a2gqZY+uxlz+CGbLnGnlN4
j9cBpE+MfUE+35Dq121sTpsSgF85Mz+pVhn2S633AgMBAAGjggG+MIIBujAPBgNV
HRMBAf8EBTADAQEAMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAOBgNV
HQ8BAf8EBAMCBaAwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2NybC5nb2RhZGR5
LmNvbS9nZHMxLTY0LmNybDBTBgNVHSAETDBKMEgGC2CGSAGG/W0BBxcBMDkwNwYI
KwYBBQUHAgEWK2h0dHA6Ly9jZXJ0aWZpY2F0ZXMuZ29kYWRkeS5jb20vcmVwb3Np
dG9yeS8wgYAGCCsGAQUFBwEBBHQwcjAkBggrBgEFBQcwAYYYaHR0cDovL29jc3Au
Z29kYWRkeS5jb20vMEoGCCsGAQUFBzAChj5odHRwOi8vY2VydGlmaWNhdGVzLmdv
ZGFkZHkuY29tL3JlcG9zaXRvcnkvZ2RfaW50ZXJtZWRpYXRlLmNydDAfBgNVHSME
GDAWgBT9rGEyk2xF1uLuhV+auud2mWjM5zArBgNVHREEJDAighAqLnJlYWxob3N0
aXAuY29tgg5yZWFsaG9zdGlwLmNvbTAdBgNVHQ4EFgQUZyJz9/QLy5TWIIscTXID
E8Xk47YwDQYJKoZIhvcNAQEFBQADggEBAKiUV3KK16mP0NpS92fmQkCLqm+qUWyN
BfBVgf9/M5pcT8EiTZlS5nAtzAE/eRpBeR3ubLlaAogj4rdH7YYVJcDDLLoB2qM3
qeCHu8LFoblkb93UuFDWqRaVPmMlJRnhsRkL1oa2gM2hwQTkBDkP7w5FG1BELCgl
gZI2ij2yxjge6pOEwSyZCzzbCcg9pN+dNrYyGEtB4k+BBnPA3N4r14CWbk+uxjrQ
6j2Ip+b7wOc5IuMEMl8xwTyjuX3lsLbAZyFI9RCyofwA9NqIZ1GeB6Zd196rubQp
93cmBqGGjZUs3wMrGlm7xdjlX6GQ9UvmvkMub9+lL99A5W50QgCmFeI=
-----END CERTIFICATE-----

Warning:
The certificate uses the SHA1withRSA signature algorithm which is considered a security risk. This algorithm will be disabled in a future update.
```

it comes from
```
$ openssl x509 -in ./systemvm/agent/certs/realhostip.crt -noout -text
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 11277268652730408 (0x28109db8152828)
        Signature Algorithm: sha1WithRSAEncryption
        Issuer: C = US, ST = Arizona, L = Scottsdale, O = "GoDaddy.com, Inc.", OU = http://certificates.godaddy.com/repository, CN = Go Daddy Secure Certification Authority, serialNumber = 07969287
        Validity
            Not Before: Feb  3 03:30:40 2012 GMT
            Not After : Feb  7 05:11:23 2017 GMT
        Subject: O = *.realhostip.com, OU = Domain Control Validated, CN = *.realhostip.com
```

* debian12: use ed25519 instead of rsa as ssh-rsa has been deprecated in OpenSSH

on xenserver
```
[root@pr8497-t8906-xenserver-71-xs2 ~]# ssh -i .ssh/id_rsa.cloud -p 3922 169.254.214.153
Warning: Permanently added '[169.254.214.153]:3922' (ECDSA) to the list of known hosts.
Permission denied (publickey).
```
in the CPVM
Jan 22 19:31:09 v-1-VM sshd[2869]: userauth_pubkey: signature algorithm ssh-rsa not in PubkeyAcceptedAlgorithms [preauth]
Jan 22 19:31:09 v-1-VM sshd[2869]: Connection closed by authenticating user root 169.254.0.1 port 54704 [preauth]
```

ssh-dss (DSA) is not supported either

* debian12: add PubkeyAcceptedAlgorithms=+ssh-rsa to sshd_config

* VR: install python3 packages in case of Debian 11

* pom.xml: exclude systemvm/agent/packages/* in license check

* systemvm: do not patch router/systemvm during startup

this will cause 4.19 SYSTEM template not work, but may be expected
- python3 VS python2 (default)
- openSSL 3.0.1 VS 1.1.1w
- openssh-server 9.1 VS 8.4

* VR: patch router/systemvm if template is debian11

This supports debian 11 template by
- revert change in systemvm/debian/etc/ssh/sshd_config
- patch VR/systemvms during startup
- install packages during patching system vm/routers

* python3 flake: fix E502 the backslash is redundant between brackets

```
../debian/root/health_checks/router_version_check.py:55:70: E502 the backslash is redundant between brackets
../debian/root/health_checks/router_version_check.py:58:61: E502 the backslash is redundant between brackets
../debian/root/health_checks/router_version_check.py:67:71: E502 the backslash is redundant between brackets
../debian/root/health_checks/router_version_check.py:70:60: E502 the backslash is redundant between brackets
../debian/root/health_checks/haproxy_check.py:47:71: E502 the backslash is redundant between brackets
../debian/root/health_checks/haproxy_check.py:48:64: E502 the backslash is redundant between brackets
../debian/root/health_checks/cpu_usage_check.py:43:54: E502 the backslash is redundant between brackets
../debian/root/health_checks/cpu_usage_check.py:46:58: E502 the backslash is redundant between brackets
../debian/root/health_checks/memory_usage_check.py:31:65: E502 the backslash is redundant between brackets
../debian/root/health_checks/memory_usage_check.py:42:57: E502 the backslash is redundant between brackets
../debian/root/health_checks/memory_usage_check.py:45:63: E502 the backslash is redundant between brackets
```

* python3 flake: fix E275 missing whitespace after keyword

```
../debian/opt/cloud/bin/cs_firewallrules.py:29:20: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_dhcp.py:27:16: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_dhcp.py:36:16: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_guestnetwork.py:33:20: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_guestnetwork.py:35:16: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_vpnusers.py:37:16: E275 missing whitespace after keyword
../debian/opt/cloud/bin/merge.py:230:11: E275 missing whitespace after keyword
../debian/opt/cloud/bin/merge.py:239:19: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_remoteaccessvpn.py:24:12: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs_site2sitevpn.py:24:12: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs/CsHelper.py:90:15: E275 missing whitespace after keyword
../debian/opt/cloud/bin/cs/CsAddress.py:367:15: E275 missing whitespace after keyword
```

* python3 flake: fix configure.py

```
../debian/opt/cloud/bin/configure.py:24:22: E401 multiple imports on one line
../debian/opt/cloud/bin/configure.py:43:180: E501 line too long (294 > 179 characters)
../debian/opt/cloud/bin/configure.py:46:1: E302 expected 2 blank lines, found 1
../debian/opt/cloud/bin/configure.py:63:1: E302 expected 2 blank lines, found 1
../debian/opt/cloud/bin/configure.py:65:12: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`
../debian/opt/cloud/bin/configure.py:72:1: E302 expected 2 blank lines, found 1
../debian/opt/cloud/bin/configure.py:310:25: E711 comparison to None should be 'if cond is not None:'
../debian/opt/cloud/bin/configure.py:312:29: E711 comparison to None should be 'if cond is None:'
../debian/opt/cloud/bin/configure.py:378:25: E711 comparison to None should be 'if cond is not None:'
../debian/opt/cloud/bin/configure.py:380:29: E711 comparison to None should be 'if cond is None:'
../debian/opt/cloud/bin/configure.py:490:29: E712 comparison to False should be 'if cond is False:' or 'if not cond:'
../debian/opt/cloud/bin/configure.py:642:16: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`
../debian/opt/cloud/bin/configure.py:644:18: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`
../debian/opt/cloud/bin/configure.py:1416:1: E305 expected 2 blank lines after class or function definition, found 1
```

* python3 flake: fix other python files

```
../debian/opt/cloud/bin/vmdata.py:97:12: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`
../debian/opt/cloud/bin/vmdata.py:99:14: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`

../debian/opt/cloud/bin/cs/CsRedundant.py:438:53: E203 whitespace before ':'
../debian/opt/cloud/bin/cs/CsRedundant.py:461:53: E203 whitespace before ':'
../debian/opt/cloud/bin/cs/CsRedundant.py:499:5: E303 too many blank lines (2)

../debian/opt/cloud/bin/cs/CsDatabag.py:189:1: E302 expected 2 blank lines, found 1
../debian/opt/cloud/bin/cs/CsDatabag.py:193:37: E721 do not compare types, for exact checks use `is` / `is not`, for instance checks use `isinstance()`

../debian/opt/cloud/bin/cs/CsHelper.py:118:30: E231 missing whitespace after ','
../debian/opt/cloud/bin/cs/CsHelper.py:119:15: E225 missing whitespace around operator
../debian/opt/cloud/bin/cs/CsHelper.py:127:19: E225 missing whitespace around operator

../debian/opt/cloud/bin/cs/CsAddress.py:324:43: E221 multiple spaces before operator

../debian/opt/cloud/bin/cs/CsVpcGuestNetwork.py:28:1: E302 expected 2 blank lines, found 1
```

* python3 flake: fix CsNetfilter.py

```
../debian/opt/cloud/bin/cs/CsNetfilter.py:226:13: E117 over-indented
../debian/opt/cloud/bin/cs/CsNetfilter.py:233:180: E501 line too long (197 > 179 characters)
../debian/opt/cloud/bin/cs/CsNetfilter.py:241:14: E201 whitespace after '{'
../debian/opt/cloud/bin/cs/CsNetfilter.py:242:14: E201 whitespace after '{'
../debian/opt/cloud/bin/cs/CsNetfilter.py:247:18: E201 whitespace after '{'
../debian/opt/cloud/bin/cs/CsNetfilter.py:247:74: E202 whitespace before '}'
../debian/opt/cloud/bin/cs/CsNetfilter.py:248:18: E201 whitespace after '{'
```

* systemvm/test: fix sys.path

```
$ bash runtests.sh
/usr/bin/python
Python 3.10.12
Running pycodestyle to check systemvm/python code for errors
Running pylint to check systemvm/python code for errors
Python 3.10.12
pylint 2.12.2
astroid 2.9.3
Python 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0]

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)

--------------------------------------------------------------------
Your code has been rated at 10.00/10 (previous run: 10.00/10, +0.00)

Running systemvm/python unit tests
....Device "eth0" does not exist.
.....................
----------------------------------------------------------------------
Ran 25 tests in 0.008s

OK
```

* Revert "systemvm template: remove hyperv packages and do not export"

This reverts commit 4383d59d031bde6eae7ebba261ff641ca0a66cd5.

* debian12: move SQL change to schema-41900to42000.sql

* debian12: update systemvm template version to 4.20 in pom.xml

* pom.xml: fix NPE if templates do not exist on download.cloudstack.org

* debian12: increase default system offering for routers to 384MiB RAM

* CKS: fix addkubernetessupportedversion failed with JRE17

```
marvin.cloudstackException.CloudstackAPIException: Execute cmd: addkubernetessupportedversion failed, due to: errorCode: 530, errorText:Cannot invoke "org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine$State.toString()" because the return value of "com.cloud.api.query.vo.TemplateJoinVO.getState()" is null
```

* python3: revert changes by 2to3 with systemvm/debian/root/health_checks/*.py

* debian12: use ISO/packages on download.cloudstack.org

* VR: Update default ram size to 384

* debian12: fix router_version_check.py after VR live-patch and add health check in test_routers.py

* debian12: fix build error after log4j 2.x merge

* VR: Update default ram size to 512MB (again)

This reverts commit 578dd2b73f380e8231ae1eb59827230757cac5e8 and efafa8c4d63775653a2cd406fca10784fbcec3e3.

* systemvmtemplate: Upgrade to Debian 12.5.0

* systemvm template: increase swap to 512MB

* VR: fix health check error due to deprecated SafeConfigParser

warning below
```
root@r-20-VM:~# /opt/cloud/bin/getRouterMonitorResults.sh true
/root/monitorServices.py:59: DeprecationWarning: The SafeConfigParser class has been renamed to ConfigParser in Python 3.2. This alias will be removed in Python 3.12. Use ConfigParser directly instead.
  parser = SafeConfigParser()
```

* test: fix wget does not work in macchinina vms on vmware80u1

fixes error below
```
{Cmd: wget -t 1 -T 1 www.google.com via Host: 10.0.55.186} {returns: ["wget: '/usr/lib/libpcre.so.1' is not an ELF file", "wget: can't load library 'libpcre.so.1'"]}
```

* packaging: add message for VR memory upgrade after packages installation

---------

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
Co-authored-by: Rohit Yadav <rohit.yadav@shapeblue.com>
Co-authored-by: Vishesh <vishesh92@gmail.com>
2024-02-26 18:07:50 +05:30

853 lines
35 KiB
Python
Executable File

# -- coding: utf-8 --
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
import logging
from netaddr import IPAddress, IPNetwork
import subprocess
import time
from . import CsHelper
from .CsDatabag import CsDataBag
from .CsApp import CsApache, CsDnsmasq, CsPasswdSvc
from .CsRoute import CsRoute
from .CsRule import CsRule
VRRP_TYPES = ['guest']
class CsAddress(CsDataBag):
def compare(self):
for dev in CsDevice('', self.config).list():
ip = CsIP(dev, self.config)
ip.compare(self.dbag)
def get_interfaces(self):
interfaces = []
for dev in self.dbag:
if dev == "id":
continue
for ip in self.dbag[dev]:
interfaces.append(CsInterface(ip, self.config))
return interfaces
def get_guest_if(self):
"""
Return CsInterface object for the lowest in use guest interface
"""
guest_interface = None
lowest_device = 1000
for interface in self.get_interfaces():
if interface.is_guest() and interface.is_added():
device = interface.get_device()
device_suffix = int(''.join([digit for digit in device if digit.isdigit()]))
if device_suffix < lowest_device:
lowest_device = device_suffix
guest_interface = interface
logging.debug("Guest interface will be set on device '%s' and IP '%s'" % (guest_interface.get_device(), guest_interface.get_ip()))
return guest_interface
def get_guest_ip(self):
"""
Return the ip of the first guest interface
For use with routers not vpcrouters
"""
ip = self.get_guest_if()
if ip:
return ip.get_ip()
return None
def get_guest_netmask(self):
"""
Return the netmask of the first guest interface
For use with routers not vpcrouters
"""
ip = self.get_guest_if()
if ip:
return ip.get_netmask()
return "255.255.255.0"
def needs_vrrp(self, o):
"""
Returns if the ip needs to be managed by keepalived or not
"""
if "nw_type" in o and o['nw_type'] in VRRP_TYPES:
return True
return False
def get_control_if(self):
"""
Return the address object that has the control interface
"""
for interface in self.get_interfaces():
if interface.is_control():
return interface
return None
def process(self):
for dev in self.dbag:
if dev == "id":
continue
ip = CsIP(dev, self.config)
for address in self.dbag[dev]:
ip.setAddress(address)
logging.info("Address found in DataBag ==> %s" % address)
if not address['add'] and not ip.configured():
logging.info("Skipping %s as the add flag is set to %s " % (address['public_ip'], address['add']))
continue
if ip.configured():
logging.info(
"Address %s on device %s already configured", ip.ip(), dev)
ip.post_configure(address)
else:
logging.info(
"Address %s on device %s not configured", ip.ip(), dev)
if CsDevice(dev, self.config).waitfordevice():
ip.configure(address)
class CsInterface:
""" Hold one single ip """
def __init__(self, o, config):
self.address = o
self.config = config
def get_ip(self):
return self.get_attr("public_ip")
def get_ip6(self):
if not self.config.is_vpc():
return self.config.cmdline().get_dev_ip6prelen(self.get_device())
if self.is_public():
return self.config.guestnetwork().get_router_ip6prelen()
elif self.is_guest():
return self.config.guestnetwork().get_dev_ip6prelen(self.get_device())
return self.get_attr("public_ip6")
def get_network(self):
return self.get_attr("network")
def get_netmask(self):
return self.get_attr("netmask")
def get_gateway(self):
if self.config.is_vpc() or not self.is_guest():
return self.get_attr("gateway")
else:
return self.config.cmdline().get_guest_gw()
def get_gateway6(self):
if self.config.is_vpc():
if self.is_public():
return self.config.guestnetwork().get_router_ip6gateway()
elif self.is_guest():
return self.config.guestnetwork().get_dev_ip6gateway(self.get_device())
else:
if self.is_public():
return self.config.cmdline().get_ip6gateway()
elif self.is_guest():
return self.config.cmdline().get_guest_ip6gateway()
return self.get_attr("gateway6")
def ip_in_subnet(self, ip):
ipo = IPAddress(ip)
net = IPNetwork("%s/%s" % (self.get_ip(), self.get_size()))
return ipo in net
def get_gateway_cidr(self):
return "%s/%s" % (self.get_gateway(), self.get_size())
def get_gateway6_cidr(self):
gw6 = self.get_gateway6()
cidr6_size = self.get_cidr6_size()
if not gw6 or not cidr6_size or gw6 == "ERROR" or cidr6_size == "ERROR":
return False
return "%s/%s" % (self.get_gateway6(), self.get_cidr6_size())
def get_size(self):
""" Return the network size in bits (24, 16, 8 etc) """
return self.get_attr("size")
def get_cidr6_size(self):
if self.config.is_vpc() and self.is_guest():
return self.config.guestnetwork().get_dev_ip6cidr(self.get_device())
elif not self.config.is_vpc() and self.is_guest():
return self.config.cmdline().get_guest_ip6cidr_size()
return self.get_attr("size6")
def get_device(self):
return self.get_attr("device")
def get_cidr(self):
return self.get_attr("cidr")
def get_broadcast(self):
return self.get_attr("broadcast")
def get_attr(self, attr):
if attr in self.address:
return self.address[attr]
else:
return "ERROR"
def needs_vrrp(self):
"""
Returns if the ip needs to be managed by keepalived or not
"""
if "nw_type" in self.address and self.address['nw_type'] in VRRP_TYPES:
return True
return False
def is_control(self):
if "nw_type" in self.address and self.address['nw_type'] in ['control']:
return True
return False
def is_guest(self):
if "nw_type" in self.address and self.address['nw_type'] in ['guest']:
return True
return False
def is_public(self):
if "nw_type" in self.address and self.address['nw_type'] in ['public']:
return True
return False
def is_private_gateway(self):
if "is_private_gateway" in self.address:
return self.address['is_private_gateway']
return False
def is_added(self):
return self.get_attr("add")
def to_str(self):
return self.address
class CsDevice:
""" Configure Network Devices """
def __init__(self, dev, config):
self.devlist = []
self.dev = dev
self.buildlist()
self.table = ''
self.tableNo = ''
if dev != '':
self.tableNo = dev[3:]
self.table = "Table_%s" % dev
self.fw = config.get_fw()
self.cl = config.cmdline()
def configure_rp(self):
"""
Configure Reverse Path Filtering
"""
filename = "/proc/sys/net/ipv4/conf/%s/rp_filter" % self.dev
CsHelper.updatefile(filename, "1\n", "w")
def buildlist(self):
"""
List all available network devices on the system
"""
self.devlist = []
for line in open('/proc/net/dev'):
vals = line.lstrip().split(':')
if (not vals[0].startswith("eth")):
continue
self.devlist.append(vals[0])
def waitfordevice(self, timeout=2):
count = 0
while count < timeout:
if self.dev in self.devlist:
return True
time.sleep(1)
count += 1
self.buildlist()
logging.error(
"Device %s cannot be configured - device was not found", self.dev)
return False
def list(self):
return self.devlist
class CsIP:
DEFAULT_MTU = '1500'
def __init__(self, dev, config):
self.dev = dev
self.dnum = hex(100 + int(dev[3:]))
self.iplist = {}
self.address = {}
self.list()
self.fw = config.get_fw()
self.cl = config.cmdline()
self.config = config
def setAddress(self, address):
self.address = address
def getAddress(self):
return self.address
def configure(self, address):
# When "add" is false, it means that the IP has to be removed.
if address["add"]:
try:
logging.info("Configuring address %s on device %s", self.ip(), self.dev)
cmd = "ip addr add dev %s %s brd +" % (self.dev, self.ip())
CsHelper.execute(cmd)
cmd = "ifconfig %s mtu %s" % (self.dev, self.mtu())
CsHelper.execute(cmd)
except Exception as e:
logging.info("Exception occurred ==> %s" % e)
self.post_configure(address)
else:
# delete method performs post_configure, so no need to call post_configure here
self.delete(self.ip())
def post_configure(self, address):
""" The steps that must be done after a device is configured """
route = CsRoute()
if not self.get_type() in ["control"]:
route.add_table(self.dev)
CsRule(self.dev).addMark()
interfaces = [CsInterface(address, self.config)]
CsHelper.reconfigure_interfaces(self.cl, interfaces)
if self.get_type() in ['public']:
self.set_mark()
if 'gateway' in self.address:
self.arpPing()
CsRpsrfs(self.dev).enable()
self.post_config_change("add")
'''For isolated/redundant and dhcpsrvr routers, call this method after the post_config is complete '''
if not self.config.is_vpc():
self.setup_router_control()
if self.config.is_vpc() or self.cl.is_redundant():
# The code looks redundant here, but we actually have to cater for routers and
# VPC routers in a different manner. Please do not remove this block otherwise
# The VPC default route will be broken.
if self.get_type() in ["public"] and address["device"] == CsHelper.PUBLIC_INTERFACES[self.cl.get_type()]:
gateway = str(address["gateway"])
route.add_defaultroute(gateway)
else:
# once we start processing public ip's we need to verify there
# is a default route and add if needed
if self.cl.get_gateway():
route.add_defaultroute(self.cl.get_gateway())
if self.config.is_router() and self.cl.get_ip6gateway():
route.add_defaultroute_v6(self.cl.get_ip6gateway())
def set_mark(self):
cmd = "-A PREROUTING -i %s -m state --state NEW -j CONNMARK --set-xmark %s/0xffffffff" % \
(self.getDevice(), self.dnum)
self.fw.append(["mangle", "", cmd])
def get_type(self):
""" Return the type of the IP
guest
control
public
"""
if "nw_type" in self.address:
return self.address['nw_type']
return "unknown"
def get_ip_address(self):
"""
Return ip address if known
"""
if "public_ip" in self.address:
return self.address['public_ip']
return "unknown"
def mtu(self):
logging.info(self.address)
if "mtu" in self.address:
return self.address['mtu']
return CsIP.DEFAULT_MTU
def setup_router_control(self):
if self.config.is_vpc():
return
self.fw.append(
["filter", "", "-A FW_OUTBOUND -m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(
["filter", "", "-A INPUT -i eth1 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-P INPUT DROP"])
self.fw.append(["filter", "", "-P FORWARD DROP"])
def fw_router(self):
if self.config.is_vpc():
return
self.fw.append(["mangle", "front", "-A PREROUTING " +
"-m state --state RELATED,ESTABLISHED " +
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
self.fw.append(["mangle", "front",
"-A POSTROUTING " +
"-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
if self.get_type() in ["public"]:
self.fw.append(["mangle", "front",
"-A PREROUTING " +
"-d %s/32 -j VPN_%s" % (self.address['public_ip'], self.address['public_ip'])])
self.fw.append(["mangle", "front",
"-A PREROUTING " +
"-d %s/32 -j FIREWALL_%s" % (self.address['public_ip'], self.address['public_ip'])])
self.fw.append(["mangle", "front",
"-A FIREWALL_%s " % self.address['public_ip'] +
"-m state --state RELATED,ESTABLISHED -j RETURN"])
self.fw.append(["mangle", "",
"-A FIREWALL_%s -j DROP" % self.address['public_ip']])
self.fw.append(["mangle", "",
"-I VPN_%s -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.address['public_ip']])
self.fw.append(["mangle", "",
"-A VPN_%s -j RETURN" % self.address['public_ip']])
self.fw.append(
["", "front", "-A FORWARD -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "front", "-A INPUT -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "front", "-A OUTPUT -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -i eth0 -o %s" % (self.dev, self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -i %s -o eth0" % (self.dev, self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -o %s ! -i eth0 -p tcp" % (self.dev, self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -i %s ! -o eth0 -p tcp" % (self.dev, self.dev)])
self.fw.append(
["nat", "", "-A POSTROUTING -o %s -j SNAT --to-source %s" % (self.dev, self.cl.get_eth2_ip())])
self.fw.append(["mangle", "",
"-A PREROUTING -i %s -m state --state NEW " % self.dev +
"-j CONNMARK --set-xmark %s/0xffffffff" % self.dnum])
self.fw.append(["filter", "",
"-A FORWARD -i %s -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
self.fw.append(["filter", "",
"-A FORWARD -i eth0 -o %s -j FW_OUTBOUND" % self.dev])
self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -i %s -m state --state RELATED,ESTABLISHED -j ACCEPT" %
self.dev])
self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
if self.get_type() in ["guest"]:
guestNetworkCidr = self.address['network']
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A FORWARD -i %s -o eth1 -m state --state RELATED,ESTABLISHED -j ACCEPT" % self.dev])
self.fw.append(
["filter", "", "-A FORWARD -i %s -o %s -m state --state NEW -j ACCEPT" % (self.dev, self.dev)])
self.fw.append(
["filter", "", "-A FORWARD -i eth0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(['', 'front', '-A FORWARD -j NETWORK_STATS'])
self.fw.append(['', 'front', '-A INPUT -j NETWORK_STATS'])
self.fw.append(['', 'front', '-A OUTPUT -j NETWORK_STATS'])
self.fw.append(['', '', '-A NETWORK_STATS -i eth0 -o eth2'])
self.fw.append(['', '', '-A NETWORK_STATS -i eth2 -o eth0'])
self.fw.append(['', '', '-A NETWORK_STATS -o eth2 ! -i eth0 -p tcp'])
self.fw.append(['', '', '-A NETWORK_STATS -i eth2 ! -o eth0 -p tcp'])
def fw_vpcrouter(self):
if not self.config.is_vpc():
return
self.fw.append(["filter", "", "-A FORWARD -m state --state RELATED,ESTABLISHED -j ACCEPT"])
if self.get_type() in ["guest"]:
self.fw.append(["mangle", "front", "-A PREROUTING " +
" -i %s -m state --state RELATED,ESTABLISHED " % self.dev +
"-j CONNMARK --restore-mark --nfmask 0xffffffff --ctmask 0xffffffff"])
guestNetworkCidr = self.address['network']
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(guestNetworkCidr, self.dev, self.dev)])
self.fw.append(
["filter", "front", "-A ACL_INBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "front", "-A ACL_INBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
self.fw.append(
["mangle", "front", "-A ACL_OUTBOUND_%s -d 225.0.0.50/32 -j ACCEPT" % self.dev])
self.fw.append(
["mangle", "front", "-A ACL_OUTBOUND_%s -d 224.0.0.18/32 -j ACCEPT" % self.dev])
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 67 -j ACCEPT" % self.dev])
self.fw.append(
["mangle", "front", "-A POSTROUTING " + "-p udp -m udp --dport 68 -j CHECKSUM --checksum-fill"])
self.fw.append(
["filter", "", "-A INPUT -i %s -p udp -m udp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 53 -s %s -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 80 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 443 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(
["filter", "", "-A INPUT -i %s -p tcp -m tcp --dport 8080 -s %s -m state --state NEW -j ACCEPT" % (self.dev, guestNetworkCidr)])
self.fw.append(["mangle", "",
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
(self.dev, guestNetworkCidr, self.address['gateway'], self.dev)])
if self.is_private_gateway():
self.fw.append(["filter", "", "-A FORWARD -d %s -o %s -j ACL_INBOUND_%s" %
(self.address['network'], self.dev, self.dev)])
self.fw.append(["filter", "", "-A ACL_INBOUND_%s -j DROP" % self.dev])
self.fw.append(["mangle", "",
"-A PREROUTING -m state --state NEW -i %s -s %s ! -d %s/32 -j ACL_OUTBOUND_%s" %
(self.dev, self.address['network'], self.address['gateway'], self.dev)])
self.fw.append(["mangle", "front",
"-A PREROUTING -s %s -d %s -m state --state NEW -j MARK --set-xmark %s/0xffffffff" %
(self.cl.get_vpccidr(), self.address['network'], hex(100 + int(self.dev[3:])))])
if self.address["source_nat"]:
self.fw.append(["nat", "front",
"-A POSTROUTING -o %s -j SNAT --to-source %s" %
(self.dev, self.address['public_ip'])])
if self.get_gateway() == self.get_ip_address():
for inf, addresses in self.config.address().dbag.items():
if not inf.startswith("eth"):
continue
for address in addresses:
if "nw_type" in address and address["nw_type"] == "guest" and address["add"]:
self.fw.append(["filter", "front", "-A FORWARD -s %s -d %s -j ACL_INBOUND_%s" %
(address["network"], self.address["network"], self.dev)])
self.fw.append(["filter", "front", "-A FORWARD -s %s -d %s -j ACL_INBOUND_%s" %
(self.address["network"], address["network"], address["device"])])
# Accept packet from private gateway if VPC VR is used as gateway
self.fw.append(["filter", "", "-A FORWARD -s %s ! -d %s -j ACCEPT" %
(self.address['network'], self.address['network'])])
if self.get_type() in ["public"]:
self.fw.append(
["mangle", "", "-A FORWARD -j VPN_STATS_%s" % self.dev])
self.fw.append(
["mangle", "", "-A VPN_STATS_%s -o %s -m mark --mark 0x525/0xffffffff" % (self.dev, self.dev)])
self.fw.append(
["mangle", "", "-A VPN_STATS_%s -i %s -m mark --mark 0x524/0xffffffff" % (self.dev, self.dev)])
self.fw.append(
["", "front", "-A FORWARD -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "front", "-A INPUT -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "front", "-A OUTPUT -j NETWORK_STATS_%s" % self.dev])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -s %s -o %s" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s -d %s -i %s" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s ! -s %s -o %s -p tcp" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(
["", "", "-A NETWORK_STATS_%s ! -d %s -i %s -p tcp" % (self.dev, self.cl.get_vpccidr(), self.dev)])
self.fw.append(["filter", "", "-A INPUT -d 224.0.0.18/32 -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -d 225.0.0.50/32 -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -p icmp -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -i lo -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -i eth0 -p tcp -m tcp --dport 3922 -m state --state NEW,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT"])
self.fw.append(["filter", "", "-P INPUT DROP"])
self.fw.append(["filter", "", "-P FORWARD DROP"])
def post_config_change(self, method):
route = CsRoute()
tableName = "Table_" + self.dev
if method == "add":
if not self.config.is_vpc():
if self.get_type() in ["public"]:
route.set_route("table %s throw %s proto static" % (tableName, self.config.address().dbag['eth0'][0]['network']))
route.set_route("table %s throw %s proto static" % (tableName, self.config.address().dbag['eth1'][0]['network']))
# add 'default via gateway' rule in the device specific routing table
if "gateway" in self.address and self.address["gateway"] and self.address["gateway"] != "None":
route.add_route(self.dev, self.address["gateway"])
if "network" in self.address and self.address["network"]:
route.add_network_route(self.dev, str(self.address["network"]))
if self.get_type() in ["public"]:
CsRule(self.dev).addRule("from " + str(self.address["network"]))
if self.config.is_vpc():
if self.get_type() in ["public"] and "gateway" in self.address and self.address["gateway"] and self.address["gateway"] != "None":
route.add_route(self.dev, self.address["gateway"])
for inf, addresses in self.config.address().dbag.items():
if not inf.startswith("eth"):
continue
for address in addresses:
if "nw_type" in address and address["nw_type"] == "guest":
route.add_network_route(self.dev, str(address["network"]))
if self.get_type() in ["public"]:
CsRule(self.dev).addRule("from " + str(self.address["network"]))
route.add_network_route(self.dev, str(self.address["network"]))
CsHelper.execute("sudo ip route flush cache")
elif method == "delete":
# treat the last IP to be dis-associated with interface as special case to clean up the routing rules
if self.get_type() in ["public"] and (not self.config.is_vpc()) and (len(self.iplist) == 0):
CsHelper.execute("sudo ip rule delete table " + tableName)
CsHelper.execute("sudo ip route flush table " + tableName)
CsHelper.execute("sudo ip route flush cache")
CsRule(self.dev).delMark()
self.fw_router()
self.fw_vpcrouter()
cmdline = self.config.cmdline()
# On deletion nw_type will no longer be known
if self.get_type() in ('guest'):
if self.config.is_vpc() or self.config.is_router():
CsDevice(self.dev, self.config).configure_rp()
logging.error(
"Not able to setup source-nat for a regular router yet")
if (self.config.has_dns() or self.config.is_dhcp()) and self.config.expose_dns():
logging.info("Making dns publicly available")
dns = CsDnsmasq(self)
dns.add_firewall_rules()
else:
logging.info("Not making dns publicly available")
if self.config.has_metadata():
if method == "add":
app = CsApache(self)
app.setup()
elif method == "delete":
app = CsApache(self)
app.remove()
# If redundant then this is dealt with
# by the primary backup functions
if not cmdline.is_redundant():
if method == "add":
CsPasswdSvc(self.address['public_ip']).start()
elif method == "delete":
CsPasswdSvc(self.address['public_ip']).stop()
elif cmdline.is_primary():
if method == "add":
CsPasswdSvc(self.get_gateway() + "," + self.address['public_ip']).start()
elif method == "delete":
CsPasswdSvc(self.get_gateway() + "," + self.address['public_ip']).stop()
if self.get_type() == "public" and self.config.is_vpc() and method == "add":
if self.address["source_nat"]:
vpccidr = cmdline.get_vpccidr()
self.fw.append(
["filter", 3, "-A FORWARD -s %s ! -d %s -j ACCEPT" % (vpccidr, vpccidr)])
self.fw.append(
["nat", "", "-A POSTROUTING -j SNAT -o %s --to-source %s" % (self.dev, self.address['public_ip'])])
elif cmdline.get_source_nat_ip() and not self.is_private_gateway():
self.fw.append(
["nat", "", "-A POSTROUTING -j SNAT -o %s --to-source %s" % (self.dev, cmdline.get_source_nat_ip())])
def list(self):
self.iplist = {}
cmd = ("ip addr show dev " + self.dev)
for i in CsHelper.execute(cmd):
vals = i.lstrip().split()
if (vals[0] == 'inet'):
cidr = vals[1]
self.iplist[cidr] = self.dev
def configured(self):
if self.address['cidr'] in list(self.iplist.keys()):
return True
return False
def needs_vrrp(self):
"""
Returns if the ip needs to be managed by keepalived or not
"""
if "nw_type" in self.address and self.address['nw_type'] in VRRP_TYPES:
return True
return False
def is_public(self):
if "nw_type" in self.address and self.address['nw_type'] in ['public']:
return True
return False
def is_private_gateway(self):
if "is_private_gateway" in self.address:
return self.address['is_private_gateway']
return False
def ip(self):
return str(self.address['cidr'])
def getDevice(self):
return self.dev
def hasIP(self, ip):
return ip in list(self.address.values())
def arpPing(self):
cmd = "arping -c 1 -I %s -A -U -s %s %s" % (
self.dev, self.address['public_ip'], self.address['gateway'])
if not self.cl.is_redundant() and (not self.address['gateway'] or self.address['gateway'] == "None"):
cmd = "arping -c 1 -I %s -A -U %s" % (self.dev, self.address['public_ip'])
CsHelper.execute2(cmd, False)
# Delete any ips that are configured but not in the bag
def compare(self, bag):
if len(self.iplist) > 0 and (self.dev not in list(bag.keys()) or len(bag[self.dev]) == 0):
# Remove all IPs on this device
logging.info(
"Will remove all configured addresses on device %s", self.dev)
self.delete("all")
app = CsApache(self)
app.remove()
# This condition should not really happen but did :)
# It means an apache file got orphaned after a guest network address
# was deleted
if len(self.iplist) == 0 and (self.dev not in list(bag.keys()) or len(bag[self.dev]) == 0):
app = CsApache(self)
app.remove()
for ip in self.iplist:
found = False
if self.dev in list(bag.keys()):
for address in bag[self.dev]:
self.setAddress(address)
if (self.hasIP(ip) or self.is_guest_gateway(address, ip)) and address["add"]:
logging.debug("The IP address in '%s' will be configured" % address)
found = True
if not found:
self.delete(ip)
def get_gateway(self):
interface = CsInterface(self.address, self.config)
return interface.get_gateway()
def is_guest_gateway(self, bag, ip):
""" Exclude the vrrp maintained addresses on a redundant router """
interface = CsInterface(bag, self.config)
if not self.config.cl.is_redundant():
return False
rip = ip.split('/')[0]
logging.info("Checking if cidr is a gateway for rVPC. IP ==> %s / device ==> %s", ip, self.dev)
gw = interface.get_gateway()
logging.info("Interface has the following gateway ==> %s", gw)
if bag['nw_type'] == "guest" and rip == gw:
return True
return False
def delete(self, ip):
remove = []
if ip == "all":
logging.info("Removing addresses from device %s", self.dev)
remove = list(self.iplist.keys())
else:
remove.append(ip)
for ip in remove:
cmd = "ip addr del dev %s %s" % (self.dev, ip)
subprocess.call(cmd, shell=True)
logging.info("Removed address %s from device %s", ip, self.dev)
self.post_config_change("delete")
class CsRpsrfs:
""" Configure rpsrfs if there is more than one cpu """
def __init__(self, dev):
self.dev = dev
def enable(self):
if not self.inKernel():
return
cpus = self.cpus()
if cpus < 2:
return
val = format((1 << cpus) - 1, "x")
filename = "/sys/class/net/%s/queues/rx-0/rps_cpus" % (self.dev)
CsHelper.updatefile(filename, val, "w+")
CsHelper.updatefile(
"/proc/sys/net/core/rps_sock_flow_entries", "256", "w+")
filename = "/sys/class/net/%s/queues/rx-0/rps_flow_cnt" % (self.dev)
CsHelper.updatefile(filename, "256", "w+")
logging.debug("rpsfr is configured for %s cpus" % (cpus))
def inKernel(self):
try:
open('/etc/rpsrfsenable')
except IOError:
logging.debug("rpsfr is not present in the kernel")
return False
else:
logging.debug("rpsfr is present in the kernel")
return True
def cpus(self):
count = 0
for line in open('/proc/cpuinfo'):
if "processor" not in line:
continue
count += 1
if count < 2:
logging.debug("Single CPU machine")
return count