OpenStack Plugin

Note: This documentation refers to Cloudify Openstack Plugin v2.X, the old version of the Openstack Plugin. For documentation on the new version, see Openstack Plugin v3.

The OpenStack plugin enables you to use an OpenStack-based cloud infrastructure for deploying services and applications. For more information about OpenStack, see https://www.openstack.org/.

Plugin Requirements

Compatibility

The OpenStack plugin uses various OpenStack client packages. The versions used in the OpenStack plugin are as follows:

OpenStack Configuration

The OpenStack plugin requires credentials and endpoint setup information in order to authenticate and interact with OpenStack.

Providing Credentials as Secrets

It is recommended that you store your credentials as secrets. You can do this using the CLI. Secrets can then be accessed inside your blueprints, as follows:

 external_network:
    type: cloudify.openstack.nodes.Network
    properties:
      openstack_config:
        username: { get_secret: keystone_username }
        password: { get_secret: keystone_password }
        tenant_name: { get_secret: keystone_tenant_name }
        auth_url: { get_secret: keystone_url }
        region: { get_secret: region }
 

Providing Credentials as Environment Variables that are not Stored as Secrets

The OpenStack client suite (Nova, Neutron and so on) will always look for your OpenStack credentials and endpoint setup information in the following order. These values take precedence because this is the default behavior of the client library. It is not recommended that these are included.

  1. Environment variables for each of the configuration parameters.
  2. JSON file at /etc/cloudify/openstack_config.json or at a path specified by the value of an environment variable named OPENSTACK_CONFIG_PATH

On the other hand, the plugin gathers credentials from the following sources, in the following order. This is the supported approach.

<div class="panel panel-primary panel-warning">
<div class="panel-heading">Caution</div>
<div class="panel-body">

Each source could partially or completely override values gathered from previous ones.

  1. Values specified in the openstack_config property for the node whose operation is currently getting executed (in the case of relationship operations, the openstack_config property of either the source or target nodes will be used if available, with the source’s one taking precedence).
  2. Values specified in the openstack_config runtime property for the node instance whose operation is currently being executed (in the case of relationship operations, the openstack_config property of either the source or target node instances will be used if available, with the source’s one taking precedence).
  3. Values specified in the openstack_config operation input.

Configuration Structure

The openstack_config property can contain the following key-value pairs.

SSL Certificate Validation

When connecting to OpenStack’s endpoint over SSL (which is the typical case), the OpenStack client libraries, by default, perform validation on the certificate presented by OpenStack. The validation is performed against the CA certificates’ bundle used by Python’s requests library. That bundle is provided by the certifi Python library.

SSL validation is being performed (or skipped) as follows:

Logging for OpenStack Libraries

The OpenStack libraries used by the OpenStack plugin perform their own logging using the standard Python logging library.

It is possible to control the visibility of OpenStack API’s logging on Cloudify’s logger by using the logging configuration directive.

The structure of the logging directive is as follows:

logging:
  use_cfy_logger: <boolean> (defaults to true)
  groups:
    nova: <level>
    neutron: <level>
    cinder: <level>
    keystone: <level>
    glance: <level>
  loggers:
    <logger-name>: <level>
    <logger-name>: <level>
    <logger-name>: <level>
    ...

The default logging directive’s value is:

logging:
  use_cfy_logger: true
  groups:
    nova: debug
    neutron: debug
    cinder: debug
    keystone: debug
    glance: debug
  loggers:
    keystoneauth.session: debug

If you specify a logging directive, its contents will be merged with the default.

If use_cfy_logger is true, then a logging handler is added to all applicable OpenStack API loggers (described below) so log records are emitted to the Cloudify logger in addition to any other handlers that may be configured.

The groups section is used to easily set the logging level for groups of loggers, per API. Each such group (nova, neutron) is associated with the list of loggers that belong to the Client class(es) of that particular service.

For example, setting nova to info will result in the following loggers being set to info level:

In addition, you can set the logging level of individual loggers under the loggers section.

Types

cloudify.openstack.nodes.Server

  my-openstack-vm:
    type: cloudify.openstack.nodes.Server
    properties:
      server:
        key_name: my-openstack-key-name
        image: e26cf47c-15a2-46fb-8adf-07b8b977b32e
        flavor: 4
 

Derived From: cloudify.nodes.Compute

Properties:

Mapped Operations:

Attributes:

See the Common Runtime Properties section.

