Skip to content

Commit

Permalink
Merge pull request #89 from kairu-ms/feature-support-identity-object
Browse files Browse the repository at this point in the history
Feature support userAssignedIdentities object
  • Loading branch information
kairu-ms authored Jul 20, 2022
2 parents f0ab1b1 + 43beff4 commit bd39cf6
Show file tree
Hide file tree
Showing 9 changed files with 78 additions and 44 deletions.
24 changes: 11 additions & 13 deletions src/aaz_dev/cli/controller/az_arg_group_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -238,9 +238,6 @@ def render_arg(arg, cmd_ctx, arg_group=None):
if arg.default:
arg_kwargs["default"] = arg.default.value

if arg.blank:
arg_kwargs["blank"] = arg.blank.value

arg_type, arg_kwargs, cls_builder_name = render_arg_base(arg, cmd_ctx, arg_kwargs)

return arg_type, arg_kwargs, cls_builder_name
Expand All @@ -260,6 +257,9 @@ def render_arg_base(arg, cmd_ctx, arg_kwargs=None):
if arg.nullable:
arg_kwargs['nullable'] = True

if arg.blank:
arg_kwargs["blank"] = arg.blank.value

if isinstance(arg, CMDStringArgBase):
arg_type = "AAZStrArg"
enum = parse_arg_enum(arg.enum)
Expand Down Expand Up @@ -395,34 +395,32 @@ def render_arg_base(arg, cmd_ctx, arg_kwargs=None):
# raise NotImplementedError()

elif isinstance(arg, CMDObjectArgBase):
if arg.args:
arg_type = "AAZObjectArg"
if arg.additional_props:
raise NotImplementedError()
if arg.additional_props:
arg_type = "AAZDictArg"
if arg.fmt is not None:
assert isinstance(arg.fmt, CMDObjectFormat)
arg_kwargs['fmt'] = fmt = {
"cls": "AAZObjectArgFormat",
"cls": "AAZDictArgFormat",
"kwargs": {}
}
if arg.fmt.max_properties is not None:
fmt['kwargs']['max_properties'] = arg.fmt.max_properties
if arg.fmt.min_properties is not None:
fmt['kwargs']['min_properties'] = arg.fmt.min_properties
elif arg.additional_props:
arg_type = "AAZDictArg"
else:
arg_type = "AAZObjectArg"
if arg.additional_props:
raise NotImplementedError()
if arg.fmt is not None:
assert isinstance(arg.fmt, CMDObjectFormat)
arg_kwargs['fmt'] = fmt = {
"cls": "AAZDictArgFormat",
"cls": "AAZObjectArgFormat",
"kwargs": {}
}
if arg.fmt.max_properties is not None:
fmt['kwargs']['max_properties'] = arg.fmt.max_properties
if arg.fmt.min_properties is not None:
fmt['kwargs']['min_properties'] = arg.fmt.min_properties
else:
raise NotImplementedError()

