diff --git a/doc/source/contributors/clouds.yaml b/doc/source/contributors/clouds.yaml index 86897d75a..04cd4aaf3 100644 --- a/doc/source/contributors/clouds.yaml +++ b/doc/source/contributors/clouds.yaml @@ -6,13 +6,10 @@ clouds: username: demo password: secrete project_name: demo - hp: - cloud: hp - auth: - username: joe - password: joes-password - project_name: joe-tenant1 - region_name: region-b.geo-1 + example: + image_name: fedora-20.x86_64 + flavor_name: m1.small + network_name: private rackspace: cloud: rackspace auth: diff --git a/doc/source/users/guides/compute.rst b/doc/source/users/guides/compute.rst index d5c320a6c..697aedb4c 100644 --- a/doc/source/users/guides/compute.rst +++ b/doc/source/users/guides/compute.rst @@ -56,8 +56,12 @@ Create Server ------------- At minimum, a server requires a name, an image, a flavor, and a network on -creation. Once you've discovered these attributes by listing them as above, -you can create a server. +creation. You can discover the names and IDs of these attributes by listing +them as above and then using the find methods to get the appropriate +resources. + +Ideally you'll also create a server using a public/private keypair so you can +login to that server with the private key. Servers take time to boot so we call ``wait_for_server`` to wait for it to become active. diff --git a/doc/source/users/guides/connect.rst b/doc/source/users/guides/connect.rst index 56de49986..706f5bd8c 100644 --- a/doc/source/users/guides/connect.rst +++ b/doc/source/users/guides/connect.rst @@ -18,8 +18,7 @@ To create a connection you need a :class:`~openstack.profile.Profile` and a :class:`~openstack.connection.Connection`. .. literalinclude:: ../examples/connect.py - :language: python - :lines: 32-44 + :pyobject: create_connection The :class:`~openstack.profile.Profile` sets your preferences for each service. You will pass it the region of the OpenStack cloud that this @@ -27,9 +26,9 @@ connection will use. The :class:`~openstack.connection.Connection` is a context for a connection to an OpenStack cloud. You will primarily use it to set the -:class:`~openstack.profile.Profile` and authentication information with the -``auth_args`` parameter. You can also set the ``user_agent`` to something that -describes your application (e.g. ``my-web-app/1.3.4``). +:class:`~openstack.profile.Profile` and authentication information. You can +also set the ``user_agent`` to something that describes your application +(e.g. ``my-web-app/1.3.4``). Full example at `connect.py `_ diff --git a/doc/source/users/guides/connect_from_config.rst b/doc/source/users/guides/connect_from_config.rst index d7efb314f..c06ffedb4 100644 --- a/doc/source/users/guides/connect_from_config.rst +++ b/doc/source/users/guides/connect_from_config.rst @@ -19,13 +19,12 @@ Default Location **************** To create a connection from a file you need a YAML file to contain the -configuration and the :py:func:`~openstack.connection.from_config` -function. +configuration. .. literalinclude:: ../../contributors/clouds.yaml :language: yaml -To look for a configuration file called ``clouds.yaml`` in the default +To use a configuration file called ``clouds.yaml`` in one of the default locations: * Current Directory @@ -36,15 +35,17 @@ call :py:func:`~openstack.connection.from_config` with an object that has the name of the cloud configuration to use. .. literalinclude:: ../examples/connect.py - :language: python - :lines: 23-30 + :pyobject: Opts + +.. literalinclude:: ../examples/connect.py + :pyobject: create_connection_from_config .. note:: To enable logging, set ``debug=True`` in the ``Opts`` object. User Defined Location ********************* -To look for a configuration file in a user defined location set the +To use a configuration file in a user defined location set the environment variable ``OS_CLIENT_CONFIG_FILE`` to the absolute path of a file.:: @@ -54,8 +55,10 @@ and call :py:func:`~openstack.connection.from_config` with an object that has the name of the cloud configuration to use. .. literalinclude:: ../examples/connect.py - :language: python - :lines: 23-30 + :pyobject: Opts + +.. literalinclude:: ../examples/connect.py + :pyobject: create_connection_from_config .. note:: To enable logging, set ``debug=True`` in the ``Opts`` object. diff --git a/examples/compute/create.py b/examples/compute/create.py index 6460a235b..5fced0b06 100644 --- a/examples/compute/create.py +++ b/examples/compute/create.py @@ -10,6 +10,14 @@ # License for the specific language governing permissions and limitations # under the License. +import os + +from examples.connect import FLAVOR_NAME +from examples.connect import IMAGE_NAME +from examples.connect import KEYPAIR_NAME +from examples.connect import NETWORK_NAME +from examples.connect import PRIVATE_KEYPAIR_FILE + """ Create resources with the Compute service. @@ -17,12 +25,27 @@ For a full guide see TODO(etoews):link to docs on developer.openstack.org """ -def create_server(conn, name, image, flavor, network): +def create_server(conn): print("Create Server:") - server = conn.compute.create_server(name=name, image=image, - flavor=flavor, - networks=[{"uuid": network.id}]) - conn.compute.wait_for_server(server) + image = conn.compute.find_image(IMAGE_NAME) + flavor = conn.compute.find_flavor(FLAVOR_NAME) + network = conn.network.find_network(NETWORK_NAME) - print(server) + if not conn.compute.find_keypair(KEYPAIR_NAME): + keypair = conn.compute.create_keypair(name=KEYPAIR_NAME) + + with open(PRIVATE_KEYPAIR_FILE, 'w') as f: + f.write("%s" % keypair.private_key) + + os.chmod(PRIVATE_KEYPAIR_FILE, 0o400) + + server = conn.compute.create_server( + name='openstacksdk-example', image=image, flavor=flavor, + networks=[{"uuid": network.id}], key_name=KEYPAIR_NAME) + + server = conn.compute.wait_for_server(server) + + print("ssh -i {key} root@{ip}".format( + key=PRIVATE_KEYPAIR_FILE, + ip=server.access_ipv4)) diff --git a/examples/compute/find.py b/examples/compute/find.py index faf39a3bc..b009df922 100644 --- a/examples/compute/find.py +++ b/examples/compute/find.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import examples.connect + """ Find a resource from the Compute service. @@ -20,7 +22,7 @@ For a full guide see TODO(etoews):link to docs on developer.openstack.org def find_image(conn): print("Find Image:") - image = conn.compute.find_image("fedora-20.x86_64") + image = conn.compute.find_image(examples.connect.IMAGE_NAME) print(image) @@ -30,8 +32,18 @@ def find_image(conn): def find_flavor(conn): print("Find Flavor:") - flavor = conn.compute.find_flavor("m1.small") + flavor = conn.compute.find_flavor(examples.connect.FLAVOR_NAME) print(flavor) return flavor + + +def find_keypair(conn): + print("Find Keypair:") + + keypair = conn.compute.find_keypair(examples.connect.KEYPAIR_NAME) + + print(keypair) + + return keypair diff --git a/examples/compute/list.py b/examples/compute/list.py index 28a3c048d..0886f8818 100644 --- a/examples/compute/list.py +++ b/examples/compute/list.py @@ -36,3 +36,10 @@ def list_flavors(conn): for flavor in conn.compute.flavors(): print(flavor) + + +def list_keypairs(conn): + print("List Keypairs:") + + for keypair in conn.compute.keypairs(): + print(keypair) diff --git a/examples/connect.py b/examples/connect.py index 0bf398f74..dc45b531b 100644 --- a/examples/connect.py +++ b/examples/connect.py @@ -16,18 +16,53 @@ Connect to an OpenStack cloud. For a full guide see TODO(etoews):link to docs on developer.openstack.org """ +import os + +import os_client_config + from openstack import connection from openstack import profile +from openstack import utils +import sys + +utils.enable_logging(True, stream=sys.stdout) + +#: Defines the OpenStack Client Config (OCC) cloud key in your OCC config +#: file, typically in $HOME/.config/openstack/clouds.yaml. That configuration +#: will determine where the examples will be run and what resource defaults +#: will be used to run the examples. +TEST_CLOUD = os.getenv('OS_TEST_CLOUD', 'test_cloud') class Opts(object): - def __init__(self, cloud='hp', debug=False): - self.cloud = cloud + def __init__(self, test_cloud='test_cloud', debug=False): + self.cloud = test_cloud self.debug = debug +def _get_resource_value(resource_key, default): + try: + return cloud.config['example'][resource_key] + except KeyError: + return default + +opts = Opts(test_cloud=TEST_CLOUD) +occ = os_client_config.OpenStackConfig() +cloud = occ.get_one_cloud(opts.cloud, argparse=opts) + +IMAGE_NAME = _get_resource_value('image_name', 'fedora-20.x86_64') +FLAVOR_NAME = _get_resource_value('flavor_name', 'm1.small') +NETWORK_NAME = _get_resource_value('network_name', 'private') +KEYPAIR_NAME = _get_resource_value('keypair_name', 'openstacksdk-example') +PRIVATE_KEYPAIR_FILE = _get_resource_value('private_keypair_file', + "{home}/{ssh}/id_rsa.{key}".format( + home=os.getenv("HOME"), + ssh='.ssh', + key=KEYPAIR_NAME)) + + def create_connection_from_config(): - return connection.from_config(Opts(cloud='test_cloud')) + return connection.from_config(opts) def create_connection(auth_url, region, project_name, username, password): diff --git a/examples/network/find.py b/examples/network/find.py index 21844f326..1d9005d13 100644 --- a/examples/network/find.py +++ b/examples/network/find.py @@ -10,6 +10,8 @@ # License for the specific language governing permissions and limitations # under the License. +import examples.connect + """ Find a resource from the Network service. @@ -20,7 +22,7 @@ For a full guide see TODO(etoews):link to docs on developer.openstack.org def find_network(conn): print("Find Network:") - network = conn.network.find_network("public") + network = conn.network.find_network(examples.connect.NETWORK_NAME) print(network) diff --git a/openstack/tests/examples/test_compute.py b/openstack/tests/examples/test_compute.py index 4dd53fd93..60b62e3f5 100644 --- a/openstack/tests/examples/test_compute.py +++ b/openstack/tests/examples/test_compute.py @@ -13,8 +13,8 @@ import unittest from examples.compute import create -from examples.compute import find -from examples.compute import list +from examples.compute import find as compute_find +from examples.compute import list as compute_list from examples import connect from examples.network import find as network_find from examples.network import list as network_list @@ -32,13 +32,15 @@ class TestCompute(unittest.TestCase): cls.conn = connect.create_connection_from_config() def test_compute(self): - list.list_servers(self.conn) - list.list_images(self.conn) - list.list_flavors(self.conn) + compute_list.list_servers(self.conn) + compute_list.list_images(self.conn) + compute_list.list_flavors(self.conn) + compute_list.list_keypairs(self.conn) network_list.list_networks(self.conn) - image = find.find_image(self.conn) - flavor = find.find_flavor(self.conn) - network = network_find.find_network(self.conn) + compute_find.find_image(self.conn) + compute_find.find_flavor(self.conn) + compute_find.find_keypair(self.conn) + network_find.find_network(self.conn) - create.create_server(self.conn, 'example', image, flavor, network) + create.create_server(self.conn)