Two additional runtime properties are available on node instances of this type after the cloudify.interfaces.lifecycle.start operation succeeds.

cloudify.openstack.nodes.WindowsServer

Derived From: cloudify.openstack.nodes.Server

This type has the same properties and operations mapping as the type above it (because it derives from it). However, it overrides some of the agent and plugin installations operations mapping that is derived from the built-in cloudify.nodes.Compute type. Use this type when working with a Windows server.

In addition, the default value for the use_password property is overridden for this type, and is set to true. If you are using an image with a preset password, change the value to false.

cloudify.openstack.nodes.KeyPair

  my-openstack-keypair:
    type: cloudify.openstack.nodes.KeyPair
    properties:
      keypair:
        name: my-openstack-key-name
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.Subnet

  my-openstack-subnet:
    type: cloudify.openstack.nodes.Subnet
    properties:
      subnet:
        ip_version: 4
        cidr: '192.168.121.0/24'
        enable_dhcp: False
        dns_nameservers: ['8.8.4.4', '8.8.8.8']
        allocation_pools:
        - start: 192.168.121.50
          end: 192.168.121.250
 

Derived From: cloudify.nodes.Subnet

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.SecurityGroup

  my-openstack-security-group:
    type: cloudify.openstack.nodes.SecurityGroup
    properties:
      security_group:
        name: my-openstack-security-group
        description: My Openstack Security Group
 

Derived From: cloudify.nodes.SecurityGroup

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.Router

  my-openstack-router:
    type: cloudify.openstack.nodes.Router
    properties:
      router:
        name: my-openstack-router
 

Derived From: cloudify.nodes.Router

Properties:

Notes:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.Port

  my-openstack-port:
    type: cloudify.openstack.nodes.Port
    properties:
      port:
        allowed_address_pairs: [{'ip_address': '192.168.121.0/24'}]
        security_groups:
        - '12a49669-e590-45ac-9c7e-97652b7502f4'
        - '391bbfc3-8bde-41d7-92c7-ac83b74e6464'
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

In addition, the port’s fixed-IP is available via the fixed_ip_address runtime property.

cloudify.openstack.nodes.Network

  my-openstack-network:
    type: cloudify.openstack.nodes.Network
    properties:
      network:
        name: 'my-openstack-network'
 

Derived From: cloudify.nodes.Network

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.FloatingIP

  my-openstack-floating-ip:
    type: cloudify.openstack.nodes.FloatingIP
    properties:
      floatingip:
        floating_network_name: my-external-openstack-network
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

Note that the actual IP is available via the floating_ip_address runtime-property.

cloudify.openstack.nodes.Volume

  my-openstack-volume:
    type: cloudify.openstack.nodes.Volume
    properties:
      volume:
        size: 60
 

Derived From: cloudify.nodes.Volume

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.ServerGroup

  my-openstack-server-group:
    type: cloudify.openstack.nodes.ServerGroup
    properties:
      server_group:
        policies:
        - anti-affinity
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.Project

  my-openstack-project:
    type: cloudify.openstack.nodes.Project
    properties:
      project:
        name: my-openstack-project
        description: My new project.
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nodes.Image

  my-openstack-image:
     properties:
       image:
         name: my-openstack-image
         container_format: “bare”
         disk_format: “qcow2"
 

Derived From: cloudify.nodes.Root

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

cloudify.openstack.nova_net.nodes.FloatingIP

Derived From: cloudify.nodes.VirtualIP

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

Note that the actual IP is available via the floating_ip_address runtime-property.

cloudify.openstack.nova_net.nodes.SecurityGroup

Derived From: cloudify.nodes.SecurityGroup

Properties:

Mapped Operations:

Attributes:

See the common Runtime Properties section.

Relationships

Some relationships take effect in non-relationship operations. For example, a subnet that is connected to a network is connected on the subnet’s creation (in the cloudify.interfaces.lifecycle.create operation) and not in a cloudify.interfaces.relationship_lifecycle.establish operation. This occurs whenever the connection information is required at resource creation.

cloudify.openstack.port_connected_to_security_group

Description: A relationship for a port to a security group.

Mapped Operations:

cloudify.openstack.subnet_connected_to_router

Description: A relationship for connecting a subnet to a router.

Mapped Operations:

cloudify.openstack.server_connected_to_floating_ip

Description: A relationship for associating a floating IP with a server.

Mapped Operations:

