Looking to take Nutanix for a free test drive?
Click on the following to see what it's all about:

Nutanix Calm DSL – Project Environments

Nutanix Calm DSL - Project Environments

In the recently released Nutanix Calm DSL Lab, a ton of various Calm DSL topics were covered. Before diving into the content for this article, I strongly recommend checking out the lab, as it is a great way to get started with the Calm DSL.

One of the topics in the lab was Calm Projects. In Nutanix Calm, the project construct defines various environment-specific settings. For example:

  • Permissions e.g. user accounts and groups that can deploy a marketplace application.
  • The networks that can be used when deploying an application.
  • Default VM specifications and deployment options – vCPUs, vRAM, storage, base images, Cloud-Init or Sysprep specs.
  • Credentials.

At the time of writing the Calm DSL lab, a Calm project’s accompanying environment couldn’t yet be managed by the Calm DSL – that has now changed. In addition to the Calm DSL lab, I also published an article in latest August that outlined how to create Calm projects using the Calm DSL CLI tools. To ensure today’s content has some context, I’ll re-use some of that content here.

Quick Recap – Project Files

When using the Calm DSL CLI to create a project, an accompanying project file is required. This is a Python file that describes various project settings e.g. the cluster name, groups and users to assign to the new project. For reference, the project file below is what was used in the Nutanix Calm DSL – Managing Projects article.

from calm.dsl.builtins import Project
from calm.dsl.builtins import Provider, Ref


ACCOUNT = "NTNX_LOCAL_AZ"
SUBNET = "vlan.0"
CLUSTER = "Galactica"
USER = "jane.doe@ntnx.local"
GROUP = "cn=sspadmins,cn=users,dc=ntnx,dc=local"
VCPUS = 1
STORAGE = 2  # GiB
MEMORY = 1  # GiB


class TestDemoProject(Project):
    """Project created by the Calm DSL"""

    providers = [
        Provider.Ntnx(
            account=Ref.Account(ACCOUNT),
            subnets=[Ref.Subnet(name=SUBNET, cluster=CLUSTER)],
        ),
    ]

    users = [
        Ref.User(name=USER),
    ]

    groups = [Ref.Group(name=GROUP)]

    quotas = {"vcpus": VCPUS, "storage": STORAGE, "memory": MEMORY}

Also for reference, the command used to create the project using that file was as follows.

calm create project --file test_project.py --name test_project_cr --description "project created by the calm dsl"

You’ll notice, however, that there is no mention of the project environment in that project file. This means some Calm features can’t be used with that project. To ensure all features are available, the project needs to have environment settings configured. Before doing that, let’s look at what happens when a project is created with the project file above.

Project created with no Environment
The project has no credentials
Lastly, the project has no network adapters for use when connecting to deployed VMs

None of these things seem particularly major in isolation, since a Calm blueprint can specify those settings for us. However, certain features e.g. Marketplace Blueprint deployments, will sometimes require these settings to exist before the application can be deployed. Without those settings configured via a project’s environment, a true end-to-end infrastructure deployment would require some manual intervention.

Let’s look at the project file changes so the environment can be configured at the same time.

Calm DSL Project File with Environment Configuration

Before continuing, it’s worth noting that the required changes to configure a project’s environment may seem significant. In addition to the top-level projects settings like name, groups and users, we will also specify:

  • 1x default credential. This can be any credential supported by Nutanix Calm, i.e. username and password or SSH key pair authentication.
  • 1x VM specification that will be used as the default when required.
  • 1x network adapter that will be connected to an AHV subnet specified by the project file.
  • The required Calm DSL Python imports that enable support of these settings.

The complete project file now looks like this. Below this file I’ll briefly highlight the changes, although each one has been indicated by a comment within the file itself.

from calm.dsl.builtins import Project
from calm.dsl.builtins import Provider, Ref

# read_local_file has been added as an additional import
from calm.dsl.builtins import read_local_file

# basic_cred has been added as an additional import
from calm.dsl.builtins import basic_cred

# Environment has been added as an additional import
from calm.dsl.builtins import Environment

# Substrate has been added as an additional import
from calm.dsl.builtins import Substrate

# readiness_probe has been added as an additional import
from calm.dsl.builtins import readiness_probe

# AhvVm has been added as an additional import
from calm.dsl.builtins import AhvVm

# AhvVmResources has been added as an additional import
from calm.dsl.builtins import AhvVmResources

# AhvVmDisk has been added as an additional import
from calm.dsl.builtins import AhvVmDisk

# AhvVmGC has been added as an additional import
from calm.dsl.builtins import AhvVmGC

# AhvVmNic has been added as an additional import
from calm.dsl.builtins import AhvVmNic

