Skip to content

Commit

Permalink
Task/m calm 20742 vm recovery point changes (#76)
Browse files Browse the repository at this point in the history
* recovery point changes for bps

* Adding api changes

* Adding get commands

* Adding final validations and substrate fixes for vm_recovery_spec

* Adding tests for recovery point bp launches

* Minor fix

* Minor fix in substrate

* Fix serial_port_list for ahv_vm.py

* Adding minor log

* Added catch to check exception

* Minor fix

* Test fix

* Test fix

* Fixing network name in test blueprint
  • Loading branch information
abhijeetkaurav1st committed Oct 17, 2021
1 parent 4d4da6b commit 905fce3
Show file tree
Hide file tree
Showing 19 changed files with 1,007 additions and 89 deletions.
4 changes: 4 additions & 0 deletions calm/dsl/api/handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
from .directory_service import DirectoryServiceAPI
from .access_control_policy import AccessControlPolicyAPI
from .app_protection_policy import AppProtectionPolicyAPI
from .vm_recovery_point import VmRecoveryPointAPI
from .nutanix_task import TaskAPI


class ClientHandle:
Expand Down Expand Up @@ -54,6 +56,8 @@ def _connect(self):
self.acp = AccessControlPolicyAPI(self.connection)
self.environment = EnvironmentAPI(self.connection)
self.app_protection_policy = AppProtectionPolicyAPI(self.connection)
self.vm_recovery_point = VmRecoveryPointAPI(self.connection)
self.nutanix_task = TaskAPI(self.connection)


def get_client_handle_obj(
Expand Down
6 changes: 6 additions & 0 deletions calm/dsl/api/nutanix_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .resource import ResourceAPI


class TaskAPI(ResourceAPI):
def __init__(self, connection):
super().__init__(connection, resource_type="tasks")
6 changes: 6 additions & 0 deletions calm/dsl/api/vm_recovery_point.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from .resource import ResourceAPI


class VmRecoveryPointAPI(ResourceAPI):
def __init__(self, connection):
super().__init__(connection, resource_type="nutanix/v1/vm_recovery_points")
3 changes: 3 additions & 0 deletions calm/dsl/builtins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
AhvVmType,
AhvVmResourcesType,
)
from .models.ahv_recovery_vm import AhvVmRecoveryResources, ahv_vm_recovery_spec

from .models.substrate import Substrate, substrate, SubstrateType
from .models.deployment import Deployment, deployment, DeploymentType
Expand Down Expand Up @@ -184,4 +185,6 @@
"_endpoint",
"CalmEndpoint",
"AppProtection",
"AhvVmRecoveryResources",
"ahv_vm_recovery_spec",
]
67 changes: 67 additions & 0 deletions calm/dsl/builtins/models/ahv_recovery_vm.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import sys
import uuid

from .entity import Entity, EntityType
from .validator import PropertyValidator
from .helper import common as common_helper
from .ahv_vm import AhvVmResourcesType

from calm.dsl.store import Cache
from calm.dsl.constants import CACHE
from calm.dsl.api.handle import get_api_client
from calm.dsl.log import get_logging_handle


LOG = get_logging_handle(__name__)


# AhvRecoveryVm


class AhvVMRecoveryResourcesType(AhvVmResourcesType):
"""Metaclass for ahv vm recovery resources"""

__schema_name__ = "AhvVmRecoveryResources"
__openapi_type__ = "recovery_vm_ahv_resources"


class AhvVMRecoveryResourcesValidator(
PropertyValidator, openapi_type="recovery_vm_ahv_resources"
):
__default__ = None
__kind__ = AhvVMRecoveryResourcesType


def _ahv_vm_recovery_resources(**kwargs):
name = kwargs.get("name", None)
bases = (Entity,)
return AhvVMRecoveryResourcesType(name, bases, kwargs)


AhvVmRecoveryResources = _ahv_vm_recovery_resources()


# AhvVmRecoverySpec


class AhvVMRecoverySpecType(EntityType):
"""Metaclass for ahv vm recovery resources"""

__schema_name__ = "AhvVmRecoverySpec"
__openapi_type__ = "recovery_vm_ahv_spec"


class AhvVMRecoverySpecValidator(
PropertyValidator, openapi_type="recovery_vm_ahv_spec"
):
__default__ = None
__kind__ = AhvVMRecoverySpecType


def ahv_vm_recovery_spec(**kwargs):
name = kwargs.get("name", None)
bases = (Entity,)
return AhvVMRecoverySpecType(name, bases, kwargs)


