What's on this page

Create Resource

Create the Resource Project

The resource comprises 2 Apache servers defined in a HEAT template (one that uses an existing SSH key pair pre-created in Openstack, the other uses a new SSH key pair created by the HEAT template) and configured by Ansible playbooks.

Start by creating a directory for the Resource project and navigating to it

mkdir hw-apache2 && cd hw-apache2

Use LMCTL to create the basis of a Resource project

lmctl project create --type Resource --rm brent

Each resource requires a resource descriptor in YAML format that is located in the ‘Definitions/lm/resource.yaml’ file of the resource package. The format of this file is defined by the TNC-O Resource Descriptor YAML Specification.

Add Resource Descriptor

Update the Definitions/lm/resource.yaml file with the following content:

description: descriptor for hw-apache2
properties:
  server1_ssh_key:
    type: key
    default: apache1_server_key
    description: This is the name of an existing SSH key pair in Openstack, used by apache_server1 server
  server2_ssh_key_name:
    description: This is the name given to a new SSH key pair generated by the HEAT template, and used by apache_server2 server
    default: apache2_server_key
    type: string
  image_id:
    default: xenial-server-cloudimg-amd64-disk1
    description: Image to be used for compute instance
  flavor:
    default: m1.small
    description: Type of instance (flavor) to be used
  server1_internal_ip:
    read-only: true
    description: IP assigned to the apache1 server on the internal network
  server1_public_ip: 
    read-only: true
    description: IP assigned to the apache1 server to access from the external network
  server2_internal_ip:
    read-only: true
    description: IP assigned to the apache2 server on the internal network
  server2_public_ip: 
    read-only: true
    description: IP assigned to the apache2 server to access from the external network
private-properties:
  server2_ssh_key:
    description: An SSH key pair created by the HEAT template, used by apache_server2 server. This will be stored in TNC-O (both the public and private key portions, the private key portion will be stored securely).
    type: key
infrastructure:
  Openstack: {}
lifecycle:
  Create:
    drivers:
      openstack:
        selector:
          infrastructure-type:
          - Openstack
  Delete:
    drivers:
      openstack:
        selector:
          infrastructure-type:
          - Openstack

The descriptor includes 4 input properties, each correspond to an input in our HEAT template:

The descriptor also includes 4 read-only properties, which correspond to outputs in our HEAT template: server1_internal_ip, server1_public_ip, server2_internal_ip, server2_public_ip. Note that server2_ssh_key is a private property because we don’t wish to expose it outside of the resource manager (Brent).

infrastructure defines the infrastructure type as that of Openstack. infrastructure-type property for drivers of lifecycles can then use a wildcard value '*' and the default resource infrastructure will be automatically registered by TNC-O.

Under lifecycle section are 2 basic lifecycle transitions for the resource: Create and Delete. These will be handled by the Openstack VIM Driver to manage infrastructure (e.g create VMs with compute, storage and network infrastructure required on Openstack) to fulfill the resource’s function.

Note that “Openstack” under infrastructure is the infrastructure type by default for all lifecycles, while “openstack” under lifecycle.Create.drivers is the Resource Driver type used by a particular lifecycle.

For “Create” lifecycle, the resource driver will define the format of the templates to be used and automatically pick up suitable infrastructure template under Lifecycle/openstack. In the next step we will create a HEAT template for this lifecycle.

Add Infrastructure

For this example, we will create a new file called openstack-heat.yaml at Lifecycle/openstack with the following content:

heat_template_version: "2018-08-31"
description: "Base infrastructure for an Apache2 example"

parameters:
  server1_ssh_key:
    type: string
    label: Key Name
    description: Name of an existing Openstack SSH key pair
  server2_ssh_key_name:
    type: string
    description: Name of new Openstack SSH key pair created by the HEAT template
  image_id:
    type: string
    label: Image ID
    description: Image to be used for compute instance
  flavor:
    type: string
    label: Instance Type
    description: Type of instance (flavor) to be used

