Skip to content
This repository has been archived by the owner on Apr 26, 2024. It is now read-only.

Commit

Permalink
Merge branch 'main' into fr_template/rm/cisco_vpn
Browse files Browse the repository at this point in the history
  • Loading branch information
kagrski authored Sep 25, 2023
2 parents 9f79ccd + b3ca5ce commit 658bb4d
Show file tree
Hide file tree
Showing 45 changed files with 5,830 additions and 1,007 deletions.
2 changes: 1 addition & 1 deletion vmngclient/api/admin_tech_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ def generate(
timeout=request_timeout,
)
except HTTPError as http_error:
response = http_error.response
response = http_error.response # type: ignore
if response.status_code == 200:
return response.json()["fileName"]
if response.status_code == 400 and create_admin_tech_error_msgs in response.json().get("error", {}).get(
Expand Down
52 changes: 25 additions & 27 deletions vmngclient/api/template_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from vmngclient.api.templates.models.cisco_ntp_model import CiscoNTPModel
from vmngclient.api.templates.models.cisco_omp_model import CiscoOMPModel
from vmngclient.api.templates.models.cisco_ospf import CiscoOSPFModel
from vmngclient.api.templates.models.cisco_ospfv3 import CiscoOspfv3Model
from vmngclient.api.templates.models.cisco_secure_internet_gateway import CiscoSecureInternetGatewayModel
from vmngclient.api.templates.models.cisco_snmp_model import CiscoSNMPModel
from vmngclient.api.templates.models.cisco_system import CiscoSystemModel
Expand Down Expand Up @@ -94,7 +95,10 @@ def get(self, template):
raise NotImplementedError()

def _get_feature_templates(
self, summary: bool = True, offset: Optional[int] = None, limit: Optional[int] = None
self,
summary: bool = True,
offset: Optional[int] = None,
limit: Optional[int] = None,
) -> DataSequence[FeatureTemplateInfo]:
"""In a multitenant vManage system, this API is only available in the Provider view."""
endpoint = "/dataservice/template/feature"
Expand Down Expand Up @@ -139,7 +143,11 @@ def _attach_feature(self, name: str, device: Device, **kwargs):
def get_device_specific_variables(name: str):
endpoint = "/dataservice/template/device/config/exportcsv"
template_id = self.get(DeviceTemplate).filter(name=name).single_or_default().id
body = {"templateId": template_id, "isEdited": False, "isMasterEdited": False}
body = {
"templateId": template_id,
"isEdited": False,
"isMasterEdited": False,
}

values = self.session.post(endpoint, json=body).json()["header"]["columns"]
return [DeviceSpecificValue(**value) for value in values]
Expand Down Expand Up @@ -454,7 +462,8 @@ def get_general_template_info(
return _template

def parse_general_template(
general_template: GeneralTemplate, fr_templates: DataSequence[FeatureTemplateInfo]
general_template: GeneralTemplate,
fr_templates: DataSequence[FeatureTemplateInfo],
) -> GeneralTemplate:
if general_template.subTemplates:
general_template.subTemplates = [
Expand Down Expand Up @@ -515,6 +524,7 @@ def is_created_by_generator(self, template: FeatureTemplate) -> bool:
CiscoOSPFModel,
CliTemplateModel,
CiscoSecureInternetGatewayModel,
CiscoOspfv3Model,
)

return isinstance(template, ported_templates)
Expand Down Expand Up @@ -559,32 +569,15 @@ def generate_feature_template_payload(
if field.key in template.device_specific_variables:
value = template.device_specific_variables[field.key]
else:
# Iterate through every possible field, maybe refactor(?)
# Use data_path instead. data_path as tuple
# next(field_value.field_info.extra.get("vmanage_key") == field.key, template.__fields__.values())
for field_name, field_value in template.__fields__.items():
if "vmanage_key" in field_value.field_info.extra: # type: ignore
vmanage_key = field_value.field_info.extra.get("vmanage_key") # type: ignore
if vmanage_key != field.key:
break

value = template.dict(by_alias=True).get(field_name, None)
field_value.field_info.extra.pop("vmanage_key") # type: ignore
if field.dataPath == field_value.field_info.extra.get("data_path", []) and ( # type: ignore
field.key == field_value.alias
or field.key == field_value.field_info.extra.get("vmanage_key") # type: ignore
):
value = getattr(template, field_name)
break
if value is None:
value = template.dict(by_alias=True).get(field.key, None)

# TODO remove workaround, add specific object
# types like Ignore, Constant, None etc so generator will now
# which object to ommit while generating payload
if template.type == "cisco_vpn_interface" and value is None:
continue

if template.type == "cisco_ospf" and value is None:
continue

if isinstance(value, bool):
value = str(value).lower() # type: ignore
continue

# Merge dictionaries

Expand Down Expand Up @@ -685,7 +678,12 @@ def edit_before_push(self, name: str, device: Device) -> bool:
error_details = json.loads(error.response.text)
logger.error(f"Error in config: {error_details['error']['details']}.")
return False
payload = {"templateId": template_id, "deviceIds": [device.uuid], "isEdited": True, "isMasterEdited": True}
payload = {
"templateId": template_id,
"deviceIds": [device.uuid],
"isEdited": True,
"isMasterEdited": True,
}
endpoint = "/dataservice/template/device/config/input/"
logger.info(f"Editing template: {name} of device: {device.hostname}.")
response = self.session.post(url=endpoint, json=payload).json()
Expand Down
4 changes: 3 additions & 1 deletion vmngclient/api/templates/feature_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,10 +55,12 @@ def remove_device_variables(cls, values):
values["device_specific_variables"] = {}
to_delete = {}

# TODO: Add support for nested models with DeviceVariable
for key, value in values.items():
if isinstance(value, DeviceVariable):
to_delete[key] = value
values["device_specific_variables"][cls.__fields__[key].alias] = DeviceVariable(name=value.name)
field_key = cls.__fields__[key].field_info.extra.get("vmanage_key", cls.__fields__[key].alias)
values["device_specific_variables"][field_key] = DeviceVariable(name=value.name)

for var in to_delete:
if var in values:
Expand Down
37 changes: 24 additions & 13 deletions vmngclient/api/templates/feature_template_field.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
from typing import Any, Dict, List, Optional

from pydantic import BaseModel, Field, validator
from pydantic.fields import ModelField # type: ignore

from vmngclient.api.templates.device_variable import DeviceVariable
from vmngclient.api.templates.feature_template import FeatureTemplate


class FeatureTemplateOptionType(str, Enum):
Expand Down Expand Up @@ -91,15 +93,22 @@ def payload_scheme(self, value: Any = None, help=None, current_path=None) -> dic

output["vipObjectType"] = self.objectType.value

def nest_value_in_output(value: Any) -> dict:
pointer = rel_output
for path in self.dataPath:
pointer = pointer[path]
pointer[self.key] = value
return rel_output

if isinstance(value, DeviceVariable):
vip_variable = VipVariable(
vipValue="",
vipType=FeatureTemplateOptionType.VARIABLE_NAME,
vipObjectType=self.objectType,
vipVariableName=value.name,
)
return nest_value_in_output(vip_variable.dict(by_alias=True, exclude_none=True))

return {self.key: vip_variable.dict(by_alias=True, exclude_none=True)}
else:
if value:
output["vipType"] = FeatureTemplateOptionType.CONSTANT.value
Expand All @@ -111,19 +120,27 @@ def payload_scheme(self, value: Any = None, help=None, current_path=None) -> dic
for child in self.children: # Child in schema
if current_path is None:
current_path = []
child_payload.update(
child.payload_scheme(
obj[child.key], help=output, current_path=self.dataPath + [self.key]
obj: FeatureTemplate # type: ignore
model_field: ModelField = next(
filter(
lambda f: f.field_info.extra.get("data_path", []) == child.dataPath
and (f.alias == child.key or f.field_info.extra.get("vmanage_key") == child.key),
obj.__fields__.values(),
)
)
obj_value = getattr(obj, model_field.name)
child_payload.update(
child.payload_scheme(obj_value, help=output, current_path=self.dataPath + [self.key])
)
children_output.append(child_payload)
output["vipValue"] = children_output
else:
output["vipValue"] = value
else:
if "default" in self.dataType:
output["vipValue"] = self.dataType["default"] if value is None else value
output["vipType"] = self.defaultOption.value
return {}
# output["vipValue"] = self.dataType["default"] if value is None else value
# output["vipType"] = self.defaultOption.value
else:
output["vipValue"] = []
output["vipType"] = FeatureTemplateOptionType.IGNORE.value
Expand All @@ -135,10 +152,4 @@ def payload_scheme(self, value: Any = None, help=None, current_path=None) -> dic
if self.primaryKeys:
output["vipPrimaryKey"] = self.primaryKeys

pointer = rel_output

for path in self.dataPath:
pointer = pointer[path]

pointer[self.key] = output
return rel_output
return nest_value_in_output(output)
30 changes: 15 additions & 15 deletions vmngclient/api/templates/models/cisco_aaa_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,32 +12,32 @@ class User(BaseModel):
password: str
secret: str
privilege: Optional[str]
pubkey_chain: List[str] = Field(default=[], alias="pubkey-chain")
pubkey_chain: List[str] = Field(default=[], vmanage_key="pubkey-chain")


class RadiusServer(BaseModel):
class Config:
allow_population_by_field_name = True

address: str
auth_port: int = Field(alias="auth-port", default=1812)
acct_port: int = Field(alias="acct-port", default=1813)
auth_port: int = Field(vmanage_key="auth-port", default=1812)
acct_port: int = Field(vmanage_key="acct-port", default=1813)
timeout: int = Field(default=5)
retransmit: int = 3
key: str
secret_key: Optional[str] = Field(alias="secret-key", default=None)
key_enum: Optional[str] = Field(alias="key-enum", default=None)
key_type: Optional[str] = Field(alias="key-type", default=None)
secret_key: Optional[str] = Field(vmanage_key="secret-key", default=None)
key_enum: Optional[str] = Field(vmanage_key="key-enum", default=None)
key_type: Optional[str] = Field(vmanage_key="key-type", default=None)


class RadiusGroup(BaseModel):
class Config:
arbitrary_types_allowed = True
allow_population_by_field_name = True

group_name: str = Field(alias="group-name")
group_name: str = Field(vmanage_key="group-name")
vpn: Optional[int]
source_interface: Optional[str] = Field(alias="source-interface")
source_interface: Optional[str] = Field(vmanage_key="source-interface")
server: List[RadiusServer] = []


Expand All @@ -55,17 +55,17 @@ class Config:
port: int = 49
timeout: int = Field(default=5)
key: str
secret_key: Optional[str] = Field(alias="secret-key", default=None)
key_enum: Optional[str] = Field(alias="key-enum", default=None)
secret_key: Optional[str] = Field(vmanage_key="secret-key", default=None)
key_enum: Optional[str] = Field(vmanage_key="key-enum", default=None)


class TacacsGroup(BaseModel):
class Config:
allow_population_by_field_name = True

group_name: str = Field(alias="group-name")
group_name: str = Field(vmanage_key="group-name")
vpn: int = 0
source_interface: Optional[str] = Field(alias="source-interface", default=None)
source_interface: Optional[str] = Field(vmanage_key="source-interface", default=None)
server: List[TacacsServer] = []


Expand All @@ -75,13 +75,13 @@ class Config:
allow_population_by_field_name = True

user: List[User] = []
authentication_group: bool = Field(alias="authentication_group", default=False)
authentication_group: bool = Field(vmanage_key="authentication_group", default=False)
accounting_group: bool = True
radius: List[RadiusGroup] = []
domain_stripping: Optional[DomainStripping] = Field(alias="domain-stripping", default=None)
domain_stripping: Optional[DomainStripping] = Field(vmanage_key="domain-stripping", default=None)
port: int = 1700
tacacs: List[TacacsGroup] = []
server_auth_order: str = Field(alias="server-auth-order", default="local")
server_auth_order: str = Field(vmanage_key="server-auth-order", default="local")

payload_path: ClassVar[Path] = Path(__file__).parent / "DEPRECATED"
type: ClassVar[str] = "cedge_aaa"
12 changes: 7 additions & 5 deletions vmngclient/api/templates/models/cisco_bfd_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,9 @@ class ColorType(str, Enum):

class Color(ConvertBoolToStringModel):
color: ColorType
hello_interval: Optional[int] = Field(DEFAULT_BFD_HELLO_INTERVAL, alias="hello-interval")
hello_interval: Optional[int] = Field(DEFAULT_BFD_HELLO_INTERVAL, vmanage_key="hello-interval")
multiplier: Optional[int] = DEFAULT_BFD_COLOR_MULTIPLIER
pmtu_discovery: Optional[bool] = Field(True, alias="pmtu-discovery")
pmtu_discovery: Optional[bool] = Field(True, vmanage_key="pmtu-discovery")
dscp: Optional[int] = DEFAULT_BFD_DSCP

class Config:
Expand All @@ -55,9 +55,11 @@ class Config:
arbitrary_types_allowed = True
allow_population_by_field_name = True

multiplier: Optional[int] = DEFAULT_BFD_MULTIPLIER
poll_interval: Optional[int] = Field(DEFAULT_BFD_POLL_INTERVAL, alias="poll-interval")
default_dscp: Optional[int] = Field(DEFAULT_BFD_DSCP, alias="default-dscp")
multiplier: Optional[int] = Field(DEFAULT_BFD_MULTIPLIER, data_path=["app-route"])
poll_interval: Optional[int] = Field(
DEFAULT_BFD_POLL_INTERVAL, vmanage_key="poll-interval", data_path=["app-route"]
)
default_dscp: Optional[int] = Field(DEFAULT_BFD_DSCP, vmanage_key="default-dscp")
color: Optional[List[Color]]

payload_path: ClassVar[Path] = Path(__file__).parent / "DEPRECATED"
Expand Down
Loading

0 comments on commit 658bb4d

Please sign in to comment.