AhvVMRecoverySpec = ahv_vm_recovery_spec()
25 changes: 15 additions & 10 deletions calm/dsl/builtins/models/ahv_vm.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,25 +41,30 @@ def compile(cls):

# Merging boot_type to boot_config
cdict["boot_config"] = boot_config
boot_type = cdict.pop("boot_type")
boot_type = cdict.pop("boot_type", None)
if boot_type == "UEFI":
cdict["boot_config"]["boot_type"] = "UEFI"

if not cdict["boot_config"]:
cdict.pop("boot_config", None)

serial_port_list = []
for ind, connection_status in cdict["serial_port_list"].items():
if not isinstance(ind, int):
raise TypeError("index {} is not of type integer".format(ind))

if not isinstance(connection_status, bool):
raise TypeError(
"connection status {} is not of type bool".format(connection_status)
if cdict.get("serial_port_list"):
for ind, connection_status in cdict["serial_port_list"].items():
if not isinstance(ind, int):
raise TypeError("index {} is not of type integer".format(ind))

if not isinstance(connection_status, bool):
raise TypeError(
"connection status {} is not of type bool".format(
connection_status
)
)

serial_port_list.append(
{"index": ind, "is_connected": connection_status}
)

serial_port_list.append({"index": ind, "is_connected": connection_status})

cdict["serial_port_list"] = serial_port_list

return cdict
Expand Down
57 changes: 57 additions & 0 deletions calm/dsl/builtins/models/calm_ref.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,3 +272,60 @@ def compile(cls, name="", **kwargs):
)

return vm_ref

class RecoveryPoint:
def __new__(cls, **kwargs):

kwargs["__ref_cls__"] = cls
return _calm_ref(**kwargs)

def compile(cls, name=None, **kwargs):

cls_substrate = common_helper._walk_to_parent_with_given_type(
cls, "SubstrateType"
)
account_uuid = (
cls_substrate.get_referenced_account_uuid() if cls_substrate else ""
)
account_uuid = account_uuid or kwargs.get("account_uuid", "")
if not account_uuid:
LOG.error("Account uuid not found")
sys.exit("Account not found for vm recovery point")

vrs_uuid = kwargs.get("uuid", "")
payload = {"filter": "account_uuid=={}".format(account_uuid)}
if vrs_uuid:
payload["filter"] += ";uuid=={}".format(vrs_uuid)
else:
payload["filter"] += ";name=={}".format(name)

client = get_api_client()
vrc_map = client.vm_recovery_point.get_name_uuid_map(payload)

if not vrc_map:
log_msg = "No recovery point found with " + (
"uuid='{}'".format(vrs_uuid)
if vrs_uuid
else "name='{}'".format(name)
)
LOG.error(log_msg)
sys.exit("No recovery point found")

# there will be single key
vrc_name = list(vrc_map.keys())[0]
vrc_uuid = vrc_map[vrc_name]

if isinstance(vrc_uuid, list):
LOG.error(
"Multiple recovery points found with name='{}'. Please provide uuid.".format(
vrc_name
)
)
LOG.debug("Found recovery point uuids: {}".format(vrc_uuid))
sys.exit("Multiple recovery points found")

return {
"kind": "vm_recovery_point",
"name": vrc_name,
"uuid": vrc_uuid,
}
63 changes: 63 additions & 0 deletions calm/dsl/builtins/models/schemas/ahv_recovery_vm.yaml.jinja2
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
{% import "ref.yaml.jinja2" as ref %}


{% macro AhvVmRecoveryResources() -%}

title: Ahv VM Post Recovery Override Resources
type: object
x-calm-dsl-type: recovery_vm_ahv_resources
properties:
nic_list:
x-calm-dsl-display-name: nics
type: array
items:
$ref: '#/components/schemas/AhvNic'
num_vcpus_per_socket:
type: integer
x-calm-dsl-display-name: cores_per_vCPU
default: 1
num_sockets:
type: integer
x-calm-dsl-display-name: vCPUs
default: 2
memory_size_mib:
x-calm-dsl-display-name: memory
type: integer
default: 4
account_uuid:
type: string
gpu_list:
type: array
x-calm-dsl-display-name: gpus
items:
$ref: '#/components/schemas/AhvGpu'

{%- endmacro %}


{% macro AhvVmRecoverySpec() -%}