# this section has been added to allow environment configuration
# specifically, this creates a Calm credential
# at least one credential is mandatory when configuring a project environment
CENTOS_KEY = read_local_file("keys/centos")
CENTOS_PUBLIC_KEY = read_local_file("keys/centos_pub")

Centos = basic_cred("centos", CENTOS_KEY, name="Centos", type="KEY", default=True)


# when configuring a project environment, a default VM configuration must be provided
# here we are defining both an AHV VM and the Substrate that will use it
# please note the "centos7-cloudinit" image and "vlan.0" network referenced by the spec is cluster-specific
# you will need to alter those settings to match your environment
class MyAhvLinuxVmResources(AhvVmResources):

    memory = 4
    vCPUs = 2
    cores_per_vCPU = 1
    disks = [
        AhvVmDisk.Disk.Scsi.cloneFromImageService("centos7-cloudinit", bootable=True),
    ]
    nics = [AhvVmNic("vlan.0")]

    guest_customization = AhvVmGC.CloudInit(
        config={
            "users": [
                {
                    "name": "centos",
                    "ssh-authorized-keys": [CENTOS_PUBLIC_KEY],
                    "sudo": ["ALL=(ALL) NOPASSWD:ALL"],
                }
            ]
        }
    )


class MyAhvLinuxVm(AhvVm):

    resources = MyAhvLinuxVmResources
    # categories may need to be altered to match your environment
    categories = {"AppFamily": "Backup", "AppType": "Default"}


class AhvVmSubstrate(Substrate):
    """AHV VM config given by reading a spec file"""

    provider_spec = MyAhvLinuxVm
    readiness_probe = readiness_probe(disabled=True)


ACCOUNT = "NTNX_LOCAL_AZ"
SUBNET = "vlan.0"
CLUSTER = "Galactica"
USER = "jane.doe@ntnx.local"
GROUP = "cn=sspadmins,cn=users,dc=ntnx,dc=local"
VCPUS = 1
STORAGE = 2  # GiB
MEMORY = 1  # GiB


# this class has been added and links together both our previously-defined
# credentials and VM configuration
class ProjEnvironment(Environment):
    substrates = [AhvVmSubstrate]
    credentials = [Centos]


class TestDemoProject(Project):
    """Project created by the Calm DSL"""

    providers = [
        Provider.Ntnx(
            account=Ref.Account(ACCOUNT),
            subnets=[Ref.Subnet(name=SUBNET, cluster=CLUSTER)],
        ),
    ]

    users = [
        Ref.User(name=USER),
    ]

    groups = [Ref.Group(name=GROUP)]

    quotas = {"vcpus": VCPUS, "storage": STORAGE, "memory": MEMORY}

    # here we are using our previously-defined Environment instance
    # as the environment configuration for the new project
    envs = [ProjEnvironment]

The changes are as follows.

  • Required imports have been specified at the start of the file. I’ve spaced them out onto separate lines but only for the sake of readability.
  • 1x SSH key pair credential named Centos has been created, utilising two local files:
    • ~/.calm/.local/keys/centos
    • ~/.calm/.local/keys/centos_pub
  • 1x VM spec named MyAhvLinuxVmResources has been added.
  • 1x AHV VM named MyAhvLinuxVm has been added.
  • 1x Calm substrate named AhvVmSubstrate has been added (this is what the project will use when configuring the environment).
  • An instance of Environment has been added, named ProjEnvironment.
  • The ProjEnvironment instance has been added to the project definition.

To create the project using this new project file, the command is exactly the same as before. The only changes I’ve made are to the name and description of the project, and only so they are easily differentiated in my development environment.

calm create project --file test_project_with_env.py --name test_project_cr_with_env --description "project with environment created by the calm dsl"

The results look like this:

Creating a Calm project with configured environment, using the Nutanix Calm DSL

Lastly, if we now look at Prism Central and open the project settings within Calm, the environment warning is gone, the Centos credential is ready to be used and the default VM spec is present.

No environment warning showing
“Centos” credential ready to be used
Part of the default VM specification (full spec cut to reduce screenshot size)

Wrapping Up

This process may seem somewhat minor on its own, especially considering it is something those with Nutanix Calm experience will be familiar with.

However, combining this process with the ability to create and deploy blueprints, manage marketplace items and assign permissions (more on that in the next article) means this is just the next step towards configuring an entire infrastructure using automation processes.

Hopefully this information was interesting and useful. Thanks for reading and have a great day! 🙂

Nutanix CALM DSL LAB 1.0
AVAILABLE NOW!

logo_calm

Have you wanted to learn the Nutanix Calm DSL, but haven't been sure where to start?
Check out the Nutanix Calm DSL Lab 1.0 now!