resources:
  ap_security_group: 
    type: "OS::Neutron::SecurityGroup"
    properties: 
      rules: 
        - port_range_min: 1
          port_range_max: 100
          protocol: tcp
        - remote_ip_prefix: 0.0.0.0/0
          protocol: icmp
      name: ap_security_group

  ap_net: 
    type: "OS::Neutron::Net"
    properties: 
      admin_state_up: true
      name: ap_net

  ap_subnet: 
    type: "OS::Neutron::Subnet"
    properties: 
      network: { get_resource: ap_net }
      name: ap_subnet
      enable_dhcp: true
      cidr: "10.10.10.0/24"
  ap_port1:
    type: "OS::Neutron::Port"
    properties: 
      admin_state_up: true
      fixed_ips: 
        - subnet: { get_resource: ap_subnet }
      security_groups: 
        - { get_resource: ap_security_group }
      name: ap_port
      network: { get_resource: ap_net }
  ap_port2:
    type: "OS::Neutron::Port"
    properties: 
      admin_state_up: true
      fixed_ips: 
        - subnet: { get_resource: ap_subnet }
      security_groups: 
        - { get_resource: ap_security_group }
      name: ap_port
      network: { get_resource: ap_net }

  ap_router: 
    type: "OS::Neutron::Router"
    properties: 
      admin_state_up: true
      name: ap_router
      external_gateway_info:
        network: "public"

  ap_routerinterface: 
    type: "OS::Neutron::RouterInterface"
    properties: 
      router: { get_resource: ap_router }
      subnet: { get_resource: ap_subnet }

  apache_server1_floating_ip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: "public"
      port_id: { get_resource: ap_port1 }

  apache_server2_floating_ip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: "public"
      port_id: { get_resource: ap_port2 }

  apache_server1: 
    type: "OS::Nova::Server"
    properties: 
      networks: 
        - port: { get_resource: ap_port1 }
      name: apache_server
      flavor: { get_param: flavor }
      key_name: { get_param: server1_ssh_key }
      image: { get_param: image_id }
      config_drive: true
      user_data_format: RAW
      user_data: |
        #cloud-config
        manage_etc_hosts: true
        bootcmd: 
         - [ sysctl, net.ipv4.ip_forward=1 ]
         - [ sh, -c, echo 'nameserver 8.8.8.8' > /etc/resolv.conf ]
        packages:
         - "python"
  apache_server2: 
    type: "OS::Nova::Server"
    properties: 
      networks: 
        - port: { get_resource: ap_port2 }
      name: apache_server
      flavor: { get_param: flavor }
      key_name: { get_resource: server2_ssh_key }
      image: { get_param: image_id }
      config_drive: true
      user_data_format: RAW
      user_data: |
        #cloud-config
        manage_etc_hosts: true
        bootcmd: 
         - [ sysctl, net.ipv4.ip_forward=1 ]
         - [ sh, -c, echo 'nameserver 8.8.8.8' > /etc/resolv.conf ]
        packages:
         - "python"
  server2_ssh_key:
    type: OS::Nova::KeyPair
    properties:
      name: { get_param: server2_ssh_key_name }
      save_private_key: True

outputs:
  server1_internal_ip: 
    value: { get_attr: [ apache_server1 , first_address ] }
  server1_public_ip: 
    value: { get_attr: [ apache_server1_floating_ip , floating_ip_address ] }
  server2_internal_ip: 
    value: { get_attr: [ apache_server2 , first_address ] }
  server2_public_ip: 
    value: { get_attr: [ apache_server2_floating_ip , floating_ip_address ] }
  server2_ssh_key:
    value:
      str_replace:
        template: $key_name#$private_key#$public_key
        params:
            $key_name: { get_param: [ server2_ssh_key_name ] }
            $private_key: { get_attr: [ server2_ssh_key, private_key ] }
            $public_key: { get_attr: [ server2_ssh_key, public_key ] }

This will create two Apache Servers running in an Openstack VM.

It will output the IP addresses of the Apache servers, along with the combined private and public portions of the apache_server2’s key as an output key property called server2_ssh_key. Note the structure of the server2_ssh_key output property value; it consists of a single line containing the key name, private and public key portions (in PEM format), separated by hashes. Note also the definition of server2_ssh_key as property of type key in the private-properties section of the resource descriptor. This defines the property as private to Brent, with a type of key. Note that private string properties can be ommitted from this section (the “string” type is the default).

Next Steps

You have now created the basic files needed for a simple Resource with OpenStack infrastructure. Move on to creating a shared infrastructure key.