title: AhvVmRecoverySpec
type: object
x-calm-dsl-type: recovery_vm_ahv_spec
properties:
vm_name:
type: string
vm_override_resources:
type: object
x-calm-dsl-type: recovery_vm_ahv_resources
recovery_point:
type: object
x-calm-dsl-type: app_calm_ref

{%- endmacro -%}


{% macro AhvRecoveryVmSchema() -%}

AhvVmRecoverySpec:
{{ AhvVmRecoverySpec() | indent(2) }}
AhvVmRecoveryResources:
{{ AhvVmRecoveryResources() | indent(2) }}

{%- endmacro %}
4 changes: 2 additions & 2 deletions calm/dsl/builtins/models/schemas/main.yaml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
{% import "vm_blueprint.yaml.jinja2" as vm_blueprint %}
{% import "calm_ref.yaml.jinja2" as calm_ref %}
{% import "account_provider.yaml.jinja2" as account_provider %}

{% import "ahv_recovery_vm.yaml.jinja2" as ahv_recovery_vm %}

{% macro Schemas() -%}

Expand Down Expand Up @@ -84,7 +84,7 @@
{{ vm_blueprint.VmBlueprintSchema() }}
{{ calm_ref.CalmRefSchema() }}
{{ account_provider.AccountProviderSchema() }}

{{ ahv_recovery_vm.AhvRecoveryVmSchema() }}
{%- endmacro %}


Expand Down
4 changes: 4 additions & 0 deletions calm/dsl/builtins/models/schemas/substrate.yaml.jinja2
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ properties:
x-calm-dsl-type: app_calm_ref
x-calm-dsl-display-name: account
x-calm-dsl-min-version: 3.2.0
vm_recovery_spec:
type: object
x-calm-dsl-type: recovery_vm_ahv_spec
x-calm-dsl-min-version: 3.3.0
create_spec:
x-calm-dsl-display-name: provider_spec
type: object
Expand Down
23 changes: 21 additions & 2 deletions calm/dsl/builtins/models/substrate.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from .validator import PropertyValidator
from .readiness_probe import readiness_probe
from .provider_spec import provider_spec
from .ahv_vm import AhvVm, AhvVmType
from .ahv_vm import AhvVmType, ahv_vm
from .client_attrs import update_dsl_metadata_map, get_dsl_metadata_map
from .metadata_payload import get_metadata_obj
from .helper import common as common_helper
Expand Down Expand Up @@ -268,13 +268,29 @@ def compile(cls):
if not readiness_probe_dict.get("connection_protocol", ""):
readiness_probe_dict["connection_protocol"] = "http"

# Fill out address for readiness probe if not given
if cdict.get("vm_recovery_spec", {}) and cdict["type"] != "AHV_VM":
LOG.error(
"Recovery spec is supported only for AHV_VM substrate (given {})".format(
cdict["type"]
)
)
sys.exit("Unknown attribute vm_recovery_spec given")

# Handle cases for empty readiness_probe and vm_recovery_spec
if cdict["type"] == "AHV_VM":
if not readiness_probe_dict.get("address", ""):
readiness_probe_dict[
"address"
] = "@@{platform.status.resources.nic_list[0].ip_endpoint_list[0].ip}@@"

if cdict.get("vm_recovery_spec", {}):
_vrs = cdict.pop("vm_recovery_spec", None)
if _vrs:
cdict["create_spec"] = ahv_vm(
name=_vrs.vm_name, resources=_vrs.vm_override_resources
)
cdict["recovery_point_reference"] = _vrs.recovery_point

elif cdict["type"] == "EXISTING_VM":
if not readiness_probe_dict.get("address", ""):
readiness_probe_dict["address"] = "@@{ip_address}@@"
Expand Down Expand Up @@ -306,6 +322,9 @@ def compile(cls):
else:
raise Exception("Un-supported vm type :{}".format(cdict["type"]))

if not cdict.get("vm_recovery_spec", {}):
cdict.pop("vm_recovery_spec", None)

# Adding min defaults in vm spec required by each provider
if not cdict.get("create_spec"):

Expand Down
1 change: 1 addition & 0 deletions calm/dsl/cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,5 +25,6 @@
from .brownfield_commands import * # NoQA
from .environment_commands import * # NoQA
from .protection_policy_commands import * # NoQA
from .vm_recovery_point_commands import * # NoQA

__all__ = ["main", "get_api_client"]
Loading

0 comments on commit 905fce3

Please sign in to comment.