python4cpm 1.0.21__tar.gz → 1.0.22__tar.gz
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.
- {python4cpm-1.0.21/src/python4cpm.egg-info → python4cpm-1.0.22}/PKG-INFO +196 -48
- {python4cpm-1.0.21 → python4cpm-1.0.22}/README.md +195 -47
- {python4cpm-1.0.21 → python4cpm-1.0.22}/pyproject.toml +1 -1
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/__init__.py +2 -7
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/logger.py +1 -1
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/nethelper.py +9 -4
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/python4cpm.py +3 -8
- python4cpm-1.0.22/src/python4cpm/python4cpmhandler.py +41 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22/src/python4cpm.egg-info}/PKG-INFO +196 -48
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm.egg-info/SOURCES.txt +1 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/LICENSE +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/setup.cfg +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/args.py +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/crypto.py +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm/secrets.py +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm.egg-info/dependency_links.txt +0 -0
- {python4cpm-1.0.21 → python4cpm-1.0.22}/src/python4cpm.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: python4cpm
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.22
|
|
4
4
|
Summary: Python for CPM
|
|
5
5
|
Author-email: Gonzalo Atienza Rela <gonatienza@gmail.com>
|
|
6
6
|
License: MIT License
|
|
@@ -32,7 +32,7 @@ Dynamic: license-file
|
|
|
32
32
|
|
|
33
33
|
# Python4CPM
|
|
34
34
|
|
|
35
|
-
A simple way of using python scripts with CyberArk CPM rotations. This module
|
|
35
|
+
A simple way of using python scripts with CyberArk CPM rotations. This module leverages the [Credential Management .NET SDK](https://docs.cyberark.com/privilege-cloud-standard/latest/en/content/pasimp/plug-in-netinvoker.htm) from CyberArk to securely offload a password rotation logic into a python script.
|
|
36
36
|
|
|
37
37
|
This platform allows you to duplicate it multiple times, simply changing its settings from Privilege Cloud/PVWA to point to different python scripts leveraging the module `python4cpm`.
|
|
38
38
|
|
|
@@ -78,7 +78,127 @@ This platform allows you to duplicate it multiple times, simply changing its set
|
|
|
78
78
|
|
|
79
79
|
## Python Script
|
|
80
80
|
|
|
81
|
-
###
|
|
81
|
+
### Using the handler (recommended):
|
|
82
|
+
|
|
83
|
+
```python
|
|
84
|
+
from python4cpm import Python4CPMHandler
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
class MyApp(Python4CPMHandler): # create a subclass for the Handler
|
|
88
|
+
"""
|
|
89
|
+
These are the usable properties and methods from Python4CPMHandler:
|
|
90
|
+
|
|
91
|
+
self.args.action # action requested from CPM/SRS
|
|
92
|
+
self.args.address # address from the account address field
|
|
93
|
+
self.args.username # username from the account username field
|
|
94
|
+
self.args.reconcile_username # reconcile username from the linked reconcile account
|
|
95
|
+
self.args.logon_username # logon username from the linked logon account
|
|
96
|
+
self.args.logging # used to carry the platform logging settings for python
|
|
97
|
+
self.secrets.password.get() # get str from password received from the vault
|
|
98
|
+
self.secrets.new_password.get() # get str from new password in case of a rotation
|
|
99
|
+
self.secrets.logon_password.get() # get str from linked logon account password
|
|
100
|
+
self.secrets.reconcile_password.get() # get str from linked reconcile account password
|
|
101
|
+
|
|
102
|
+
Logging methods -> Will only log if PythonLogging (platform parameters) is set to yes (default is yes)
|
|
103
|
+
|
|
104
|
+
self.log_error("this is an error message") # logs error into Logs/ThirdParty/MyApp.log
|
|
105
|
+
self.log_warning("this is a warning message") # logs warning into Logs/ThirdParty/MyApp.log
|
|
106
|
+
self.log_info("this is an info message") # logs info into Logs/ThirdParty/MyApp.log
|
|
107
|
+
|
|
108
|
+
Logging level -> Will only log debug messages if PythonLoggingLevel (platform parameters) is set to debug (default is info)
|
|
109
|
+
|
|
110
|
+
self.log_debug("this is an debug message") # logs info into Logs/ThirdParty/MyApp.log if logging level is set to debug
|
|
111
|
+
|
|
112
|
+
=============================
|
|
113
|
+
REQUIRED TERMINATION SIGNALS
|
|
114
|
+
=============================
|
|
115
|
+
Terminate signals -> MUST use one of the following three signals to terminate the script:
|
|
116
|
+
|
|
117
|
+
self.close_success() # terminate with success state
|
|
118
|
+
self.close_fail() # terminate with recoverable failed state
|
|
119
|
+
self.close_fail(unrecoverable=True) # terminate with unrecoverable failed state
|
|
120
|
+
|
|
121
|
+
When calling a signal sys.exit is invoked and the script is terminated. If no signal is called, and the script finishes without any exception, it will behave like p4cpm.close_fail(unrecoverable=True) and log an error message.
|
|
122
|
+
=============================
|
|
123
|
+
=============================
|
|
124
|
+
"""
|
|
125
|
+
|
|
126
|
+
# =============================
|
|
127
|
+
# REQUIRED METHODS (MUST DEFINE)
|
|
128
|
+
# =============================
|
|
129
|
+
# verify(), logon(), change(), prereconcile(), reconcile()
|
|
130
|
+
|
|
131
|
+
def verify(self):
|
|
132
|
+
self._verify()
|
|
133
|
+
self.log_info("verification successful")
|
|
134
|
+
self.close_success()
|
|
135
|
+
|
|
136
|
+
def logon(self):
|
|
137
|
+
self.close_success() # terminate with success state if nothing needs to be done with a given action.
|
|
138
|
+
|
|
139
|
+
def change(self):
|
|
140
|
+
self._change()
|
|
141
|
+
self.log_error("something went wrong")
|
|
142
|
+
self.close_fail()
|
|
143
|
+
|
|
144
|
+
def prereconcile(self):
|
|
145
|
+
self._verify(from_reconcile=True)
|
|
146
|
+
self.close_success()
|
|
147
|
+
|
|
148
|
+
def reconcile(self):
|
|
149
|
+
self._change(from_reconcile=True)
|
|
150
|
+
self.close_success()
|
|
151
|
+
|
|
152
|
+
def _verify(self, from_reconcile=False):
|
|
153
|
+
if from_reconcile is False:
|
|
154
|
+
pass
|
|
155
|
+
# TODO: use self.args.address, self.args.username, self.secrets.password.get()
|
|
156
|
+
# for your logic in a verification
|
|
157
|
+
else:
|
|
158
|
+
pass
|
|
159
|
+
# TODO: use self.args.address, self.args.reconcile_username, self.secrets.reconcile_password.get()
|
|
160
|
+
# for your logic in a verification
|
|
161
|
+
result = True
|
|
162
|
+
if result is True:
|
|
163
|
+
self.log_info("verification successful") # logs info message into Logs/ThirdParty/MyApp.log
|
|
164
|
+
else:
|
|
165
|
+
self.log_error("something went wrong") # logs error message Logs/ThirdParty/MyApp.log
|
|
166
|
+
self.close_fail()
|
|
167
|
+
|
|
168
|
+
def _change(self, from_reconcile=False):
|
|
169
|
+
if from_reconcile is False:
|
|
170
|
+
pass
|
|
171
|
+
# TODO: use self.args.address, self.args.username, self.secrets.password.get()
|
|
172
|
+
# and self.secrets.new_password.get() for your logic in a rotation
|
|
173
|
+
else:
|
|
174
|
+
pass
|
|
175
|
+
# TODO: use self.args.address, self.args.username, self.args.reconcile_username,
|
|
176
|
+
# self.secrets.reconcile_password.get() and self.secrets.new_password.get() for your logic in a reconciliation
|
|
177
|
+
result = True
|
|
178
|
+
if result is True:
|
|
179
|
+
self.log_info("rotation successful") # logs info message into Logs/ThirdParty/MyApp.log
|
|
180
|
+
else:
|
|
181
|
+
self.log_error("something went wrong") # logs error message Logs/ThirdParty/MyApp.log
|
|
182
|
+
self.close_fail()
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
if __name__ == "__main__":
|
|
186
|
+
MyApp().run() # initializes the class and calls the action that was requested from CPM/SRS.
|
|
187
|
+
```
|
|
188
|
+
(*) More realistic examples can be found [here](https://github.com/gonatienza/python4cpm/blob/main/examples/python4cpmhandler).
|
|
189
|
+
|
|
190
|
+
When doing `verify`, `change` or `reconcile` from Privilege Cloud/PVWA:
|
|
191
|
+
1. Verify -> the sciprt will be executed once with the `MyApp.verify()` method.
|
|
192
|
+
2. Change -> the sciprt will be executed twice, once with the action `MyApp.logon()` method and once as `MyApp.change()` method.
|
|
193
|
+
- If all actions are not terminated with `self.close_success()` and the scripts terminates without any exception, CPM/SRS will see this as a `self.close_fail(unrecoverable=True)`.
|
|
194
|
+
3. Reconcile -> the sciprt will be executed twice, once with the action `MyApp.prereconcile()` method and once as `MyApp.reconcile()` method.
|
|
195
|
+
- If all actions are not terminated with `self.close_success()` and the scripts terminates without any exception, CPM/SRS will see this as a `self.close_fail(unrecoverable=True)`.
|
|
196
|
+
4. When calling `MyApp.logon()` or `MyApp.prereconcile()`: `self.secrets.new_password.get()` will always return an empty string.
|
|
197
|
+
5. If a logon account is not linked, `self.args.logon_username` and `self.secrets.logon_password.get()` will return an empty string.
|
|
198
|
+
6. If a reconcile account is not linked, `self.args.reconcile_username` and `self.secrets.reconcile_password.get()` will return an empty string.
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
### Using Python4CPM properties and methods directly (for low level controls):
|
|
82
202
|
|
|
83
203
|
```python
|
|
84
204
|
from python4cpm import Python4CPM
|
|
@@ -87,7 +207,7 @@ from python4cpm import Python4CPM
|
|
|
87
207
|
p4cpm = Python4CPM("MyApp") # this instantiates the object and grabs all arguments and secrets shared by the .NET SDK
|
|
88
208
|
|
|
89
209
|
# These are the usable properties and related methods from the object:
|
|
90
|
-
p4cpm.args.action # action requested from CPM
|
|
210
|
+
p4cpm.args.action # action requested from CPM/SRS
|
|
91
211
|
p4cpm.args.address # address from the account address field
|
|
92
212
|
p4cpm.args.username # username from the account username field
|
|
93
213
|
p4cpm.args.reconcile_username # reconcile username from the linked reconcile account
|
|
@@ -98,36 +218,35 @@ p4cpm.secrets.new_password.get() # get str from new password in case of a rotati
|
|
|
98
218
|
p4cpm.secrets.logon_password.get() # get str from linked logon account password
|
|
99
219
|
p4cpm.secrets.reconcile_password.get() # get str from linked reconcile account password
|
|
100
220
|
|
|
101
|
-
# Logging methods -> Will only log if
|
|
102
|
-
p4cpm.log_error("this is an error message") # logs error into Logs/ThirdParty/
|
|
103
|
-
p4cpm.log_warning("this is a warning message") # logs warning into Logs/ThirdParty/
|
|
104
|
-
p4cpm.log_info("this is an info message") # logs info into Logs/ThirdParty/
|
|
105
|
-
# Logging level -> Will only log debug messages if
|
|
106
|
-
p4cpm.log_debug("this is an debug message") # logs info into Logs/ThirdParty/
|
|
221
|
+
# Logging methods -> Will only log if PythonLogging (platform parameters) is set to yes (default is yes)
|
|
222
|
+
p4cpm.log_error("this is an error message") # logs error into Logs/ThirdParty/MyApp.log
|
|
223
|
+
p4cpm.log_warning("this is a warning message") # logs warning into Logs/ThirdParty/MyApp.log
|
|
224
|
+
p4cpm.log_info("this is an info message") # logs info into Logs/ThirdParty/MyApp.log
|
|
225
|
+
# Logging level -> Will only log debug messages if PythonLoggingLevel (platform parameters) is set to debug (default is info)
|
|
226
|
+
p4cpm.log_debug("this is an debug message") # logs info into Logs/ThirdParty/MyApp.log if logging level is set to debug
|
|
107
227
|
|
|
108
228
|
# Terminate signals -> MUST use one of the following three signals to terminate the script:
|
|
109
229
|
## p4cpm.close_success() # terminate with success state
|
|
110
230
|
## p4cpm.close_fail() # terminate with recoverable failed state
|
|
111
231
|
## p4cpm.close_fail(unrecoverable=True) # terminate with unrecoverable failed state
|
|
112
|
-
# When calling a signal sys.exit is invoked and the script is terminated.
|
|
113
|
-
# If no signal is called, and the script finishes without any exception, it will behave like p4cpm.close_fail(unrecoverable=True) and log an error message.
|
|
232
|
+
# When calling a signal sys.exit is invoked and the script is terminated. If no signal is called, and the script finishes without any exception, it will behave like p4cpm.close_fail(unrecoverable=True) and log an error message.
|
|
114
233
|
|
|
115
234
|
|
|
116
235
|
# Verification example -> verify the username and password are valid
|
|
117
236
|
def verify(from_reconcile=False):
|
|
118
237
|
if from_reconcile is False:
|
|
119
238
|
pass
|
|
120
|
-
#
|
|
239
|
+
# TODO: use p4cpm.args.address, p4cpm.args.username, p4cpm.secrets.password.get()
|
|
121
240
|
# for your logic in a verification
|
|
122
241
|
else:
|
|
123
242
|
pass
|
|
124
|
-
#
|
|
243
|
+
# TODO: use p4cpm.args.address, p4cpm.args.reconcile_username, p4cpm.secrets.reconcile_password.get()
|
|
125
244
|
# for your logic in a verification
|
|
126
245
|
result = True
|
|
127
246
|
if result is True:
|
|
128
|
-
p4cpm.log_info("verification successful")
|
|
247
|
+
p4cpm.log_info("verification successful")
|
|
129
248
|
else:
|
|
130
|
-
p4cpm.log_error("something went wrong")
|
|
249
|
+
p4cpm.log_error("something went wrong")
|
|
131
250
|
raise Exception("verify failed") # raise to trigger failed termination signal
|
|
132
251
|
|
|
133
252
|
|
|
@@ -135,17 +254,17 @@ def verify(from_reconcile=False):
|
|
|
135
254
|
def change(from_reconcile=False):
|
|
136
255
|
if from_reconcile is False:
|
|
137
256
|
pass
|
|
138
|
-
#
|
|
257
|
+
# TODO: use p4cpm.args.address, p4cpm.args.username, p4cpm.secrets.password.get()
|
|
139
258
|
# and p4cpm.secrets.new_password.get() for your logic in a rotation
|
|
140
259
|
else:
|
|
141
260
|
pass
|
|
142
|
-
#
|
|
261
|
+
# TODO: use p4cpm.args.address, p4cpm.args.username, p4cpm.args.reconcile_username,
|
|
143
262
|
# p4cpm.secrets.reconcile_password.get() and p4cpm.secrets.new_password.get() for your logic in a reconciliation
|
|
144
263
|
result = True
|
|
145
264
|
if result is True:
|
|
146
|
-
p4cpm.log_info("rotation successful")
|
|
265
|
+
p4cpm.log_info("rotation successful")
|
|
147
266
|
else:
|
|
148
|
-
p4cpm.log_error("something went wrong")
|
|
267
|
+
p4cpm.log_error("something went wrong")
|
|
149
268
|
raise Exception("change failed") # raise to trigger failed termination signal
|
|
150
269
|
|
|
151
270
|
|
|
@@ -153,48 +272,44 @@ if __name__ == "__main__":
|
|
|
153
272
|
try:
|
|
154
273
|
if p4cpm.args.action == Python4CPM.ACTION_VERIFY: # class attribute ACTION_VERIFY holds the verify action value
|
|
155
274
|
verify()
|
|
156
|
-
p4cpm.close_success()
|
|
275
|
+
p4cpm.close_success()
|
|
157
276
|
elif p4cpm.args.action == Python4CPM.ACTION_LOGON: # class attribute ACTION_LOGON holds the logon action value
|
|
158
|
-
|
|
159
|
-
p4cpm.close_success() # terminate with success state
|
|
277
|
+
p4cpm.close_success() # terminate with success state if nothing needs to be done with a given action.
|
|
160
278
|
elif p4cpm.args.action == Python4CPM.ACTION_CHANGE: # class attribute ACTION_CHANGE holds the password change action value
|
|
161
279
|
change()
|
|
162
|
-
p4cpm.close_success()
|
|
280
|
+
p4cpm.close_success()
|
|
163
281
|
elif p4cpm.args.action == Python4CPM.ACTION_PRERECONCILE: # class attribute ACTION_PRERECONCILE holds the pre-reconcile action value
|
|
164
282
|
verify(from_reconcile=True)
|
|
165
|
-
p4cpm.close_success()
|
|
283
|
+
p4cpm.close_success()
|
|
166
284
|
# Alternatively ->
|
|
167
285
|
## p4cpm.log_error("reconciliation is not supported") # let the logs know that reconciliation is not supported
|
|
168
|
-
## p4cpm.close_fail() # let CPM know to check the logs
|
|
286
|
+
## p4cpm.close_fail() # let CPM/SRS know to check the logs
|
|
169
287
|
elif p4cpm.args.action == Python4CPM.ACTION_RECONCILE: # class attribute ACTION_RECONCILE holds the reconcile action value
|
|
170
288
|
change(from_reconcile=True)
|
|
171
|
-
p4cpm.close_success()
|
|
289
|
+
p4cpm.close_success()
|
|
172
290
|
# Alternatively ->
|
|
173
291
|
## p4cpm.log_error("reconciliation is not supported") # let the logs know that reconciliation is not supported
|
|
174
|
-
## p4cpm.close_fail() # let CPM know to check the logs
|
|
175
|
-
else:
|
|
176
|
-
p4cpm.log_error(f"invalid action: '{p4cpm.args.action}'") # logs into Logs/ThirdParty/Python4CPM/MyApp.log
|
|
177
|
-
p4cpm.close_fail(unrecoverable=True) # terminate with unrecoverable failed state
|
|
292
|
+
## p4cpm.close_fail() # let CPM/SRS know to check the logs
|
|
178
293
|
except Exception as e:
|
|
179
294
|
p4cpm.log_error(f"{type(e).__name__}: {e}")
|
|
180
|
-
p4cpm.close_fail()
|
|
295
|
+
raise e # CPM/SRS will see any Exception as a p4cpm.close_fail(unrecoverable=True)
|
|
181
296
|
```
|
|
182
|
-
(*) More realistic examples can be found [here](https://github.com/gonatienza/python4cpm/blob/main/examples).
|
|
297
|
+
(*) More realistic examples can be found [here](https://github.com/gonatienza/python4cpm/blob/main/examples/python4cpm).
|
|
183
298
|
|
|
184
299
|
When doing `verify`, `change` or `reconcile` from Privilege Cloud/PVWA:
|
|
185
300
|
1. Verify -> the sciprt will be executed once with the `p4cpm.args.action` as `Python4CPM.ACTION_VERIFY`.
|
|
186
301
|
2. Change -> the sciprt will be executed twice, once with the action `p4cpm.args.action` as `Python4CPM.ACTION_LOGON` and once as `Python4CPM.ACTION_CHANGE`.
|
|
187
|
-
- If all actions are not terminated with `p4cpm.close_success()` and the scripts terminates without any exception,
|
|
302
|
+
- If all actions are not terminated with `p4cpm.close_success()` and the scripts terminates without any exception, CPM/SRS will see this as a `p4cpm.close_fail(unrecoverable=True)`.
|
|
188
303
|
3. Reconcile -> the sciprt will be executed twice, once with the `p4cpm.args.action` as `Python4CPM.ACTION_PRERECONCILE` and once as `Python4CPM.ACTION_RECONCILE`.
|
|
189
|
-
- If all actions are not terminated with `p4cpm.close_success()` the
|
|
304
|
+
- If all actions are not terminated with `p4cpm.close_success()` and the scripts terminates without any exception, CPM/SRS will see this as a `p4cpm.close_fail(unrecoverable=True)`.
|
|
190
305
|
4. When `p4cpm.args.action` comes as `Python4CPM.ACTION_VERIFY`, `Python4CPM.ACTION_LOGON` or `Python4CPM.ACTION_PRERECONCILE`: `p4cpm.secrets.new_password.get()` will always return an empty string.
|
|
191
306
|
5. If a logon account is not linked, `p4cpm.args.logon_username` and `p4cpm.secrets.logon_password.get()` will return an empty string.
|
|
192
307
|
6. If a reconcile account is not linked, `p4cpm.args.reconcile_username` and `p4cpm.secrets.reconcile_password.get()` will return an empty string.
|
|
193
308
|
|
|
194
309
|
|
|
195
|
-
### Installing
|
|
310
|
+
### Installing dependencies in python venv
|
|
196
311
|
|
|
197
|
-
As with any python venv, you can install
|
|
312
|
+
As with any python venv, you can install dependencies in your venv.
|
|
198
313
|
1. If your CPM can connect to the internet:
|
|
199
314
|
- You can use regular pip install commands (e.g., `c:\venv\Scripts\pip.exe install requests`).
|
|
200
315
|
2. If your CPM cannot connect to the internet:
|
|
@@ -203,7 +318,7 @@ As with any python venv, you can install dependancies in your venv.
|
|
|
203
318
|
|
|
204
319
|
## Dev Helper:
|
|
205
320
|
|
|
206
|
-
For dev purposes, `NETHelper` is a companion helper that simplifies the instantiation of the `Python4CPM`
|
|
321
|
+
For dev purposes, `NETHelper` is a companion helper that simplifies the instantiation of the `Python4CPM` or `Python4CPMHandler` objects by simulating how the plugin passes arguments and secrets to the modules.
|
|
207
322
|
Install this module (in a dev workstation) with:
|
|
208
323
|
|
|
209
324
|
```bash
|
|
@@ -215,7 +330,7 @@ pip install python4cpm
|
|
|
215
330
|
### Example:
|
|
216
331
|
|
|
217
332
|
```python
|
|
218
|
-
from python4cpm import NETHelper, Python4CPM
|
|
333
|
+
from python4cpm import NETHelper, Python4CPM, Python4CPMHandler
|
|
219
334
|
from getpass import getpass
|
|
220
335
|
|
|
221
336
|
# Get secrets for your password, logon account password, reconcile account password and new password
|
|
@@ -224,8 +339,12 @@ password = getpass("password: ") # password from account
|
|
|
224
339
|
logon_password = getpass("logon_password: ") # password from linked logon account
|
|
225
340
|
reconcile_password = getpass("reconcile_password: ") # password from linked reconcile account
|
|
226
341
|
new_password = getpass("new_password: ") # new password for the rotation
|
|
342
|
+
```
|
|
227
343
|
|
|
228
|
-
|
|
344
|
+
#### Set your arguments and secrets:
|
|
345
|
+
|
|
346
|
+
```python
|
|
347
|
+
NETHelper.set(
|
|
229
348
|
action=Python4CPM.ACTION_LOGON, # use actions from Python4CPM.ACTION_*
|
|
230
349
|
address="myapp.corp.local", # populate with the address from your account properties
|
|
231
350
|
username="jdoe", # populate with the username from your account properties
|
|
@@ -238,19 +357,48 @@ p4cpm = NETHelper.run(
|
|
|
238
357
|
reconcile_password=reconcile_password,
|
|
239
358
|
new_password=new_password
|
|
240
359
|
)
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
#### Using the handler (recommended):
|
|
363
|
+
|
|
364
|
+
```python
|
|
365
|
+
class MyApp(Python4CPMHandler):
|
|
366
|
+
def verify(self):
|
|
367
|
+
# TODO: Add your logic here
|
|
368
|
+
self.close_success()
|
|
369
|
+
|
|
370
|
+
def logon(self):
|
|
371
|
+
# TODO: Add your logic here
|
|
372
|
+
self.close_success()
|
|
373
|
+
|
|
374
|
+
def change(self):
|
|
375
|
+
# TODO: Add your logic here
|
|
376
|
+
self.close_success()
|
|
377
|
+
|
|
378
|
+
def prereconcile(self):
|
|
379
|
+
# TODO: Add your logic here
|
|
380
|
+
self.close_success()
|
|
241
381
|
|
|
242
|
-
|
|
382
|
+
def reconcile(self):
|
|
383
|
+
# TODO: Add your logic here
|
|
384
|
+
self.close_success()
|
|
385
|
+
|
|
386
|
+
MyApp().run()
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
#### Using Python4CPM properties and methods directly:
|
|
390
|
+
|
|
391
|
+
```python
|
|
392
|
+
p4cpm = NETHelper.get()
|
|
393
|
+
|
|
394
|
+
# TODO: use the p4cpm object during dev to build your script logic
|
|
243
395
|
assert password == p4cpm.secrets.password.get()
|
|
244
396
|
p4cpm.log_info("success!")
|
|
245
397
|
p4cpm.close_success()
|
|
246
|
-
|
|
247
|
-
# Remember for your final script:
|
|
248
|
-
## changing the definition of p4cpm from NETHelper.run() to Python4CPM("MyApp")
|
|
249
|
-
## remove any secrets prompting
|
|
250
|
-
## remove the NETHelper import
|
|
251
398
|
```
|
|
252
399
|
|
|
253
|
-
Remember for your final script:
|
|
254
|
-
|
|
400
|
+
#### Remember for your final script:
|
|
401
|
+
|
|
402
|
+
- Change the definition of `p4cpm` from `p4cpm = NETHelper.get()` to `p4cpm = Python4CPM("MyApp")` if you are using the properties and methods directly.
|
|
255
403
|
- Remove any secrets prompting or interactive interruptions.
|
|
256
404
|
- Remove the import of `NETHelper`.
|