pyxecm 2.0.0__py3-none-any.whl → 2.0.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of pyxecm might be problematic. Click here for more details.
- pyxecm/__init__.py +2 -1
- pyxecm/avts.py +79 -33
- pyxecm/customizer/api/app.py +45 -796
- pyxecm/customizer/api/auth/__init__.py +1 -0
- pyxecm/customizer/api/{auth.py → auth/functions.py} +2 -64
- pyxecm/customizer/api/auth/router.py +78 -0
- pyxecm/customizer/api/common/__init__.py +1 -0
- pyxecm/customizer/api/common/functions.py +47 -0
- pyxecm/customizer/api/{metrics.py → common/metrics.py} +1 -1
- pyxecm/customizer/api/common/models.py +21 -0
- pyxecm/customizer/api/{payload_list.py → common/payload_list.py} +6 -1
- pyxecm/customizer/api/common/router.py +72 -0
- pyxecm/customizer/api/settings.py +25 -0
- pyxecm/customizer/api/terminal/__init__.py +1 -0
- pyxecm/customizer/api/terminal/router.py +87 -0
- pyxecm/customizer/api/v1_csai/__init__.py +1 -0
- pyxecm/customizer/api/v1_csai/router.py +87 -0
- pyxecm/customizer/api/v1_maintenance/__init__.py +1 -0
- pyxecm/customizer/api/v1_maintenance/functions.py +100 -0
- pyxecm/customizer/api/v1_maintenance/models.py +12 -0
- pyxecm/customizer/api/v1_maintenance/router.py +76 -0
- pyxecm/customizer/api/v1_otcs/__init__.py +1 -0
- pyxecm/customizer/api/v1_otcs/functions.py +61 -0
- pyxecm/customizer/api/v1_otcs/router.py +179 -0
- pyxecm/customizer/api/v1_payload/__init__.py +1 -0
- pyxecm/customizer/api/v1_payload/functions.py +179 -0
- pyxecm/customizer/api/v1_payload/models.py +51 -0
- pyxecm/customizer/api/v1_payload/router.py +499 -0
- pyxecm/customizer/browser_automation.py +567 -324
- pyxecm/customizer/customizer.py +204 -430
- pyxecm/customizer/guidewire.py +907 -43
- pyxecm/customizer/k8s.py +243 -56
- pyxecm/customizer/m365.py +104 -15
- pyxecm/customizer/payload.py +1943 -885
- pyxecm/customizer/pht.py +19 -2
- pyxecm/customizer/servicenow.py +22 -5
- pyxecm/customizer/settings.py +9 -6
- pyxecm/helper/xml.py +69 -0
- pyxecm/otac.py +1 -1
- pyxecm/otawp.py +2104 -1535
- pyxecm/otca.py +569 -0
- pyxecm/otcs.py +202 -38
- pyxecm/otds.py +35 -13
- {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/METADATA +6 -32
- pyxecm-2.0.2.dist-info/RECORD +76 -0
- {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/WHEEL +1 -1
- pyxecm-2.0.0.dist-info/RECORD +0 -54
- /pyxecm/customizer/api/{models.py → auth/models.py} +0 -0
- {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/licenses/LICENSE +0 -0
- {pyxecm-2.0.0.dist-info → pyxecm-2.0.2.dist-info}/top_level.txt +0 -0
pyxecm/customizer/pht.py
CHANGED
|
@@ -17,21 +17,38 @@ __email__ = "mdiefenb@opentext.com"
|
|
|
17
17
|
|
|
18
18
|
import json
|
|
19
19
|
import logging
|
|
20
|
+
import platform
|
|
21
|
+
import sys
|
|
20
22
|
import time
|
|
23
|
+
from importlib.metadata import version
|
|
21
24
|
|
|
22
25
|
import requests
|
|
23
26
|
from requests.auth import HTTPBasicAuth
|
|
24
27
|
|
|
25
28
|
from pyxecm.helper import Data
|
|
26
29
|
|
|
27
|
-
|
|
30
|
+
APP_NAME = "pyxecm"
|
|
31
|
+
APP_VERSION = version("pyxecm")
|
|
32
|
+
MODULE_NAME = APP_NAME + ".customizer.pht"
|
|
28
33
|
|
|
29
|
-
|
|
34
|
+
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
35
|
+
OS_INFO = f"{platform.system()} {platform.release()}"
|
|
36
|
+
ARCH_INFO = platform.machine()
|
|
37
|
+
REQUESTS_VERSION = requests.__version__
|
|
38
|
+
|
|
39
|
+
USER_AGENT = (
|
|
40
|
+
f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
|
|
41
|
+
f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
REQUEST_HEADERS = {"User-Agent": USER_AGENT, "accept": "application/json", "Content-Type": "application/json"}
|
|
30
45
|
|
|
31
46
|
REQUEST_TIMEOUT = 60
|
|
32
47
|
REQUEST_RETRY_DELAY = 20
|
|
33
48
|
REQUEST_MAX_RETRIES = 2
|
|
34
49
|
|
|
50
|
+
default_logger = logging.getLogger(MODULE_NAME)
|
|
51
|
+
|
|
35
52
|
|
|
36
53
|
class PHT:
|
|
37
54
|
"""Class PHT is used to retrieve data from OpenText PHT. It is a pure read-only access."""
|
pyxecm/customizer/servicenow.py
CHANGED
|
@@ -12,12 +12,15 @@ __email__ = "mdiefenb@opentext.com"
|
|
|
12
12
|
import json
|
|
13
13
|
import logging
|
|
14
14
|
import os
|
|
15
|
+
import platform
|
|
16
|
+
import sys
|
|
15
17
|
import tempfile
|
|
16
18
|
import threading
|
|
17
19
|
import time
|
|
18
20
|
import urllib.parse
|
|
19
21
|
from collections.abc import Callable
|
|
20
22
|
from functools import cache
|
|
23
|
+
from importlib.metadata import version
|
|
21
24
|
from typing import Any
|
|
22
25
|
|
|
23
26
|
import requests
|
|
@@ -26,14 +29,28 @@ from requests.exceptions import HTTPError, RequestException
|
|
|
26
29
|
|
|
27
30
|
from pyxecm.helper import Data
|
|
28
31
|
|
|
29
|
-
|
|
32
|
+
APP_NAME = "pyxecm"
|
|
33
|
+
APP_VERSION = version("pyxecm")
|
|
34
|
+
MODULE_NAME = APP_NAME + ".customizer.servicenow"
|
|
30
35
|
|
|
31
|
-
|
|
36
|
+
PYTHON_VERSION = f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}"
|
|
37
|
+
OS_INFO = f"{platform.system()} {platform.release()}"
|
|
38
|
+
ARCH_INFO = platform.machine()
|
|
39
|
+
REQUESTS_VERSION = requests.__version__
|
|
40
|
+
|
|
41
|
+
USER_AGENT = (
|
|
42
|
+
f"{APP_NAME}/{APP_VERSION} ({MODULE_NAME}/{APP_VERSION}; "
|
|
43
|
+
f"Python/{PYTHON_VERSION}; {OS_INFO}; {ARCH_INFO}; Requests/{REQUESTS_VERSION})"
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
REQUEST_HEADERS = {"User-Agent": USER_AGENT, "Accept": "application/json", "Content-Type": "application/json"}
|
|
32
47
|
|
|
33
48
|
REQUEST_TIMEOUT = 60
|
|
34
49
|
|
|
35
50
|
KNOWLEDGE_BASE_PATH = os.path.join(tempfile.gettempdir(), "attachments")
|
|
36
51
|
|
|
52
|
+
default_logger = logging.getLogger(MODULE_NAME)
|
|
53
|
+
|
|
37
54
|
# ServiceNow database tables. Table names starting with "u_" are custom OpenText tables:
|
|
38
55
|
SN_TABLE_CATEGORIES = "kb_category"
|
|
39
56
|
SN_TABLE_KNOWLEDGE_BASES = "kb_knowledge_base"
|
|
@@ -78,7 +95,7 @@ class ServiceNow:
|
|
|
78
95
|
base_url (str):
|
|
79
96
|
The base URL of the ServiceNow tenant.
|
|
80
97
|
auth_type (str):
|
|
81
|
-
|
|
98
|
+
The authorization type, either "oauth" or "basic".
|
|
82
99
|
client_id (str):
|
|
83
100
|
ServiceNow Client ID.
|
|
84
101
|
client_secret (str):
|
|
@@ -168,7 +185,7 @@ class ServiceNow:
|
|
|
168
185
|
|
|
169
186
|
Returns:
|
|
170
187
|
dict:
|
|
171
|
-
The configuration dictionary.
|
|
188
|
+
The configuration dictionary with all settings.
|
|
172
189
|
|
|
173
190
|
"""
|
|
174
191
|
|
|
@@ -387,7 +404,7 @@ class ServiceNow:
|
|
|
387
404
|
|
|
388
405
|
return token
|
|
389
406
|
else:
|
|
390
|
-
self.logger.error("Unsupported authentication type")
|
|
407
|
+
self.logger.error("Unsupported authentication type -> %s!", auth_type)
|
|
391
408
|
return None
|
|
392
409
|
|
|
393
410
|
# end method definition
|
pyxecm/customizer/settings.py
CHANGED
|
@@ -19,7 +19,7 @@ class CustomizerSettingsOTDS(BaseModel):
|
|
|
19
19
|
username: str = Field(default="admin", description="Username for the OTDS admin user")
|
|
20
20
|
password: SecretStr = Field(default=None, description="Password for the OTDS admin user")
|
|
21
21
|
ticket: str | None = Field(None, description="Ticket for the OTDS admin user")
|
|
22
|
-
admin_partition: str = Field(default="otds.admin", description="Name of the
|
|
22
|
+
admin_partition: str = Field(default="otds.admin", description="Name of the admin partition in OTDS")
|
|
23
23
|
enable_audit: bool = Field(default=True, description="Enable the OTDS Audit")
|
|
24
24
|
disable_password_policy: bool = Field(
|
|
25
25
|
default=True,
|
|
@@ -68,6 +68,7 @@ class CustomizerSettingsOTCS(BaseModel):
|
|
|
68
68
|
username: str = Field(default="admin", description="Username for the OTCS admin user")
|
|
69
69
|
password: SecretStr = Field(default=None, description="Password for the OTCS admin user")
|
|
70
70
|
base_path: str = Field(default="/cs/cs", description="Base path of the OTCS installation")
|
|
71
|
+
support_path: str = Field(default="/cssupport", description="Support path of the OTCS installation")
|
|
71
72
|
url: HttpUrl | None = Field(default=None, description="URL of the OTCS service")
|
|
72
73
|
url_frontend: HttpUrl | None = Field(
|
|
73
74
|
default=None,
|
|
@@ -91,7 +92,7 @@ class CustomizerSettingsOTCS(BaseModel):
|
|
|
91
92
|
description="temporary download directory for payload processing",
|
|
92
93
|
)
|
|
93
94
|
|
|
94
|
-
# FEME endpoint for additional
|
|
95
|
+
# FEME endpoint for additional embedding supporting Content Aviator:
|
|
95
96
|
feme_uri: str = Field(default="ws://feme:4242", description="URL of the FEME endpoint")
|
|
96
97
|
|
|
97
98
|
# Add configuration options for Customizer behaviour
|
|
@@ -266,7 +267,7 @@ class CustomizerSettingsK8S(BaseModel):
|
|
|
266
267
|
sts_otcs_admin_replicas: int = Field(default=None)
|
|
267
268
|
ingress_otxecm: str = Field(default="otxecm-ingress", description="Name of the otxecm ingress")
|
|
268
269
|
|
|
269
|
-
maintenance_service_name: str = Field(default="
|
|
270
|
+
maintenance_service_name: str = Field(default="customizer")
|
|
270
271
|
maintenance_service_port: int = Field(default=5555)
|
|
271
272
|
|
|
272
273
|
|
|
@@ -279,6 +280,7 @@ class CustomizerSettingsOTAWP(BaseModel):
|
|
|
279
280
|
description="Username of the OTAWP Admin user",
|
|
280
281
|
)
|
|
281
282
|
password: SecretStr = Field(default=None, description="Password of the OTAWP Admin user")
|
|
283
|
+
organization: str = Field(default="system", description="The name of the organization (kind of tenant in AppWorks)")
|
|
282
284
|
license_file: str = Field(default="/payload/otawp-license.lic", description="Path to the OTAWP license file.")
|
|
283
285
|
product_name: str = Field(default="APPWORKS_PLATFORM", description="Name of the Product for the license")
|
|
284
286
|
product_description: str = Field(
|
|
@@ -351,7 +353,6 @@ class CustomizerSettingsAVTS(BaseModel):
|
|
|
351
353
|
enabled: bool = Field(default=False, description="Enable Aviator Search configuration")
|
|
352
354
|
username: str = Field(default="", description="Admin username for Aviator Search")
|
|
353
355
|
password: str = Field(default="", description="Admin password for Aviator Search")
|
|
354
|
-
otds_url: HttpUrl | None = Field(default=None, description="URL of the OTDS")
|
|
355
356
|
client_id: str = Field(default="", description="OTDS Client ID for Aviator Search")
|
|
356
357
|
client_secret: str = Field(default="", description="OTDS Client Secret for Aviator Search")
|
|
357
358
|
base_url: HttpUrl | None = Field(
|
|
@@ -399,13 +400,15 @@ class Settings(BaseSettings):
|
|
|
399
400
|
|
|
400
401
|
profiling: bool = Field(
|
|
401
402
|
default=False,
|
|
402
|
-
description="
|
|
403
|
+
description="Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using pyinstrument. Result is a html file showing the execution of payload broken down into functions and their duration. The files are located in the logdir. Profiling is disabled by default.",
|
|
403
404
|
)
|
|
404
405
|
cprofiling: bool = Field(
|
|
405
406
|
default=False,
|
|
406
|
-
description="
|
|
407
|
+
description="Profiling can only be enabled when using the CustomizerAPI. Switch to enable python profiling using cProfile. Result is a log file with the cProfile results, as well as a dump of the profiling session. The files are located in the logdir. The files are located in the logdir. Profilig is disabled by default.",
|
|
407
408
|
)
|
|
408
409
|
|
|
410
|
+
headless_browser: bool = Field(default=True, description="Headless Browser for the BrowserAutomation")
|
|
411
|
+
|
|
409
412
|
otds: CustomizerSettingsOTDS = CustomizerSettingsOTDS()
|
|
410
413
|
otcs: CustomizerSettingsOTCS = CustomizerSettingsOTCS()
|
|
411
414
|
otac: CustomizerSettingsOTAC = CustomizerSettingsOTAC()
|
pyxecm/helper/xml.py
CHANGED
|
@@ -31,6 +31,75 @@ class XML:
|
|
|
31
31
|
|
|
32
32
|
logger: logging.Logger = default_logger
|
|
33
33
|
|
|
34
|
+
@classmethod
|
|
35
|
+
def remove_xml_namespace(cls, tag: str) -> str:
|
|
36
|
+
"""Remove namespace from XML tag.
|
|
37
|
+
|
|
38
|
+
Args:
|
|
39
|
+
tag (str):
|
|
40
|
+
The XML tag with namespace.
|
|
41
|
+
|
|
42
|
+
Returns:
|
|
43
|
+
str:
|
|
44
|
+
The tag without namespace.
|
|
45
|
+
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
# In Python's ElementTree, the tag namespace
|
|
49
|
+
# is put into curly braces like "{namespace}element"
|
|
50
|
+
# that's why this method splits after the closing curly brace
|
|
51
|
+
# and takes the last item (-1):
|
|
52
|
+
|
|
53
|
+
return tag.split("}", 1)[-1]
|
|
54
|
+
|
|
55
|
+
# end method definition
|
|
56
|
+
|
|
57
|
+
@classmethod
|
|
58
|
+
def xml_to_dict(cls, xml_string: str) -> dict:
|
|
59
|
+
"""Parse XML string and return a dictionary without namespaces.
|
|
60
|
+
|
|
61
|
+
Args:
|
|
62
|
+
xml_string (str):
|
|
63
|
+
The XML string to process.
|
|
64
|
+
|
|
65
|
+
Returns:
|
|
66
|
+
dict:
|
|
67
|
+
The XML structure converted to a dictionary.
|
|
68
|
+
|
|
69
|
+
"""
|
|
70
|
+
|
|
71
|
+
def xml_element_to_dict(element: Element) -> dict:
|
|
72
|
+
"""Convert XML element to dictionary.
|
|
73
|
+
|
|
74
|
+
Args:
|
|
75
|
+
element (Element):
|
|
76
|
+
The XML element.
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
dict:
|
|
80
|
+
Dictionary representing the XML element
|
|
81
|
+
|
|
82
|
+
"""
|
|
83
|
+
tag = cls.remove_xml_namespace(element.tag)
|
|
84
|
+
children = list(element)
|
|
85
|
+
if children:
|
|
86
|
+
return {
|
|
87
|
+
tag: {
|
|
88
|
+
cls.remove_xml_namespace(child.tag): xml_element_to_dict(child)[
|
|
89
|
+
cls.remove_xml_namespace(child.tag)
|
|
90
|
+
]
|
|
91
|
+
for child in children
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return {tag: element.text.strip() if element.text else None}
|
|
96
|
+
|
|
97
|
+
root = etree.fromstring(xml_string)
|
|
98
|
+
|
|
99
|
+
return xml_element_to_dict(root)
|
|
100
|
+
|
|
101
|
+
# end method definition
|
|
102
|
+
|
|
34
103
|
@classmethod
|
|
35
104
|
def load_xml_file(
|
|
36
105
|
cls,
|
pyxecm/otac.py
CHANGED
|
@@ -387,7 +387,7 @@ class OTAC:
|
|
|
387
387
|
# Check if previous authentication was not successful.
|
|
388
388
|
# Then we do the normal username + password authentication:
|
|
389
389
|
self.logger.debug(
|
|
390
|
-
"Requesting OTAC ticket with
|
|
390
|
+
"Requesting OTAC ticket with username and password; calling -> %s",
|
|
391
391
|
request_url,
|
|
392
392
|
)
|
|
393
393
|
|