elif isinstance(arg, CMDArrayArgBase):
arg_type = "AAZListArg"
Expand Down
29 changes: 15 additions & 14 deletions src/aaz_dev/cli/controller/az_operation_generator.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def __init__(self, name, cmd_ctx, operation):
self.success_responses.append(AzHttpResponseGenerator(self._cmd_ctx, response))
else:
if not isinstance(response.body, CMDHttpResponseJsonBody):
raise NotImplementedError()
raise exceptions.InvalidAPIUsage(
f"Invalid error response body: Only support json, current is '{type(response.body)}'")
schema = response.body.json.schema
if not isinstance(schema, CMDClsSchemaBase):
raise NotImplementedError()
Expand Down Expand Up @@ -490,24 +491,27 @@ def _iter_request_scopes_by_schema_base(schema, name, scope_define, arg_key, cmd
s_name = s.name
s_typ, s_typ_kwargs, cls_builder_name = render_schema(s, cmd_ctx.update_clses, s_name)
if s.arg:
# current schema linked with argument
s_arg_key, hide = cmd_ctx.get_argument(s.arg)
if hide:
continue
else:
# current schema not linked with argument, then use current arg_key
s_arg_key = arg_key

# handle enum item attached with argument
has_enum_argument = False
if hasattr(s, "enum") and isinstance(s.enum, CMDSchemaEnum):
for item in s.enum.items:
if item.arg:
# enum item linked with argument
item_arg_key, hide = cmd_ctx.get_argument(item.arg)
if hide:
continue
has_enum_argument = True
r_key = item_arg_key.replace(arg_key, '')
if not r_key:
r_key = '.'
r_key = '.' # which means if the arg exist, fill it
is_const = True
const_value = item.value
rendered_schemas.append(
Expand All @@ -517,7 +521,7 @@ def _iter_request_scopes_by_schema_base(schema, name, scope_define, arg_key, cmd
if not has_enum_argument:
r_key = s_arg_key.replace(arg_key, '')
if not r_key:
r_key = '.' if s.required else None
r_key = '.' if s.required else None # which means if the parent exist, fill it

is_const = False
const_value = None
Expand All @@ -533,15 +537,12 @@ def _iter_request_scopes_by_schema_base(schema, name, scope_define, arg_key, cmd
search_schemas[s_name] = (s, s_arg_key)

elif schema.additional_props:
assert schema.additional_props.item is not None
assert schema.additional_props.item is not None # make sure additional props schema defined its element schema
s = schema.additional_props.item
s_name = '{}'
s_typ, s_typ_kwargs, cls_builder_name = render_schema_base(s, cmd_ctx.update_clses)
s_arg_key = arg_key + '{}'
if not isinstance(s, (CMDObjectSchemaBase, CMDArraySchemaBase)):
r_key = '.'
else:
r_key = None
r_key = '.' # if element exist, always fill it

is_const = False
const_value = None
Expand All @@ -560,17 +561,20 @@ def _iter_request_scopes_by_schema_base(schema, name, scope_define, arg_key, cmd
s_name = s.name
s_typ, s_typ_kwargs, cls_builder_name = render_schema(s, cmd_ctx.update_clses, s_name)
if s.arg:
# current schema linked with argument
s_arg_key, hide = cmd_ctx.get_argument(s.arg)
if hide:
continue
else:
# current schema not linked with argument, then use current arg_key
s_arg_key = arg_key

# handle enum item attached with argument
has_enum_argument = False
if hasattr(s, "enum") and isinstance(s.enum, CMDSchemaEnum):
for item in s.enum.items:
if item.arg:
# enum item linked with argument
item_arg_key, hide = cmd_ctx.get_argument(item.arg)
if hide:
continue
Expand Down Expand Up @@ -600,19 +604,16 @@ def _iter_request_scopes_by_schema_base(schema, name, scope_define, arg_key, cmd
)
if not cls_builder_name and not is_const \
and isinstance(s, (CMDObjectSchemaBase, CMDArraySchemaBase)):
# step into object and array schemas
search_schemas[s_name] = (s, s_arg_key)

elif isinstance(schema, CMDArraySchemaBase):
assert schema.item is not None
assert schema.item is not None # make sure array schema defined its element schema
s = schema.item
s_name = "[]"
s_typ, s_typ_kwargs, cls_builder_name = render_schema_base(s, cmd_ctx.update_clses)
s_arg_key = arg_key + '[]'

if not isinstance(s, (CMDObjectSchemaBase, CMDArraySchemaBase)):
r_key = '.'
else:
r_key = None
r_key = '.' # if element exist, always fill it

is_const = False
const_value = None
Expand Down
1 change: 1 addition & 0 deletions src/aaz_dev/command/model/configuration/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
CMDFloat32SchemaBase, CMDFloat32Schema, \
CMDFloat64SchemaBase, CMDFloat64Schema, \
CMDObjectSchemaDiscriminator, CMDObjectSchemaAdditionalProperties, CMDObjectSchemaBase, CMDObjectSchema, \
CMDIdentityObjectSchemaBase, CMDIdentityObjectSchema, \
CMDArraySchemaBase, CMDArraySchema
from ._utils import CMDDiffLevelEnum, DEFAULT_CONFIRMATION_PROMPT
from ._xml import XMLSerializer
9 changes: 7 additions & 2 deletions src/aaz_dev/command/model/configuration/_arg.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ class CMDArgBase(Model):

nullable = CMDBooleanField() # whether can pass null value or not.

blank = ModelType(CMDArgBlank) # blank value is used when argument don't have any value

class Options:
serialize_when_none = False

Expand Down Expand Up @@ -130,6 +132,7 @@ def _claim_polymorphic(cls, data):
def build_arg_base(cls, builder):
arg_base = cls()
arg_base.nullable = builder.get_nullable()
arg_base.blank = builder.get_blank()
return arg_base

def _reformat_base(self, **kwargs):
Expand Down Expand Up @@ -196,7 +199,6 @@ class CMDArg(CMDArgBase):
# properties as nodes
help = ModelType(CMDArgumentHelp)
default = ModelType(CMDArgDefault) # default value is used when argument isn't in command
blank = ModelType(CMDArgBlank) # blank value is used when argument don't have any value

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Expand All @@ -222,7 +224,6 @@ def build_arg(cls, builder):

arg.required = builder.get_required()
arg.default = builder.get_default()
arg.blank = builder.get_blank()

arg.hide = builder.get_hide()
return arg
Expand Down Expand Up @@ -607,6 +608,10 @@ def build_arg_base(cls, builder):
raise
arg.args = builder.get_sub_args()
arg.additional_props = builder.get_additional_props()
if not arg.args and not arg.additional_props:
# when object arg don't have args or additional_props, set its blank value as empty dict
arg.blank = CMDArgBlank()
arg.blank.value = {}
arg.cls = builder.get_cls()
return arg

Expand Down
2 changes: 1 addition & 1 deletion src/aaz_dev/command/model/configuration/_format.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
from schematics.models import Model
from schematics.types import StringType, FloatType, IntType
from ._fields import CMDRegularExpressionField, CMDBooleanField, CMDVariantField
from ._fields import CMDRegularExpressionField, CMDBooleanField
from ._utils import CMDDiffLevelEnum


Expand Down
12 changes: 12 additions & 0 deletions src/aaz_dev/command/model/configuration/_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -875,6 +875,18 @@ def _diff(self, old, level, diff):
return diff


class CMDIdentityObjectSchemaBase(CMDObjectSchemaBase):
""" And identity object which contains 'userAssignedIdentities' property and 'type' property
with "SystemAssigned", "UserAssigned", "SystemAssigned, UserAssigned" and "None" enum values.
"""
TYPE_VALUE = "IdentityObject"
ARG_TYPE = CMDObjectArgBase


class CMDIdentityObjectSchema(CMDIdentityObjectSchemaBase, CMDObjectSchema):
ARG_TYPE = CMDObjectArg


# array
class CMDArraySchemaBase(CMDSchemaBase):
TYPE_VALUE = "array"
Expand Down
4 changes: 2 additions & 2 deletions src/aaz_dev/swagger/model/schema/cmd_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ def build_schema(self, schema):
else:
raise exceptions.InvalidSwaggerValueError(
f"format is not supported", key=getattr(schema, "traces", None), value=[schema_type, schema.format])
elif schema_type == "object" or getattr(schema, "properties", None) or getattr(schema, "additional_properties",
None):
elif schema_type == "object" or getattr(schema, "properties", None) or \
getattr(schema, "additional_properties", None):
if schema.format is None:
if self.in_base:
model = CMDObjectSchemaBase()
Expand Down
18 changes: 15 additions & 3 deletions src/aaz_dev/swagger/model/schema/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
CMDStringSchema, CMDResourceIdSchema, CMDResourceIdFormat, \
CMDResourceLocationSchema, \
CMDObjectSchemaBase, CMDObjectSchemaDiscriminator, CMDObjectSchemaAdditionalProperties, \
CMDArraySchemaBase, CMDObjectSchema
CMDArraySchemaBase, CMDObjectSchema, CMDIdentityObjectSchema, CMDIdentityObjectSchemaBase
from command.model.configuration import CMDSchemaEnum, CMDSchemaEnumItem, CMDSchema, CMDSchemaBase
from swagger.utils import exceptions
from .external_documentation import ExternalDocumentation
Expand Down Expand Up @@ -436,7 +436,7 @@ def to_cmd(self, builder, **kwargs):
# because required property will not be included in a cls definition,
# so it's fine to update it in parent level when prop_dict[name] is a cls definition.
prop_dict[name].required = True
# when a property is required, it's frozen status must be consist with the defined schema.
# when a property is required, it's frozen status must be consisted with the defined schema.
# This can help to for empty object schema.
prop_dict[name].frozen = builder.frozen

Expand Down Expand Up @@ -521,6 +521,15 @@ def to_cmd(self, builder, **kwargs):
prop_dict['location'] = CMDResourceLocationSchema(raw_data=raw_data)

if prop_dict:
if "userAssignedIdentities" in prop_dict and "type" in prop_dict:
if isinstance(model, CMDObjectSchema):
# Transfer to IdentityObjectSchema
model = CMDIdentityObjectSchema(model.to_native())
elif isinstance(model, CMDObjectSchemaBase):
# Transfer to IdentityObjectSchemaBase
model = CMDIdentityObjectSchemaBase(model.to_native())
else:
raise NotImplementedError()
model.props = []
for prop in prop_dict.values():
model.props.append(prop)
Expand All @@ -533,7 +542,9 @@ def to_cmd(self, builder, **kwargs):
assert isinstance(v, CMDSchemaBase)
model.additional_props = CMDObjectSchemaAdditionalProperties()
model.additional_props.item = v
model.additional_props.frozen = v.frozen
# item is required, it's frozen status must be consisted with the defined schema.
# This can help to for empty object.
model.additional_props.item.frozen = builder.frozen
# Note: not support additional_properties without schema define
# elif self.additional_properties is True:
# model.additional_props = CMDObjectSchemaAdditionalProperties()
Expand Down Expand Up @@ -568,6 +579,7 @@ def to_cmd(self, builder, **kwargs):
# Note: model will always frozen when object without any props, additional_props or discriminators,
# If this property is required by parent schema, it will be updated in parent.
model.frozen = need_frozen

else:
if self.all_of is not None:
# inherent from allOf
Expand Down
23 changes: 14 additions & 9 deletions src/web/src/views/workspace/WSEditorCommandArgumentsContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1145,13 +1145,16 @@ function ArgumentPropsReviewer(props: {
onSelectSubArg: (subArgVar: string) => void,
}) {
const groupArgs: { [name: string]: CMDArg[] } = {};
props.args.forEach((arg) => {
const groupName: string = arg.group.length > 0 ? arg.group : "";
if (!(groupName in groupArgs)) {
groupArgs[groupName] = []
}
groupArgs[groupName].push(arg)
})
if (props.args !== undefined) {
props.args.forEach((arg) => {
const groupName: string = arg.group.length > 0 ? arg.group : "";
if (!(groupName in groupArgs)) {
groupArgs[groupName] = []
}
groupArgs[groupName].push(arg)
})
}

const groups: ArgGroup[] = []

for (const groupName in groupArgs) {
Expand Down Expand Up @@ -1265,6 +1268,10 @@ function ArgumentPropsReviewer(props: {
</Box>)
}

if (groups.length == 0) {
return (<></>)
}

return (<React.Fragment>
<Box sx={{
p: 2,
Expand Down Expand Up @@ -1560,8 +1567,6 @@ function decodeArgBase(response: any): { argBase: CMDArgBase, clsDefineMap: ClsA
type: argBaseType,
item: itemArgBaseParse.argBase
}
} else {
throw Error("Invalid object arguments, neither args nor additionalProps exist")
}

if (response.cls) {
Expand Down

0 comments on commit bd39cf6

Please sign in to comment.