def test_parse_weight_string(): is_percent, act_val, err_str = weight.parse_weight_string("10") assert err_str == "" assert not is_percent assert act_val == 10 is_percent, act_val, err_str = weight.parse_weight_string("10.0%") assert err_str == "" assert is_percent assert act_val == 10 is_percent, act_val, err_str = weight.parse_weight_string("10.1 %") assert err_str == "" assert is_percent assert act_val == 10.1 is_percent, act_val, err_str = weight.parse_weight_string(10.0) assert err_str == "weight must be a string." is_percent, act_val, err_str = weight.parse_weight_string("abc.123%") assert "Could not convert abc.123% into a number " in err_str is_percent, act_val, err_str = weight.parse_weight_string("abc.123") assert "Could not convert abc.123 into a number " in err_str is_percent, act_val, err_str = weight.parse_weight_string( "15.6", allow_fraction=False) assert "Weight must be an integer value." in err_str is_percent, act_val, err_str = weight.parse_weight_string( "15.6", allow_fraction=True) assert err_str == "" assert act_val == 15.6 assert not is_percent is_percent, act_val, err_str = weight.parse_weight_string( "15.6%", allow_fraction=False) assert err_str == "" assert is_percent assert act_val == 15.6
def run(StmTemplateMix, TagName, DeviceCount, PortGroupTagList): # MixInfo JSON: # { # "deviceCount": 100, # "components": [ # { # "weight": 10.0, # "devicesPerBlock": 0, # "baseTemplateFile": "IPv4_NoVlan.xml" # "appliedValue": 0, # } # ] # } plLogger = PLLogger.GetLogger("methodology") ctor = CScriptableCreator() obj_list = [] this_cmd = get_this_cmd() if StmTemplateMix: obj_list = CCommandEx.ProcessInputHandleVec("StmTemplateMix", [StmTemplateMix]) if TagName: obj_list = obj_list + \ tag_utils.get_tagged_objects_from_string_names( [TagName]) if len(obj_list) == 0: err_str = "Neither StmTemplateMix nor TagName specified a " + \ "valid StmTemplateMix object." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False if DeviceCount < 1: err_str = "DeviceCount must be at least 1." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Process obj_list to remove duplicates by using # a dictionary indexed on object handle. obj_dict = {obj.GetObjectHandle(): obj for obj in obj_list} for mix in obj_dict.values(): str_mix_info = mix.Get("MixInfo") if str_mix_info == "": err_str = "MixInfo is empty" plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False ''' # Validate the MixInfo # mi_schema = CreateProtoMixCmd_get_mix_info_schema() # res = json_utils.validate_json(str_mix_info, mi_schema) # if res != "": # err_str = res # plLogger.LogError(err_str) # this_cmd.Set("Status", err_str) # return False ''' plLogger.LogDebug("string mix_info: " + str_mix_info) mix_info = json_utils.load_json(str_mix_info) plLogger.LogDebug("mix_info: " + str(mix_info)) if "components" not in mix_info.keys(): err_str = "components is missing in MixInfo for " + \ "StmProtocolMix: " + mix.Get("Name") plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False component_list = mix_info["components"] if len(component_list) == 0: err_str = "Could not find any objects in components in " + \ "the MixInfo in " + mix.Get("Name") plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False template_list = mix.GetObjects("StmTemplateConfig") if len(component_list) != len(template_list): err_str = "Number of component elements in the " + \ "MixInfo for " + mix.Get("Name") + \ " does not match " + \ "number of StmTemplateConfig objects." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Check the DeviceCount if DeviceCount < len(component_list): err_str = "Invalid DeviceCount " + str(DeviceCount) + \ " specified. DeviceCount must be at " + \ " least " + str(len(component_list)) plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Process the weight parameter static_list = [] percent_list = [] use_percent_list = [] for component in component_list: if "weight" not in component.keys(): err_str = "Missing required weight parameter in " + \ "Component in StmProtocolMix: " + \ mix.Get("Name") plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False weight = component["weight"] is_percent, act_val, err_str = weight_ops.parse_weight_string( weight) if err_str != "": plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False if is_percent: static_list.append(0) percent_list.append(act_val) else: static_list.append(act_val) percent_list.append(0) use_percent_list.append(is_percent) total_static_count = sum(static_list) total_percent = sum(percent_list) plLogger.LogDebug("total_static_count: " + str(total_static_count)) plLogger.LogDebug("total_percent: " + str(total_percent)) # Don't allow the aggregate of static counts to exceed the # configured total device count... if total_static_count > DeviceCount: err_str = "Sum total of the static counts (" + \ str(int(total_static_count)) + ") exceeds the total " + \ "configured DeviceCount (" + str(DeviceCount) + ")." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Don't allow the total percent to exceed 100% if total_percent > 100: err_str = "Sum total of the weights defined as percentages (" + \ str(total_percent) + "%) exceeds 100%." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Error if there is no DeviceCount left to divide amongst # the weighted components (NetworkCount == 0 probably not allowed) if total_percent > 0 and total_static_count == DeviceCount: err_str = "Not enough total DeviceCount to distribute devices " + \ "to all components of the mix. The required total static " + \ "device count will use up all of the DeviceCount leaving " + \ "nothing to distribute on the percent-based weighted " + \ "components." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Calculate how much of the DeviceCount is left for the # weighted components... total_percent_count = DeviceCount - total_static_count # Check that each percent-based weighted component can get # at least 1 device if total_percent_count < sum(use_percent_list): err_str = "Not enough total DeviceCount to distribute devices " + \ "to all components of the mix. Once the static counts " + \ "are handled (if any), there aren't enough devices left (" + \ str(total_percent_count) + ") such that each " + \ "percent-based mix component will get at least one device." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Calculate the percent weighted counts from the percents... weighted_counts = weight_ops.allocate_weighted_list( total_percent_count, percent_list, allow_fraction=False) # Apply the counts across each component # Assume apply in creation order to map components to templates i = 0 final_device_count = 0 plLogger.LogInfo("weighted_counts: " + str(weighted_counts)) plLogger.LogInfo("static_list: " + str(static_list)) for component, template in zip(component_list, template_list): act_value = 0.0 if use_percent_list[i]: act_value = weighted_counts[i] else: act_value = static_list[i] # Note what we chose to apply and then apply it... component["appliedValue"] = act_value final_device_count += act_value i = i + 1 if "devicesPerBlock" not in component.keys(): err_str = "Missing required devicesPerBlock parameter in " + \ "Component in StmProtocolMix: " + \ mix.Get("Name") plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False dev_per_block = component["devicesPerBlock"] plLogger.LogDebug("Template: " + template.Get("Name")) plLogger.LogDebug("dev_count: " + str(act_value)) plLogger.LogDebug("devicesPerBlock: " + str(dev_per_block)) last_block_count = 0 if dev_per_block == 0 or dev_per_block > act_value: # All devices into one block block_dev_count = act_value copies_per_parent = 1 else: # (Greedily) Fill device block with number of devices # specified by devicesPerBlock. Last block will have # remainder of devices that does not fill a complete block. block_dev_count = dev_per_block copies_per_parent = int(act_value // dev_per_block) last_block_count = int(act_value % dev_per_block) if last_block_count > 0: copies_per_parent += 1 plLogger.LogDebug("block_dev_count: " + str(block_dev_count)) plLogger.LogDebug("copies_per_parent: " + str(copies_per_parent)) plLogger.LogDebug("last_block_count: " + str(last_block_count)) # Call ExpandTemplateConfigCommand cmd = ctor.CreateCommand(PKG + ".ExpandTemplateCommand") cmd.SetCollection("StmTemplateConfigList", [template.GetObjectHandle()]) cmd.Set("CopiesPerParent", copies_per_parent) cmd.SetCollection("TargetTagList", PortGroupTagList) cmd.Execute() cmd.MarkDelete() emul_dev_list = template.GetObjects("emulateddevice", RelationType("GeneratedObject")) for emul_dev in emul_dev_list: # Last Block has remainder AND last emulateddevice in list if (last_block_count > 0) and (emul_dev == emul_dev_list[-1]): emul_dev.Set("DeviceCount", last_block_count) else: emul_dev.Set("DeviceCount", block_dev_count) mix_info["deviceCount"] = final_device_count # Write the MixInfo back to the StmProtocolMix plLogger.LogDebug("dumping back into MixInfo: " + json.dumps(mix_info)) mix.Set("MixInfo", json.dumps(mix_info)) return True
def run(RouteMixList, RouteMixTagList, RouteCount): plLogger = PLLogger.GetLogger("methodology") obj_list = [] this_cmd = get_this_cmd() if RouteMixList: obj_list = CCommandEx.ProcessInputHandleVec("StmTemplateMix", RouteMixList) if RouteMixTagList: obj_list = obj_list + \ tag_utils.get_tagged_objects_from_string_names( RouteMixTagList) if len(obj_list) == 0: err_str = "Neither RouteMixList nor RouteMixTagList specified a " + \ "valid StmTemplateMix object." this_cmd.Set("Status", err_str) plLogger.LogError(err_str) return False if RouteCount < 1: err_str = "RouteCount must be at least 1." this_cmd.Set("Status", err_str) plLogger.LogError(err_str) return False obj_dict = {obj.GetObjectHandle(): obj for obj in obj_list} for mix in obj_dict.values(): # Get all of the StmTemplateConfig objects for this mix... templates = mix.GetObjects("StmTemplateConfig") # Get the MixInfo str_mix_info = mix.Get("MixInfo") # Validate the input MixInfo against its schema # res = json_utils.validate_json(str_mix_info, # get_this_cmd().Get("MixInfoJsonSchema")) # if res != "": # this_cmd.Set("Status", res) # plLogger.LogError(res) # return False plLogger.LogInfo("string mix_info: " + str(str_mix_info)) err_str, mix_info = json_utils.load_json(str_mix_info) if err_str != "": plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False plLogger.LogInfo("mix_info: " + str(mix_info)) component_list = mix_info["components"] plLogger.LogInfo("number of components: " + str(len(component_list))) # Check the MixInfo component_list length against the # number of templates if len(templates) != len(component_list): err_str = "There are " + str(len(templates)) + " under the " + \ "StmTemplateMix " + mix.Get("Name") + " (" + \ str(mix.GetObjectHandle()) + ") but " + \ str(len(component_list)) + \ " components in the MixInfo. " + \ "These MUST match." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Record what we will use over the whole mix mix_info["routeCount"] = RouteCount # Process the weight parameter static_list = [] percent_list = [] use_percent_list = [] for component in component_list: weight = component["weight"] is_percent, act_val, err_str = weight_ops.parse_weight_string( weight) if err_str != "": plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False if is_percent: static_list.append(0) percent_list.append(act_val) else: static_list.append(act_val) percent_list.append(0) use_percent_list.append(is_percent) total_static_count = sum(static_list) total_percent = sum(percent_list) plLogger.LogDebug("total_static_count: " + str(total_static_count)) plLogger.LogDebug("total_percent: " + str(total_percent)) # Don't allow the aggregate of static counts to exceed the # configured total route count... if total_static_count > RouteCount: err_str = "Sum total of the static counts (" + \ str(int(total_static_count)) + ") exceeds the total " + \ "configured RouteCount (" + str(RouteCount) + ")." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Don't allow the total percent to exceed 100% if total_percent > 100: err_str = "Sum total of the weights defined as percentages (" + \ str(total_percent) + "%) exceeds 100%." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Error if there is no RouteCount left to divide amongst # the weighted components (NetworkCount == 0 probably not allowed) if total_percent > 0 and total_static_count == RouteCount: err_str = "Not enough total RouteCount to distribute routes " + \ "to all components of the mix. The required total static " + \ "route count will use up all of the RouteCount leaving " + \ "nothing to distribute on the percent-based weighted " + \ "components." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Calculate how much of the RouteCount is left for the # weighted components... total_percent_count = RouteCount - total_static_count # Check that each percent-based weighted component can get # at least 1 route if total_percent_count < sum(use_percent_list): err_str = "Not enough total RouteCount to distribute routes " + \ "to all components of the mix. Once the static counts " + \ "are handled (if any), there aren't enough routes left (" + \ str(total_percent_count) + ") such that each " + \ "percent-based mix component will get at least one route." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Calculate the percent weighted counts from the percents... weighted_counts = weight_ops.allocate_weighted_list( total_percent_count, percent_list, allow_fraction=False) # Apply the counts across each component # Assume apply in creation order to map components to templates i = 0 plLogger.LogInfo("weighted_counts: " + str(weighted_counts)) plLogger.LogInfo("static_list: " + str(static_list)) for component, template in zip(component_list, templates): act_value = 0.0 if use_percent_list[i]: act_value = weighted_counts[i] else: act_value = static_list[i] # Note what we chose to apply and then apply it... component["appliedValue"] = act_value # Update the NetworkBlocks err_str = update_generated_objects(template, act_value) if err_str != "": plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False i = i + 1 # Update the mix with our changes... mix.Set("MixInfo", json.dumps(mix_info)) return True
def run(StmTrafficMix, TrafficMixTagName, Load, LoadUnit): plLogger = PLLogger.GetLogger('AllocateTrafficMixLoad2Command') obj_list = [] this_cmd = get_this_cmd() if StmTrafficMix: obj_list = CCommandEx.ProcessInputHandleVec('StmTrafficMix', [StmTrafficMix]) if TrafficMixTagName: obj_list = obj_list + tag_utils.get_tagged_objects_from_string_names([TrafficMixTagName]) if len(obj_list) == 0: err_str = "Neither StmTrafficMix nor TrafficMixTagName " + \ "specified a valid StmTrafficMix Object" plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False obj_dict = {obj.GetObjectHandle(): obj for obj in obj_list} for mix in obj_dict.values(): mix_info_s = mix.Get('MixInfo') # Validate the input MixInfo against its schema res = json_utils.validate_json(mix_info_s, this_cmd.Get('MixInfoJsonSchema')) if res != '': plLogger.LogError(res) this_cmd.Set("Status", res) return False err_str, mix_info = json_utils.load_json(mix_info_s) if err_str != "": plLoger.LogError(err_str) component_list = mix_info['components'] # Record what we will use MIX wide... mix_info['load'] = Load mix_info['loadUnits'] = LoadUnit # Aggregate the individual streamblock information... static_list = [] percent_list = [] use_percent_list = [] for component in component_list: weight = component["weight"] is_percent, act_val, err_str = \ weight_ops.parse_weight_string(weight) if err_str != "": err_str = "Total static loads exceed the mix load." plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False if is_percent: static_list.append(0) percent_list.append(act_val) else: static_list.append(act_val) percent_list.append(0) use_percent_list.append(is_percent) total_static_load = sum(static_list) total_percent = sum(percent_list) # Don't allow the aggregate of static loads to exceed the MIX wide load... if total_static_load > Load: err_str = 'Total static load ({}) exceeds the ' \ 'configured mix load ({}).'.format(total_static_load, Load) plLogger.LogError(err_str) this_cmd.Set('Status', err_str) return False # Don't allow an invalid aggregate of streamblock weights... if total_percent > 100: err_str = "Total weights ({}) exceed 100%.".format(total_percent) plLogger.LogError(err_str) this_cmd.Set("Status", err_str) return False # Warn if there is no MIX wide load left to divide amongst the # weighted streamblocks... if total_percent > 0 and total_static_load == Load: err_str = 'No mix load available for weight distribution' plLogger.LogWarn(err_str) this_cmd.Set("Status", err_str) # Fractions are not supported only for these settings allow = (LoadUnit not in ['FRAMES_PER_SECOND', 'INTER_BURST_GAP']) # Calculate how much of the load is left for the weighted streamblocks... total_weighted_load = Load - total_static_load # Calculate the weighted loads from the weights... weighted_loads = weight_ops.allocate_weighted_list(total_weighted_load, percent_list, allow_fraction=allow) # Get all of the StmTemplateConfig objects for this MIX... templates = mix.GetObjects('StmTemplateConfig') # Apply the loads across each streamblock according to their individual preferences... # Yes, we are ASSUMING creation order to map components to templates... for component, template, weight_load in zip(component_list, templates, weighted_loads): is_percent, act_val, err_str = \ weight_ops.parse_weight_string(component['weight']) if not is_percent: applied_load = act_val else: applied_load = weight_load # Note what we chose to apply and then apply it... component['appliedValue'] = applied_load allocate_weighted_load(applied_load, template, LoadUnit) config_generator(template, LoadUnit) # Update the MIX with our changes... mix.Set('MixInfo', json.dumps(mix_info)) return True