cloudify.openstack.server_connected_to_security_group

Description: A relationship for setting a security group on a server.

Mapped Operations:

cloudify.openstack.volume_attached_to_server

Description: A relationship for attaching a volume to a server.

Mapped Operations:

cloudify.openstack.server_connected_to_port

Description: A relationship for connecting a server to a port. The server uses this relationship to automatically connect to the port upon server creation.

Mapped Operations:

cloudify.openstack.port_connected_to_subnet

Description: A relationship for connecting a port to a subnet. This is useful when a network has multiple subnets, and a port must belong to a specific subnet on that network. The port then receives an IP from that specific subnet.

Note that when using this relationship in combination with the port type’s property fixed_ip, the IP must be on the CIDR of the subnet connected to the port.

Note: This relationship has no operations associated with it. The port uses this relationship to automatically connect to the subnet upon port creation.

cloudify.openstack.port_connected_to_floating_ip

Description: A relationship for associating a floating IP with a port. If that port is later connected to a server, the server is accessible via the floating IP.

Mapped Operations:

Common Behaviors of Types

Validations

All types provide the same base functionality for the cloudify.interfaces.validation.creation interface operation:

Runtime Properties

Node instances of any of the types defined in this plugin are set with the following runtime properties during the cloudify.interfaces.lifecycle.create operation:

The only exceptions are the two floating IP types. Because floating-ip objects on OpenStack do not have a name, the external_name runtime property is replaced with the floating_ip_address name, which holds the object’s actual IP address.

Default Resource Naming Convention

When creating a new resource (i.e. use_external_resource is set to false), its name on OpenStack is the value of its resource_id property. However, if this value is not provided, the name defaults to the following schema:

<openstack-resource-type>_<deployment-id>_<node-instance-id>

For example, if a server node is defined as follows:

node_templates:
  myserver:
    type: cloudify.openstack.nodes.Server
    ...

Without setting the resource_id property, the server’s name on OpenStack will be server_my-deployment_myserver_XXXXX (where the XXXXX is the autogenerated part of the node instance’s ID).

Using Existing Resources

You can use existing resources on OpenStack, regardless of whether they were created by a different Cloudify deployment or not via Cloudify at all.

All Cloudify OpenStack types have a property called use_external_resource, which has a default value of false. When set to true, the plugin applies different semantics for each of the operations executed on the relevant node’s instances. Specifically, in the case of the cloudify.interfaces.lifecycle.create operation, rather than creating a new resource on OpenStack of the specified type, the plugin behaves as follows:

  1. Attempts to locate an existing resource on OpenStack for which the name (or IP, in the case of one of the floating-ip types) is the value specified for the resource_id property. If more than one is found, an error is generated.

  2. If no resource is found, the plugin uses the value of the resource_id property to look for the resource by ID. If a resource is still not found, an error is generated.

  3. If a single resource is found, the plugin uses that resource and sets the node instance with the appropriate runtime properties, according to the resource’s data.

The semantics of other operations are also affected, as follows:

Notes

Nova-net Support

The OpenStack plugin includes support for Nova-net mode, meaning an OpenStack installation that does not have the Networking API (Neutron service).

In such an environment, there is only a single preconfigured private network that all servers make use of automatically. There are no subnets, networks, routers or ports. Since these resource types do not exist, the plugin’s equivalent types are not valid for use in such an environment.

However, there are some resource types for which the API is available via both the Nova and the Neutron services. They had originally been on the Nova service and were later moved and received extended implementation in the Neutron service. They were also retained for backward compatibility in the Nova service.

For these resource types the OpenStack plugin defines two separate types. One type is in the plugin’s standard types namespace (cloudify.openstack.nodes.XXX) that uses the newer, extended API via the Neutron service. The other type is in a special namespace (cloudify.openstack.nova_net.nodes.XXX) that uses the older API via the Nova service. You might therefore notice two separate types defined for Floating IP, and for Security Group.

To summarize, ensure that when working in a Nova-net OpenStack environment, Neutron types are not used. These include all types in which the resources’ APIs are natively available only via the Network API, and the types that are in the cloudify.openstack.nova_net.Nodes namespace.

Conversely, when using an OpenStack environment that supports Neutron, it is recommended that you use the Neutron-versions of the relevant types (meaning that you avoid any types defined under the cloudify.openstack.nova_net.Nodes namespace), as they offer more advanced capabilities. However, it’s important to mention that this is not required, and using the Nova-versions of some types in a Neutron-enabled environment is possible and will work as well.

