Skip to content

Commit 9d33f26

Browse files
authored
Merge pull request #2 from softlayer/master
Updating my fork
2 parents 03e7265 + 301a488 commit 9d33f26

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+1005
-387
lines changed

CHANGELOG.md

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
11
# Change Log
22

3+
4+
## [5.5.1] - 2018-08-31
5+
- Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.1...v5.5.2
6+
7+
+ #1018 Fixed hardware credentials.
8+
+ #1019 support for ticket priorities
9+
+ #1025 create dedicated host with gpu fixed.
10+
11+
12+
## [5.5.1] - 2018-08-06
13+
- Changes: https://github.com/softlayer/softlayer-python/compare/v5.5.0...v5.5.1
14+
15+
- #1006, added paginations to several slcli methods, making them work better with large result sets.
16+
- #995, Fixed an issue displaying VLANs.
17+
- #1011, Fixed an issue displaying some NAS passwords
18+
- #1014, Ability to delete users
19+
320
## [5.5.0] - 2018-07-09
4-
- Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.4...master
21+
- Changes: https://github.com/softlayer/softlayer-python/compare/v5.4.4...v5.5.0
522

623
- Added a warning when ordering legacy storage volumes
724
- Added documentation link to volume-order

CONTRIBUTING.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,18 @@ guidelines below.
1212
* Additional infomration can be found in our [contribution guide](http://softlayer-python.readthedocs.org/en/latest/dev/index.html)
1313

1414

15+
## Code style
16+
17+
Code is tested and style checked with tox, you can run the tox tests individually by doing `tox -e <TEST>`
18+
19+
* `autopep8 -r -v -i --max-line-length 119 SoftLayer/`
20+
* `autopep8 -r -v -i --max-line-length 119 tests/`
21+
* `tox -e analysis`
22+
* `tox -e py36`
23+
* `git commit --message="#<ISSUENUMBER> <whatever you did>`
24+
* `git push origin <issueBranch>`
25+
* create pull request
26+
27+
28+
29+

README.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,9 @@ SoftLayer API Python Client
1212
.. image:: https://coveralls.io/repos/github/softlayer/softlayer-python/badge.svg?branch=master
1313
:target: https://coveralls.io/github/softlayer/softlayer-python?branch=master
1414

15+
.. image:: https://build.snapcraft.io/badge/softlayer/softlayer-python.svg
16+
:target: https://build.snapcraft.io/user/softlayer/softlayer-python
17+
1518

1619
This library provides a simple Python client to interact with `SoftLayer's
1720
XML-RPC API <http://developer.softlayer.com/reference/softlayerapi>`_.

SoftLayer/API.py

Lines changed: 29 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -214,7 +214,9 @@ def call(self, service, method, *args, **kwargs):
214214
215215
"""
216216
if kwargs.pop('iter', False):
217-
return self.iter_call(service, method, *args, **kwargs)
217+
# Most of the codebase assumes a non-generator will be returned, so casting to list
218+
# keeps those sections working
219+
return list(self.iter_call(service, method, *args, **kwargs))
218220

219221
invalid_kwargs = set(kwargs.keys()) - VALID_CALL_ARGS
220222
if invalid_kwargs:
@@ -267,55 +269,49 @@ def iter_call(self, service, method, *args, **kwargs):
267269
268270
:param service: the name of the SoftLayer API service
269271
:param method: the method to call on the service
270-
:param integer chunk: result size for each API call (defaults to 100)
272+
:param integer limit: result size for each API call (defaults to 100)
271273
:param \\*args: same optional arguments that ``Service.call`` takes
272-
:param \\*\\*kwargs: same optional keyword arguments that
273-
``Service.call`` takes
274+
:param \\*\\*kwargs: same optional keyword arguments that ``Service.call`` takes
274275
275276
"""
276-
chunk = kwargs.pop('chunk', 100)
277-
limit = kwargs.pop('limit', None)
278-
offset = kwargs.pop('offset', 0)
279277

280-
if chunk <= 0:
281-
raise AttributeError("Chunk size should be greater than zero.")
278+
limit = kwargs.pop('limit', 100)
279+
offset = kwargs.pop('offset', 0)
282280

283-
if limit:
284-
chunk = min(chunk, limit)
281+
if limit <= 0:
282+
raise AttributeError("Limit size should be greater than zero.")
285283

286-
result_count = 0
284+
# Set to make unit tests, which call this function directly, play nice.
287285
kwargs['iter'] = False
288-
while True:
289-
if limit:
290-
# We've reached the end of the results
291-
if result_count >= limit:
292-
break
293-
294-
# Don't over-fetch past the given limit
295-
if chunk + result_count > limit:
296-
chunk = limit - result_count
297-
298-
results = self.call(service, method,
299-
offset=offset, limit=chunk, *args, **kwargs)
286+
result_count = 0
287+
keep_looping = True
300288

301-
# It looks like we ran out results
302-
if not results:
303-
break
289+
while keep_looping:
290+
# Get the next results
291+
results = self.call(service, method, offset=offset, limit=limit, *args, **kwargs)
304292

305293
# Apparently this method doesn't return a list.
306294
# Why are you even iterating over this?
307-
if not isinstance(results, list):
308-
yield results
309-
break
295+
if not isinstance(results, transports.SoftLayerListResult):
296+
if isinstance(results, list):
297+
# Close enough, this makes testing a lot easier
298+
results = transports.SoftLayerListResult(results, len(results))
299+
else:
300+
yield results
301+
return
310302

311303
for item in results:
312304
yield item
313305
result_count += 1
314306

315-
offset += chunk
307+
# Got less results than requested, we are at the end
308+
if len(results) < limit:
309+
keep_looping = False
310+
# Got all the needed items
311+
if result_count >= results.total_count:
312+
keep_looping = False
316313

317-
if len(results) < chunk:
318-
break
314+
offset += limit
319315

320316
def __repr__(self):
321317
return "Client(transport=%r, auth=%r)" % (self.transport, self.auth)

SoftLayer/CLI/hardware/credentials.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,9 @@ def cli(env, identifier):
2323
instance = manager.get_hardware(hardware_id)
2424

2525
table = formatting.Table(['username', 'password'])
26-
if 'passwords' not in instance['operatingSystem']:
27-
raise exceptions.SoftLayerError("No passwords found in operatingSystem")
28-
29-
for item in instance['operatingSystem']['passwords']:
30-
table.add_row([item.get('username', 'None'), item.get('password', 'None')])
26+
for item in instance['softwareComponents']:
27+
if 'passwords' not in item:
28+
raise exceptions.SoftLayerError("No passwords found in softwareComponents")
29+
for credentials in item['passwords']:
30+
table.add_row([credentials.get('username', 'None'), credentials.get('password', 'None')])
3131
env.fout(table)

SoftLayer/CLI/hardware/list.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,12 @@
5555
help='Columns to display. [options: %s]' % ', '.join(column.name for column in COLUMNS),
5656
default=','.join(DEFAULT_COLUMNS),
5757
show_default=True)
58+
@click.option('--limit', '-l',
59+
help='How many results to get in one api call, default is 100',
60+
default=100,
61+
show_default=True)
5862
@environment.pass_env
59-
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, columns):
63+
def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, columns, limit):
6064
"""List hardware servers."""
6165

