Skip to content

Commit

Permalink
Merge pull request #198 from nutanix/release/3.3.0
Browse files Browse the repository at this point in the history
Changes for Calm v3.3.0
  • Loading branch information
abhijeetkaurav1st authored Nov 8, 2021
2 parents a704367 + 36dfaf1 commit e5d97b4
Show file tree
Hide file tree
Showing 110 changed files with 8,827 additions and 362 deletions.
1 change: 1 addition & 0 deletions .github/workflows/sync-repo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ on:

jobs:
build:
if: ${{ github.repository == 'nutanix/calm-dsl' }}
runs-on: [ubuntu-latest]
steps:
- uses: actions/checkout@v2
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ clean:
[ -S /var/run/docker.sock ] && \
docker ps -aq --no-trunc --filter "status=exited" | xargs -I {} docker rm {} && \
docker image prune -f
rm -r venv/ && mkdir venv/ && touch venv/.empty
rm -rf venv/ && mkdir venv/ && touch venv/.empty

test-verbose: dev
venv/bin/py.test -s -vv
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ Context info includes server, project and log configuration for dsl operations.
- List Brownfield vms: `calm get brownfield vms --project <project_name> --type [AHV_VM|AWS_VM|AZURE_VM|GCP_VM|VMWARE_VM]`. Please use `--account` cli option, if project has multiple accounts for a provider type.
- Compile Blueprint: `calm compile bp -f <blueprint_file_location> -b <brownfield_deployments_file_location>`.
- Create Brownfield Application: `calm create app -f <bluprint_file_location> -b <brownfield_deployments_file_location> -n <app_name> -i`.
- Create Brownfield Application using existing blueprint: `calm launch bp <bp_name> -b <brownfield_deployments_file_location> -n <app_name>`. Command will launch existing blueprint to create brownfield application (3.3.0 onwards). Look at sample file [here](examples/Brownfield/separate_file_example/brownfield_deployments.py).

### Decompiling Blueprints (`.json`->`.py`)
Decompilation is process to consume json data for any entity and convert it back to dsl python helpers/classes. Currently, decompile is supported for converting blueprint json to python files. Summary of support for blueprint decompilation(Experimental feature):
Expand Down
8 changes: 8 additions & 0 deletions calm/dsl/api/app_protection_policy.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from .resource import ResourceAPI


class AppProtectionPolicyAPI(ResourceAPI):
def __init__(self, connection):
super().__init__(
connection, resource_type="app_protection_policies", calm_api=True
)
20 changes: 20 additions & 0 deletions calm/dsl/api/application.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,10 @@ def __init__(self, connection):
super().__init__(connection, resource_type="apps")

self.ACTION_RUN = self.ITEM + "/actions/{}/run"
self.PATCH_RUN = self.ITEM + "/patch/{}/run"
self.DOWNLOAD_RUNLOG = self.ITEM + "/app_runlogs/{}/output/download"
self.ACTION_VARIABLE = self.ITEM + "/actions/{}/variables"
self.RECOVERY_GROUPS_LIST = self.ITEM + "/recovery_groups/list"

def run_action(self, app_id, action_id, payload):
return self.connection._call(
Expand All @@ -18,6 +20,14 @@ def run_action(self, app_id, action_id, payload):
method=REQUEST.METHOD.POST,
)

def run_patch(self, app_id, patch_id, payload):
return self.connection._call(
self.PATCH_RUN.format(app_id, patch_id),
request_json=payload,
verify=False,
method=REQUEST.METHOD.POST,
)

def poll_action_run(self, poll_url, payload=None):
if payload:
return self.connection._call(
Expand Down Expand Up @@ -47,3 +57,13 @@ def action_variables(self, app_id, action_name):
return self.connection._call(
action_var_url, method=REQUEST.METHOD.GET, verify=False
)

def get_recovery_groups(self, app_id, api_filter, length=250, offset=0):
payload = {"filter": api_filter, "length": length, "offset": offset}
recovery_groups_url = self.RECOVERY_GROUPS_LIST.format(app_id)
return self.connection._call(
recovery_groups_url,
request_json=payload,
verify=False,
method=REQUEST.METHOD.POST,
)
18 changes: 18 additions & 0 deletions calm/dsl/api/blueprint.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ def __init__(self, connection):
self.VARIABLE_VALUES_WITH_TRLID = (
self.VARIABLE_VALUES + "?requestId={}&trlId={}"
)
self.PROTECTION_POLICY_LIST = (
self.ITEM + "/app_profile/{}/config_spec/{}/app_protection_policies/list"
)

# TODO https://jira.nutanix.com/browse/CALM-17178
# Blueprint creation timeout is dependent on payload.
Expand Down Expand Up @@ -88,6 +91,21 @@ def brownfield_vms(self, payload):
method=REQUEST.METHOD.POST,
)

