send_build_stats.py 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. #!/usr/bin/env python3
  2. import configparser
  3. import datetime
  4. import os
  5. import ydb
  6. import uuid
  7. import subprocess
  8. dir = os.path.dirname(__file__)
  9. config = configparser.ConfigParser()
  10. config_file_path = f"{dir}/../config/ydb_qa_db.ini"
  11. config.read(config_file_path)
  12. YDBD_PATH = config["YDBD"]["YDBD_PATH"]
  13. DATABASE_ENDPOINT = config["QA_DB"]["DATABASE_ENDPOINT"]
  14. DATABASE_PATH = config["QA_DB"]["DATABASE_PATH"]
  15. FROM_ENV_COLUMNS = [
  16. "github_head_ref",
  17. "github_workflow",
  18. "github_workflow_ref",
  19. "github_sha",
  20. "github_repository",
  21. "github_event_name",
  22. "github_ref_type",
  23. "github_ref_name",
  24. "github_ref",
  25. ]
  26. STRING_COLUMNS = FROM_ENV_COLUMNS + [
  27. "id",
  28. "git_commit_message",
  29. "binary_path",
  30. "build_preset",
  31. ]
  32. DATETIME_COLUMNS = [
  33. "git_commit_time",
  34. ]
  35. UINT64_COLUMNS = [
  36. "size_bytes",
  37. "size_stripped_bytes",
  38. ]
  39. ALL_COLUMNS = STRING_COLUMNS + DATETIME_COLUMNS + UINT64_COLUMNS
  40. def sanitize_str(s):
  41. # YDB SDK expects bytes for 'String' columns
  42. if s is None:
  43. s = "N\A"
  44. return s.encode("utf-8")
  45. def main():
  46. if "CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS" not in os.environ:
  47. print("Env variable CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS is missing, skipping")
  48. return 1
  49. # Do not set up 'real' variable from gh workflows because it interfere with ydb tests
  50. # So, set up it locally
  51. os.environ["YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS"] = os.environ["CI_YDB_SERVICE_ACCOUNT_KEY_FILE_CREDENTIALS"]
  52. if not os.path.exists(YDBD_PATH):
  53. # can be possible due to incremental builds and ydbd itself is not affected by changes
  54. print("{} not exists, skipping".format(YDBD_PATH))
  55. return 0
  56. with ydb.Driver(
  57. endpoint=DATABASE_ENDPOINT,
  58. database=DATABASE_PATH,
  59. credentials=ydb.credentials_from_env_variables()
  60. ) as driver:
  61. driver.wait(timeout=10, fail_fast=True)
  62. session = ydb.retry_operation_sync(
  63. lambda: driver.table_client.session().create()
  64. )
  65. with session.transaction() as tx:
  66. text_query_builder = []
  67. for type_ in STRING_COLUMNS:
  68. text_query_builder.append("DECLARE ${} as String;".format(type_))
  69. for type_ in UINT64_COLUMNS:
  70. text_query_builder.append("DECLARE ${} as Uint64;".format(type_))
  71. for type_ in DATETIME_COLUMNS:
  72. text_query_builder.append("DECLARE ${} as Datetime;".format(type_))
  73. text_query_builder.append(
  74. """INSERT INTO binary_size
  75. (
  76. {}
  77. )
  78. VALUES
  79. (
  80. {}
  81. );
  82. """.format(
  83. ", \n ".join(ALL_COLUMNS),
  84. ", \n ".join(["$" + column for column in ALL_COLUMNS]),
  85. )
  86. )
  87. text_query = "\n".join(text_query_builder)
  88. prepared_query = session.prepare(text_query)
  89. binary_size_bytes = subprocess.check_output(
  90. ["bash", "-c", "cat {} | wc -c".format(YDBD_PATH)]
  91. )
  92. binary_size_stripped_bytes = subprocess.check_output(
  93. ["bash", "-c", "./ya tool strip {} -o - | wc -c".format(YDBD_PATH)]
  94. )
  95. build_preset = os.environ.get("build_preset", None)
  96. github_sha = os.environ.get("commit_git_sha", None)
  97. if github_sha is not None:
  98. git_commit_time_bytes = subprocess.check_output(
  99. ["git", "show", "--no-patch", "--format=%cI", github_sha]
  100. )
  101. git_commit_message_bytes = subprocess.check_output(
  102. ["git", "log", "--format=%s", "-n", "1", github_sha]
  103. )
  104. git_commit_time = datetime.datetime.fromisoformat(
  105. git_commit_time_bytes.decode("utf-8").strip()
  106. )
  107. git_commit_message = git_commit_message_bytes.decode("utf-8").strip()
  108. git_commit_time_unix = int(git_commit_time.timestamp())
  109. else:
  110. git_commit_time = None
  111. git_commit_message = None
  112. git_commit_time_unix = 0
  113. parameters = {
  114. "$id": sanitize_str(str(uuid.uuid4())),
  115. "$build_preset": sanitize_str(build_preset),
  116. "$binary_path": sanitize_str(YDBD_PATH),
  117. "$size_stripped_bytes": int(binary_size_stripped_bytes.decode("utf-8")),
  118. "$size_bytes": int(binary_size_bytes.decode("utf-8")),
  119. "$git_commit_time": git_commit_time_unix,
  120. "$git_commit_message": sanitize_str(git_commit_message),
  121. }
  122. for column in FROM_ENV_COLUMNS:
  123. value = os.environ.get(column.upper(), None)
  124. parameters["$" + column] = sanitize_str(value)
  125. #workaround for https://github.com/ydb-platform/ydb/issues/5294
  126. parameters["$github_sha"] = sanitize_str(github_sha)
  127. print("Executing query:\n{}".format(text_query))
  128. print("With parameters:")
  129. for k, v in parameters.items():
  130. print("{}: {}".format(k, v))
  131. tx.execute(prepared_query, parameters, commit_tx=True)
  132. if __name__ == "__main__":
  133. exit(main())