6266
manager = SoftLayer.HardwareManager(env.client)
@@ -67,7 +71,8 @@ def cli(env, sortby, cpu, domain, datacenter, hostname, memory, network, tag, co
6771
datacenter=datacenter,
6872
nic_speed=network,
6973
tags=tag,
70-
mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask())
74+
mask="mask(SoftLayer_Hardware_Server)[%s]" % columns.mask(),
75+
limit=limit)
7176

7277
table = formatting.Table(columns.columns)
7378
table.sortby = sortby

SoftLayer/CLI/order/place.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ def cli(env, package_keyname, location, preset, verify, billing, complex_type,
4343
can then be converted to be made programmatically by calling
4444
SoftLayer.OrderingManager.place_order() with the same keynames.
4545
46-
Packages for ordering can be retrived from `slcli order package-list`
46+
Packages for ordering can be retrieved from `slcli order package-list`
4747
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
4848
have presets)
4949

SoftLayer/CLI/order/place_quote.py

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
"""Place quote"""
2+
# :license: MIT, see LICENSE for more details.
3+
4+
import json
5+
6+
import click
7+
8+
from SoftLayer.CLI import environment
9+
from SoftLayer.CLI import formatting
10+
from SoftLayer.managers import ordering
11+
12+
13+
@click.command()
14+
@click.argument('package_keyname')
15+
@click.argument('location')
16+
@click.option('--preset',
17+
help="The order preset (if required by the package)")
18+
@click.option('--name',
19+
help="A custom name to be assigned to the quote (optional)")
20+
@click.option('--send-email',
21+
is_flag=True,
22+
help="The quote will be sent to the email address associated.")
23+
@click.option('--complex-type', help=("The complex type of the order. This typically begins"
24+
" with 'SoftLayer_Container_Product_Order_'."))
25+
@click.option('--extras',
26+
help="JSON string denoting extra data that needs to be sent with the order")
27+
@click.argument('order_items', nargs=-1)
28+
@environment.pass_env
29+
def cli(env, package_keyname, location, preset, name, send_email, complex_type,
30+
extras, order_items):
31+
"""Place a quote.
32+
33+
This CLI command is used for placing a quote of the specified package in
34+
the given location (denoted by a datacenter's long name). Orders made via the CLI
35+
can then be converted to be made programmatically by calling
36+
SoftLayer.OrderingManager.place_quote() with the same keynames.
37+
38+
Packages for ordering can be retrieved from `slcli order package-list`
39+
Presets for ordering can be retrieved from `slcli order preset-list` (not all packages
40+
have presets)
41+
42+
Items can be retrieved from `slcli order item-list`. In order to find required
43+
items for the order, use `slcli order category-list`, and then provide the
44+
--category option for each category code in `slcli order item-list`.
45+
46+
\b
47+
Example:
48+
# Place quote a VSI with 4 CPU, 16 GB RAM, 100 GB SAN disk,
49+
# Ubuntu 16.04, and 1 Gbps public & private uplink in dal13
50+
slcli order place-quote --name "foobar" --send-email CLOUD_SERVER DALLAS13 \\
51+
GUEST_CORES_4 \\
52+
RAM_16_GB \\
53+
REBOOT_REMOTE_CONSOLE \\
54+
1_GBPS_PUBLIC_PRIVATE_NETWORK_UPLINKS \\
55+
BANDWIDTH_0_GB_2 \\
56+
1_IP_ADDRESS \\
57+
GUEST_DISK_100_GB_SAN \\
58+
OS_UBUNTU_16_04_LTS_XENIAL_XERUS_MINIMAL_64_BIT_FOR_VSI \\
59+
MONITORING_HOST_PING \\
60+
NOTIFICATION_EMAIL_AND_TICKET \\
61+
AUTOMATED_NOTIFICATION \\
62+
UNLIMITED_SSL_VPN_USERS_1_PPTP_VPN_USER_PER_ACCOUNT \\
63+
NESSUS_VULNERABILITY_ASSESSMENT_REPORTING \\
64+
--extras '{"virtualGuests": [{"hostname": "test", "domain": "softlayer.com"}]}' \\
65+
--complex-type SoftLayer_Container_Product_Order_Virtual_Guest
66+
67+
"""
68+
manager = ordering.OrderingManager(env.client)
69+
70+
if extras:
71+
extras = json.loads(extras)
72+
73+
args = (package_keyname, location, order_items)
74+
kwargs = {'preset_keyname': preset,
75+
'extras': extras,
76+
'quantity': 1,
77+
'quote_name': name,
78+
'send_email': send_email,
79+
'complex_type': complex_type}
80+
81+
order = manager.place_quote(*args, **kwargs)
82+
83+
table = formatting.KeyValueTable(['name', 'value'])
84+
table.align['name'] = 'r'
85+
table.align['value'] = 'l'
86+
table.add_row(['id', order['quote']['id']])
87+
table.add_row(['name', order['quote']['name']])
88+
table.add_row(['created', order['orderDate']])
89+
table.add_row(['expires', order['quote']['expirationDate']])
90+
table.add_row(['status', order['quote']['status']])
91+
env.fout(table)