Examples

Example I: Using plugin types and creating relationships

This example demonstrates how to use most of the types in this plugin, and how to create the relationships between them. It creates a server with a security group set on it and a floating IP associated to it, on a subnet in a network.

The following is an excerpt from the blueprint’s blueprint.node_templates section:

my_floating_ip:
  type: cloudify.openstack.nodes.FloatingIP
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            floating_network_name: Ext-Net


my_network:
  type: cloudify.openstack.nodes.Network
  properties:
    resource_id: my_network_openstack_name


my_subnet:
  type: cloudify.openstack.nodes.Subnet
  properties:
    resource_id: my_subnet_openstack_name
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            cidr: 1.2.3.0/24
            ip_version: 4
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            cidr: 1.2.3.0/24
            ip_version: 4
  relationships:
    - target: my_network
      type: cloudify.relationships.contained_in


my_security_group:
  type: cloudify.openstack.nodes.SecurityGroup
  properties:
    resource_id: my_security_group_openstack_name
    rules:
      - remote_ip_prefix: 0.0.0.0/0
        port: 8080


my_server:
  type: cloudify.openstack.nodes.Server
  properties:
    resource_id: my_server_openstack_name
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101
  relationships:
    - target: my_network
      type: cloudify.relationships.connected_to
    - target: my_subnet
      type: cloudify.relationships.depends_on
    - target: my_floating_ip
      type: cloudify.openstack.server_connected_to_floating_ip
    - target: my_security_group
      type: cloudify.openstack.server_connected_to_security_group

Node by Node Explanation

  1. Creates a floating IP with the node name my_floating_ip, and the Ext-Net floating_network_name. (This value represents the name of the external network).

  2. Creates a network with the node name my_network, and the my_network_openstack_name name on OpenStack.

  3. Creates a subnet with the node name my_subnet, and the my_subnet_openstack_name name on OpenStack. The subnet’s address range is defined as 1.2.3.0 - 1.2.3.255 using the cidr parameter, and the subnet’s IP version is set to version 4. The subnet will be set on the my_network_openstack_name network because of the relationship to the my_network node.

  4. Creates a security_group with the node name my_security_group, and the my_security_group_openstack_Name name on OpenStack. The security group is set with a single rule, that allows all traffic (Because the address range 0.0.0.0/0 is used) to port 8080. (The default direction is ingress).

  5. Creates a server with the node name my_server, and the my_server_openstack_name name on OpenStack. The server is set with an image and flavor IDs. The server is set with multiple relationships:

Example II: Using the router and port types

This example demonstrates how to use the router and port types, and some of the relationships that were not included in example I. It creates a server connected to a port, in which the port is set on a subnet in a network and has a security group set on it. Finally, it shows how this subnet connects to a router and from there to the external network.

Following is an excerpt from the blueprint’s blueprint.node_templates section:

my_network:
  type: cloudify.openstack.nodes.Network
  properties:
    resource_id: my_network_openstack_name


my_security_group:
  type: cloudify.openstack.nodes.SecurityGroup
  properties:
    resource_id: my_security_group_openstack_name
    rules:
      - remote_ip_prefix: 0.0.0.0/0
        port: 8080


my_subnet:
  type: cloudify.openstack.nodes.Subnet
  properties:
    resource_id: my_subnet_openstack_name
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            cidr: 1.2.3.0/24
            ip_version: 4
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            cidr: 1.2.3.0/24
            ip_version: 4
  relationships:
    - target: my_network
      type: cloudify.relationships.contained_in
    - target: my_router
      type: cloudify.openstack.subnet_connected_to_router


my_port:
  type: cloudify.openstack.nodes.Port
  properties:
    resource_id: my_port_openstack_name
  relationships:
    - target: my_network
      type: cloudify.relationships.connected_to
    - target: my_subnet
      type: cloudify.openstack.port_connected_to_subnet
    - target: my_security_group
      type: cloudify.openstack.port_connected_to_security_group


my_router:
  type: cloudify.openstack.nodes.Router
  properties:
    resource_id: my_router_openstack_Name


my_server:
  type: cloudify.openstack.nodes.Server
  properties:
    cloudify_agent:
      user: ubuntu
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101
  relationships:
    - target: my_port
      type: cloudify.openstack.server_connected_to_port

