Skip to content

Commit f173f78

Browse files
committed
- Update .gitignore to ignore .pyc files
- Add 'axl_add_partition_css.py' sample - Update README.md
1 parent 9d5e314 commit f173f78

File tree

3 files changed

+257
-2
lines changed

3 files changed

+257
-2
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
AXLAPI.wsdl
22
AXLEnums.xsd
33
AXLSoap.xsd
4-
.vscode/
4+
.vscode/
5+
*.pyc

README.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,56 @@ The concepts and techniques shown can be extended to enable automated management
3535

3636
1. Copy the three WSDL files to the root directory of this project: `AXLAPI.wsdl`, `AXLEnums.xsd`, `AXLSoap.xsd`
3737

38+
## Hints
39+
40+
* You can get a 'dump' of the AXL WSDL to see how Zeep interprets it by copying the AXL WSDL files to the project root (see above) and running (Mac/Linux):
41+
42+
```
43+
python3 -mzeep AXLAPI.wsdl > wsdl.txt
44+
```
45+
46+
This can help with identifying the proper object structure to send to Zeep
47+
48+
* Elements which contain a list, such as:
49+
50+
```xml
51+
<members>
52+
<member>
53+
<subElement1/>
54+
<subElement2/>
55+
</member>
56+
<member>
57+
<subElement1/>
58+
<subElement2/>
59+
</member>
60+
</members>
61+
```
62+
63+
are represented a little differently than expected by Zeep. Note that `<members>` becomes an array, not `<members>`:
64+
65+
```json
66+
{
67+
members: {
68+
member: [
69+
{
70+
"subElement1": None,
71+
"subElement2": None
72+
},
73+
{
74+
"subElement1": None,
75+
"subElement2": None
76+
}
77+
]
78+
}
79+
}
80+
```
81+
3882
## Available samples
3983
40-
* `axlZeep.py` - Demonstrates adding a user, line, and phone (`<addLine>, <addPhone>, <addUser>, <updatePhone>, <getUser>)`
84+
* `axlZeep.py` - Demonstrates adding a user, line, and phone (`<addLine>`, `<addPhone>`, `<addUser>`, `<updatePhone>`, `<getUser>`)`
4185
4286
* `axl_updateDevicePool` - Demonstrates updating an existing Device Pool to modify the Local Route Group settings (`<updateDevicePool>`)
4387
88+
* `axl_add_partition_css.py` - Adds two partitions, then adds a CSS containing the two new partitions (`<addRoutePartition>`, `<addCss>`)
89+
4490
[![published](https://static.production.devnetcloud.com/codeexchange/assets/images/devnet-published.svg)](https://developer.cisco.com/codeexchange/github/repo/CiscoDevNet/axl-python-zeep-sample)

axl_add_partition_css.py

Lines changed: 208 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,208 @@
1+
"""AXL <addRoutePartition> and <addCss> sample script, using the zeep library
2+
3+
Install Python 2.7 or 3.7
4+
On Windows, choose the option to add to PATH environment variable
5+
6+
If this is a fresh installation, update pip (you may need to use `pip3` on Linux or Mac)
7+
8+
$ python -m pip install --upgrade pip
9+
10+
Script Dependencies:
11+
lxml
12+
requests
13+
zeep
14+
15+
Dependency Installation:
16+
17+
$ pip install zeep
18+
19+
This will install automatically all of zeep dependencies, including lxml, requests
20+
21+
Copyright (c) 2018 Cisco and/or its affiliates.
22+
Permission is hereby granted, free of charge, to any person obtaining a copy
23+
of this software and associated documentation files (the "Software"), to deal
24+
in the Software without restriction, including without limitation the rights
25+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
26+
copies of the Software, and to permit persons to whom the Software is
27+
furnished to do so, subject to the following conditions:
28+
The above copyright notice and this permission notice shall be included in all
29+
copies or substantial portions of the Software.
30+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
31+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
32+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
33+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
34+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
35+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
36+
SOFTWARE.
37+
"""
38+
39+
from lxml import etree
40+
from requests import Session
41+
from requests.auth import HTTPBasicAuth
42+
43+
from zeep import Client, Settings, Plugin
44+
from zeep.transports import Transport
45+
from zeep.exceptions import Fault
46+
47+
# Configure CUCM location and AXL credentials in creds.py
48+
import creds
49+
50+
# Change to true to enable output of request/response headers and XML
51+
DEBUG = False
52+
53+
# The WSDL is a local file in the working directory, see README
54+
WSDL_FILE = 'AXLAPI.wsdl'
55+
56+
# The below Partions and CSSs will be created
57+
58+
PARTITION1_NAME = 'testPartition1'
59+
PARTITION2_NAME = 'testPartition2'
60+
CSS_NAME = 'newCss'
61+
62+
# This class lets you view the incoming and outgoing http headers and XML
63+
64+
class MyLoggingPlugin(Plugin):
65+
66+
def egress(self, envelope, http_headers, operation, binding_options):
67+
print(
68+
'''Request
69+
-------
70+
Headers:
71+
{headers}
72+
73+
Body:
74+
{xml}
75+
76+
'''.format( headers = http_headers,
77+
xml = etree.tostring( envelope, pretty_print = True, encoding = 'unicode') )
78+
)
79+
80+
def ingress( self, envelope, http_headers, operation ):
81+
print('\n')
82+
print(
83+
'''Response
84+
-------
85+
Headers:
86+
{headers}
87+
88+
Body:
89+
{xml}
90+
91+
'''.format( headers = http_headers,
92+
xml = etree.tostring( envelope, pretty_print = True, encoding = 'unicode') )
93+
)
94+
95+
# This is where the meat of the application starts
96+
# The first step is to create a SOAP client session
97+
98+
session = Session()
99+
100+
# We avoid certificate verification by default
101+
102+
session.verify = False
103+
104+
# To enabled SSL cert checking (production)
105+
# place the CUCM Tomcat cert .pem file in the root of the project
106+
# and uncomment the two lines below
107+
108+
# CERT = 'changeme.pem'
109+
# session.verify = CERT
110+
111+
session.auth = HTTPBasicAuth(creds.AXL_USERNAME, creds.AXL_PASSWORD)
112+
113+
transport = Transport( session = session, timeout = 10 )
114+
115+
# strict=False is not always necessary, but it allows zeep to parse imperfect XML
116+
settings = Settings( strict = False, xml_huge_tree = True )
117+
118+
if DEBUG:
119+
client = Client( WSDL_FILE, settings = settings, transport = transport,
120+
plugins = [MyLoggingPlugin() ] )
121+
else:
122+
client = Client( WSDL_FILE, settings = settings, transport = transport )
123+
124+
service = client.create_service( "{http://www.cisco.com/AXLAPIService/}AXLAPIBinding",
125+
'https://{cucm}:8443/axl/'.format( cucm = creds.CUCM_ADDRESS ))
126+
127+
# Add testPartition1
128+
partition_data = {
129+
'name': PARTITION1_NAME
130+
}
131+
132+
try:
133+
resp = service.addRoutePartition( partition_data )
134+
except Fault as err:
135+
print('Zeep error: addRoutePartition (1 of 2): {err}'.format( err = err))
136+
else:
137+
print('addRoutePartition (1 of 2) response:')
138+
print(resp)
139+
140+
input( 'Press Enter to continue...')
141+
142+
# # Add testPartition2
143+
partition_data = {
144+
'name': PARTITION2_NAME
145+
}
146+
try:
147+
resp = service.addRoutePartition( partition_data )
148+
except Fault as err:
149+
print('Zeep error: addRoutePartition (2 of 2): {err}'.format( err = err))
150+
else:
151+
print('addRoutePartition (2 of 2) response:')
152+
print(resp)
153+
154+
input( 'Press Enter to continue...')
155+
156+
# Add testCss
157+
css_data = {
158+
'name': CSS_NAME,
159+
'members': { 'member': [ ] }
160+
}
161+
162+
css_data['members']['member'].append(
163+
{
164+
'routePartitionName': PARTITION1_NAME,
165+
'index': '1'
166+
} )
167+
168+
css_data['members']['member'].append(
169+
{
170+
'routePartitionName': PARTITION2_NAME,
171+
'index': '2'
172+
} )
173+
174+
try:
175+
resp = service.addCss( css_data )
176+
except Fault as err:
177+
print('Zeep error: addCss: {err}'.format( err = err))
178+
else:
179+
print('addCss response:')
180+
print(resp)
181+
182+
input( 'Press Enter to continue...')
183+
184+
# Cleanup the objects we just created
185+
186+
try:
187+
resp = service.removeCss( name = CSS_NAME )
188+
except Fault as err:
189+
print('Zeep error: removeCss: {err}'.format( err = err))
190+
else:
191+
print('removeCss response:')
192+
print(resp)
193+
194+
try:
195+
resp = service.removeRoutePartition( name = PARTITION1_NAME )
196+
except Fault as err:
197+
print('Zeep error: remoteRoutePartition (1 of 2): {err}'.format( err = err))
198+
else:
199+
print('removeRoutePartition (1 or 2) response:')
200+
print(resp)
201+
202+
try:
203+
resp = service.removeRoutePartition( name = PARTITION2_NAME )
204+
except Fault as err:
205+
print('Zeep error: remoteRoutePartition (2 of 2): {err}'.format( err = err))
206+
else:
207+
print('removeRoutePartition (2 or 2) response:')
208+
print(resp)

0 commit comments

Comments
 (0)