SoftLayer/CLI/routes.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@
210210
('order:place', 'SoftLayer.CLI.order.place:cli'),
211211
('order:preset-list', 'SoftLayer.CLI.order.preset_list:cli'),
212212
('order:package-locations', 'SoftLayer.CLI.order.package_locations:cli'),
213+
('order:place-quote', 'SoftLayer.CLI.order.place_quote:cli'),
213214

214215
('rwhois', 'SoftLayer.CLI.rwhois'),
215216
('rwhois:edit', 'SoftLayer.CLI.rwhois.edit:cli'),

SoftLayer/CLI/securitygroup/list.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,16 +16,20 @@
1616
@click.option('--sortby',
1717
help='Column to sort by',
1818
type=click.Choice(COLUMNS))
19+
@click.option('--limit', '-l',
20+
help='How many results to get in one api call, default is 100',
21+
default=100,
22+
show_default=True)
1923
@environment.pass_env
20-
def cli(env, sortby):
24+
def cli(env, sortby, limit):
2125
"""List security groups."""
2226

2327
mgr = SoftLayer.NetworkManager(env.client)
2428

2529
table = formatting.Table(COLUMNS)
2630
table.sortby = sortby
2731

28-
sgs = mgr.list_securitygroups()
32+
sgs = mgr.list_securitygroups(limit=limit)
2933
for secgroup in sgs:
3034
table.add_row([
3135
secgroup['id'],

0 commit comments

Comments
 (0)