def protection_policies(
self, bp_uuid, app_profile_uuid, config_uuid, env_uuid, length=250, offset=0
):
payload = {
"length": 250,
"offset": 0,
"filter": "environment_references=={}".format(env_uuid),
}
return self.connection._call(
self.PROTECTION_POLICY_LIST.format(bp_uuid, app_profile_uuid, config_uuid),
verify=False,
request_json=payload,
method=REQUEST.METHOD.POST,
)

@staticmethod
def _make_blueprint_payload(bp_name, bp_desc, bp_resources, bp_metadata=None):

Expand Down
6 changes: 6 additions & 0 deletions calm/dsl/api/handle.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
from .role import RoleAPI
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 @@ -52,6 +55,9 @@ def _connect(self):
self.directory_service = DirectoryServiceAPI(self.connection)
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")
9 changes: 5 additions & 4 deletions calm/dsl/api/resource.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@
class ResourceAPI:

ROOT = "api/nutanix/v3"
CALM_ROOT = "api/calm/v3.0"

def __init__(self, connection, resource_type):
def __init__(self, connection, resource_type, calm_api=False):
self.connection = connection
self.PREFIX = ResourceAPI.ROOT + "/" + resource_type
self.PREFIX = (self.CALM_ROOT if calm_api else self.ROOT) + "/" + resource_type
self.LIST = self.PREFIX + "/list"
self.ITEM = self.PREFIX + "/{}"

Expand Down Expand Up @@ -120,5 +121,5 @@ def list_all(self, api_limit=250):
return final_list


def get_resource_api(resource_type, connection):
return ResourceAPI(connection, resource_type)
def get_resource_api(resource_type, connection, calm_api=False):
return ResourceAPI(connection, resource_type, calm_api=calm_api)
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")
15 changes: 14 additions & 1 deletion calm/dsl/builtins/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
from .models.provider_spec import provider_spec, read_provider_spec, read_spec
from .models.provider_spec import read_ahv_spec, read_vmw_spec
from .models.readiness_probe import ReadinessProbe, readiness_probe, ReadinessProbeType

from .models.ahv_vm_nic import ahv_vm_nic, AhvVmNic, AhvNicType
from .models.ahv_vm_disk import ahv_vm_disk, AhvVmDisk, AhvDiskType
from .models.ahv_vm_gpu import ahv_vm_gpu, AhvVmGpu, AhvGpuType
Expand All @@ -47,13 +46,24 @@
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
from .models.pod_deployment import PODDeployment, pod_deployment

from .models.config_attrs import AhvUpdateConfigAttrs, PatchDataField
from .models.app_protection import AppProtection
from .models.config_spec import ConfigSpecType
from .models.app_edit import AppEdit
from .models.patch_field import PatchField

from .models.profile import Profile, profile, ProfileType

from .models.config_spec import (
UpdateConfig,
)

from .models.blueprint import Blueprint, blueprint, BlueprintType

from .models.simple_deployment import SimpleDeployment
Expand Down Expand Up @@ -180,4 +190,7 @@
"Endpoint",
"_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
12 changes: 3 additions & 9 deletions calm/dsl/builtins/models/ahv_vm_nic.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,11 @@ def compile(cls):

if not subnet_cache_data:
LOG.debug(
"Ahv Subnet (name = '{}') not found in registered Nutanix PC account (uuid = '{}') "
"in project (name = '{}')".format(
subnet_name, account_uuid, project["name"]
"Ahv Subnet (name = '{}') not found in registered Nutanix PC account (uuid = '{}') ".format(
subnet_name, account_uuid
)
)
LOG.error(
"AHV Subnet {} not found. Please run: calm update cache".format(
subnet_name
)
)
sys.exit(-1)
sys.exit("AHV Subnet {} not found.".format(subnet_name))

subnet_uuid = subnet_cache_data.get("uuid", "")

Expand Down
31 changes: 31 additions & 0 deletions calm/dsl/builtins/models/app_edit.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import sys

from calm.dsl.log import get_logging_handle

from .config_spec import patch_config_create

LOG = get_logging_handle(__name__)


class AppEdit:
def __new__(cls, *args, **kwargs):
raise TypeError("'{}' is not callable".format(cls.__name__))

class UpdateConfig:
def __new__(
cls,
name,
target,
patch_attrs,
):
if target.__self__.substrate.__self__.provider_type != "AHV_VM":
LOG.error(
"Config is not supported for {} provider. Please try again after changing the provider".format(
target.__self__.substrate.__self__.provider_type
)
)
return patch_config_create(
name,
target=target,
patch_attrs=patch_attrs,
)
Loading

0 comments on commit e5d97b4

Please sign in to comment.