_requirements.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. import lib.test_const as consts
  2. import re
  3. import lib._metric_resolvers as mr
  4. CANON_SB_VAULT_REGEX = re.compile(r"\w+=(value|file):[-\w]+:\w+")
  5. CANON_YAV_REGEX = re.compile(r"\w+=(value|file):sec-[a-z0-9]+:\w+")
  6. VALID_DNS_REQUIREMENTS = ("default", "local", "dns64")
  7. VALID_NETWORK_REQUIREMENTS = ("full", "restricted")
  8. def check_cpu(suite_cpu_requirements, test_size, is_kvm=False):
  9. min_cpu_requirements = consts.TestRequirementsConstants.MinCpu
  10. max_cpu_requirements = consts.TestSize.get_max_requirements(test_size).get(consts.TestRequirements.Cpu)
  11. if isinstance(suite_cpu_requirements, str):
  12. if all(
  13. consts.TestRequirementsConstants.is_all_cpu(req) for req in (max_cpu_requirements, suite_cpu_requirements)
  14. ):
  15. return None
  16. return "Wrong 'cpu' requirements: {}, should be in [{}..{}] for {}-size tests".format(
  17. suite_cpu_requirements, min_cpu_requirements, max_cpu_requirements, test_size
  18. )
  19. if not isinstance(suite_cpu_requirements, int):
  20. return "Wrong 'cpu' requirements: {}, should be integer".format(suite_cpu_requirements)
  21. if (
  22. suite_cpu_requirements < min_cpu_requirements
  23. or suite_cpu_requirements > consts.TestRequirementsConstants.get_cpu_value(max_cpu_requirements)
  24. ):
  25. return "Wrong 'cpu' requirement: {}, should be in [{}..{}] for {}-size tests".format(
  26. suite_cpu_requirements, min_cpu_requirements, max_cpu_requirements, test_size
  27. )
  28. return None
  29. # TODO: Remove is_kvm param when there will be guarantees on RAM
  30. def check_ram(suite_ram_requirements, test_size, is_kvm=False):
  31. if not isinstance(suite_ram_requirements, int):
  32. return "Wrong 'ram' requirements: {}, should be integer".format(suite_ram_requirements)
  33. min_ram_requirements = consts.TestRequirementsConstants.MinRam
  34. max_ram_requirements = (
  35. consts.MAX_RAM_REQUIREMENTS_FOR_KVM
  36. if is_kvm
  37. else consts.TestSize.get_max_requirements(test_size).get(consts.TestRequirements.Ram)
  38. )
  39. if suite_ram_requirements < min_ram_requirements or suite_ram_requirements > max_ram_requirements:
  40. err_msg = "Wrong 'ram' requirements: {}, should be in [{}..{}] for {}-size tests".format(
  41. suite_ram_requirements, min_ram_requirements, max_ram_requirements, test_size
  42. )
  43. if is_kvm:
  44. err_msg += ' with kvm requirements'
  45. return err_msg
  46. return None
  47. def check_ram_disk(suite_ram_disk, test_size, is_kvm=False):
  48. min_ram_disk = consts.TestRequirementsConstants.MinRamDisk
  49. max_ram_disk = consts.TestSize.get_max_requirements(test_size).get(consts.TestRequirements.RamDisk)
  50. if isinstance(suite_ram_disk, str):
  51. if all(consts.TestRequirementsConstants.is_all_ram_disk(req) for req in (max_ram_disk, suite_ram_disk)):
  52. return None
  53. return "Wrong 'ram_disk' requirements: {}, should be in [{}..{}] for {}-size tests".format(
  54. suite_ram_disk, 0, max_ram_disk, test_size
  55. )
  56. if not isinstance(suite_ram_disk, int):
  57. return "Wrong 'ram_disk' requirements: {}, should be integer".format(suite_ram_disk)
  58. if suite_ram_disk < min_ram_disk or suite_ram_disk > consts.TestRequirementsConstants.get_ram_disk_value(
  59. max_ram_disk
  60. ):
  61. return "Wrong 'ram_disk' requirement: {}, should be in [{}..{}] for {}-size tests".format(
  62. suite_ram_disk, min_ram_disk, max_ram_disk, test_size
  63. )
  64. return None
  65. def validate_sb_vault(name, value):
  66. if not CANON_SB_VAULT_REGEX.match(value):
  67. return "sb_vault value '{}' should follow pattern <ENV_NAME>=<value|file>:<owner>:<vault key>".format(value)
  68. def validate_yav_vault(name, value):
  69. if not CANON_YAV_REGEX.match(value):
  70. return "yav value '{}' should follow pattern <ENV_NAME>=<value|file>:<sec-id>:<key>".format(value)
  71. def validate_numerical_requirement(name, value):
  72. if mr.resolve_value(value) is None:
  73. return "Cannot convert [[imp]]{}[[rst]] to the proper [[imp]]{}[[rst]] requirement value".format(value, name)
  74. def validate_choice_requirement(name, val, valid):
  75. if val not in valid:
  76. return "Unknown [[imp]]{}[[rst]] requirement: [[imp]]{}[[rst]], choose from [[imp]]{}[[rst]]".format(
  77. name, val, ", ".join(valid)
  78. )
  79. def validate_force_sandbox_requirement(
  80. name, value, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, check_func
  81. ):
  82. if is_force_sandbox or not in_autocheck or is_fuzzing or is_ytexec_run:
  83. if value == 'all':
  84. return
  85. return validate_numerical_requirement(name, value)
  86. error_msg = validate_numerical_requirement(name, value)
  87. if error_msg:
  88. return error_msg
  89. return check_func(mr.resolve_value(value), test_size, is_kvm)
  90. def validate_ram_disk_requirement(
  91. name, value, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, ram
  92. ):
  93. error_msg = validate_force_sandbox_requirement(
  94. name, value, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, check_ram_disk
  95. )
  96. if error_msg:
  97. return error_msg
  98. if is_force_sandbox or not in_autocheck or test_size == consts.TestSize.Large:
  99. return
  100. if int(value) > int(ram):
  101. return "Wrong 'ram_disk' value, 'ram_disk':{} should be no more than 'ram':{}".format(value, ram)
  102. return None
  103. # TODO: Remove is_kvm param when there will be guarantees on RAM
  104. def validate_requirement(
  105. req_name, value, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, requirements
  106. ):
  107. req_checks = {
  108. 'container': validate_numerical_requirement,
  109. 'cpu': lambda n, v: validate_force_sandbox_requirement(
  110. n, v, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, check_cpu
  111. ),
  112. 'disk_usage': validate_numerical_requirement,
  113. 'dns': lambda n, v: validate_choice_requirement(n, v, VALID_DNS_REQUIREMENTS),
  114. 'kvm': None,
  115. 'network': lambda n, v: validate_choice_requirement(n, v, VALID_NETWORK_REQUIREMENTS),
  116. 'ram': lambda n, v: validate_force_sandbox_requirement(
  117. n, v, test_size, is_force_sandbox, in_autocheck, is_fuzzing, is_kvm, is_ytexec_run, check_ram
  118. ),
  119. 'ram_disk': lambda n, v: validate_ram_disk_requirement(
  120. n,
  121. v,
  122. test_size,
  123. is_force_sandbox,
  124. in_autocheck,
  125. is_fuzzing,
  126. is_kvm,
  127. is_ytexec_run,
  128. requirements.get(
  129. 'ram', consts.TestSize.get_default_requirements(test_size).get(consts.TestRequirements.Ram)
  130. ),
  131. ),
  132. 'sb': None,
  133. 'sb_vault': validate_sb_vault,
  134. 'yav': validate_yav_vault,
  135. }
  136. if req_name not in req_checks:
  137. return "Unknown requirement: [[imp]]{}[[rst]], choose from [[imp]]{}[[rst]]".format(
  138. req_name, ", ".join(sorted(req_checks))
  139. )
  140. if req_name in ('container', 'disk') and not is_force_sandbox:
  141. return "Only [[imp]]LARGE[[rst]] tests without [[imp]]ya:force_distbuild[[rst]] tag can have [[imp]]{}[[rst]] requirement".format(
  142. req_name
  143. )
  144. check_func = req_checks[req_name]
  145. if check_func:
  146. return check_func(req_name, value)