Node by Node Explanation

  1. Creates a network. See example I for more information.

  2. Creates a security group. See example I for more information.

  3. Creates a subnet. This is similar to that in example I, but in this example the subnet has an additional relationship set towards a router.

  4. Creates a port, with the node name my_port, and the name my_port_openstack_name on OpenStack. The port is set with multiple relationships:

  1. Creates a router, with the node name my_router and the my_router_openstack_name name on OpenStack. The router will automatically have an interface in the external network.

  2. Creates a server, with the node name my_server, and the the node’s ID name (because no name parameter was supplied under the server property) on OpenStack. The server is set with an image and flavor IDs. It also overrides the cloudify_agent property of its parent type, to set the username that will be used to connect to the server for installing the Cloudify agent on it. Finally, it is set with a relationship to the my_port node. This designated relationship type manages connecting the server to my_port_openstack_name.

Example III: Using the volume type

This example demonstrates how to use the volume type, and the volume_attached_to_server relationship.

Following is an excerpt from the blueprint’s blueprint.node_templates section.

my_server:
  type: cloudify.openstack.nodes.Server
  properties:
    cloudify_agent:
      user: ubuntu
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
            flavor: 101

my_volume:
  type: cloudify.openstack.nodes.Volume
  properties:
    resource_id: my_openstack_volume_name
    device_name: /dev/vdb
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            size: 1
  relationships:
    - target: my_server
      type: cloudify.openstack.volume_attached_to_server

Node by Node Explanation

  1. Creates a server, with name my_server, and with name on OpenStack the node’s ID (since no name parameter was supplied under the server property). The server is set with an image and flavor IDs.
  2. Creates a volume. It is set with a relationship to the my_server node: This designated relationship type will take care of attaching the volume to OpenStack server node.

Example IV: Using Windows server with a Cloudify agent

This example demonstrates how to use a Windows server on which a Cloudify agent is deployed.

Following is an excerpt from the blueprint’s blueprint.node_templates section:

my_keypair:
  type: cloudify.openstack.nodes.KeyPair
  properties:
    private_key_path: /tmp/windows-test.pem

my_server:
  type: cloudify.openstack.nodes.WindowsServer
  relationships:
    - type: cloudify.openstack.server_connected_to_keypair
      target: keypair
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            server:
              image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
              flavor: 101
              name: my-server
              userdata: |
                #ps1_sysnative
                winrm quickconfig -q
                winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'
                winrm set winrm/config '@{MaxTimeoutms="1800000"}'
                winrm set winrm/config/service '@{AllowUnencrypted="true"}'
                winrm set winrm/config/service/auth '@{Basic="true"}'
                &netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow
                &netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow

                msiexec /i https://www.python.org/ftp/python/2.7.6/python-2.7.6.msi TARGETDIR=C:\Python27 ALLUSERS=1 /qn
    cloudify.interfaces.validation:
      creation:
        inputs:
          args:
            server:
              image: 8672f4c6-e33d-46f5-b6d8-ebbeba12fa02
              flavor: 101
              name: my-server
              userdata: |
                #ps1_sysnative
                winrm quickconfig -q
                winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}'
                winrm set winrm/config '@{MaxTimeoutms="1800000"}'
                winrm set winrm/config/service '@{AllowUnencrypted="true"}'
                winrm set winrm/config/service/auth '@{Basic="true"}'
                &netsh advfirewall firewall add rule name="WinRM 5985" protocol=TCP dir=in localport=5985 action=allow
                &netsh advfirewall firewall add rule name="WinRM 5986" protocol=TCP dir=in localport=5986 action=allow

                msiexec /i https://www.python.org/ftp/python/2.7.6/python-2.7.6.msi TARGETDIR=C:\Python27 ALLUSERS=1 /qn
    cloudify.interfaces.worker_installer:
      install:
        inputs:
          cloudify_agent:
            user: Admin
            password: { get_attribute: [SELF, password] }

Node by Node Explanation

  1. Creates a keypair. The private key is saved under /tmp/windows-test.pem.
  2. Creates a Windows server.

Tips

my_network:
  type: cloudify.openstack.nodes.Network
  ...
  interfaces:
    cloudify.interfaces.lifecycle:
      create:
        inputs:
          args:
            # Note that for this parameter to work, OpenStack must be configured to use Neutron's ML2 extensions
            provider:network_type: vxlan

Misc