Conservative SmartOS global-zone memory pressure guard with dry-run-first policy and SMF integration.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

134 lines
7.4 KiB

  1. /* Exercise the actual daemon selection/action path. Native backend NOT linked. */
  2. #define main guard_program_main
  3. #include "../src/main.c"
  4. #undef main
  5. static double fake_now = 100;
  6. static sample_t fake_sample;
  7. static process_t fixtures[8];
  8. static unsigned nfixtures, real_requests, validation_requests, checks;
  9. static int fail_validation, fail_sample, partial;
  10. #define CHECK(x) do { if (!(x)) { fprintf(stderr, "FAIL runtime line %d: %s\n", __LINE__, #x); exit(1); } checks++; } while (0)
  11. double monotime(void) { return fake_now; }
  12. int secure_file(const char *p, int flags, unsigned mode)
  13. { (void)p; (void)flags; (void)mode; errno = EPERM; return -1; }
  14. int secure_directory(const char *p) { (void)p; return -1; }
  15. int platform_init(void) { return 0; }
  16. void platform_fini(void) { }
  17. int platform_sample(sample_t *s)
  18. { *s = fake_sample; s->at = fake_now; return fail_sample ? -1 : 0; }
  19. int platform_walk(int (*fn)(const process_t *, void *), void *arg, unsigned budget)
  20. {
  21. unsigned j; (void)budget;
  22. for (j = 0; j < nfixtures; j++) if (fn(&fixtures[j], arg)) return -1;
  23. return partial ? -1 : 0;
  24. }
  25. int platform_signal(const config_t *c, const process_t *p, enum action action,
  26. int real, uint64_t ceiling)
  27. {
  28. CHECK(action == TERM || action == KILL);
  29. CHECK(!protected_process(c, p));
  30. if (real) { CHECK(c->armed && fake_sample.free < ceiling); real_requests++; }
  31. else validation_requests++;
  32. if (fail_validation) { errno = ESTALE; return -1; }
  33. return 0; /* This test backend cannot send any signal. */
  34. }
  35. static void reset(void)
  36. {
  37. defaults(&cfg); cfg.log_mib = 100;
  38. cfg.nzones = 2;
  39. strcpy(cfg.zones[0].uuid, "11111111-1111-4111-8111-111111111111");
  40. strcpy(cfg.zones[0].alias, "web-a"); cfg.zones[0].policy = ALLOW;
  41. strcpy(cfg.zones[1].uuid, "22222222-2222-4222-8222-222222222222");
  42. strcpy(cfg.zones[1].alias, "web-b"); cfg.zones[1].policy = ALLOW;
  43. memset(processes, 0, sizeof (processes)); memset(zone_stats, 0, sizeof (zone_stats));
  44. memset(metrics, 0, sizeof (metrics));
  45. memset(&controller, 0, sizeof (controller)); memset(fixtures, 0, sizeof (fixtures));
  46. engine_init(&engine); engine.state = CRITICAL; engine.danger = 1;
  47. stopping = 0; started = 0; log_ok = 1; log_bytes = 0;
  48. scan_generation = 0; fake_now = 100; partial = fail_sample = fail_validation = 0;
  49. real_requests = validation_requests = 0;
  50. memset(&fake_sample, 0, sizeof (fake_sample)); fake_sample.at = fake_now;
  51. fake_sample.free = 60000; fake_sample.lots = 130875;
  52. fake_sample.des = 65437; fake_sample.min = 49077;
  53. fixtures[0].pid = 123; fixtures[0].ppid = 100; fixtures[0].zid = 9;
  54. fixtures[0].initpid = 99; fixtures[0].nlwp = 1; fixtures[0].start_sec = 1000;
  55. fixtures[0].zone_generation = 20; fixtures[0].rss_kib = 100000;
  56. strcpy(fixtures[0].uuid, cfg.zones[0].uuid); strcpy(fixtures[0].name, "php-fpm");
  57. nfixtures = 1;
  58. scan_processes(0);
  59. }
  60. int main(void)
  61. {
  62. FILE *log = tmpfile(); char contents[65536]; size_t n;
  63. const process_t *chosen;
  64. unsigned second;
  65. CHECK(log != NULL); logfd = fileno(log);
  66. reset(); act(&fake_sample);
  67. CHECK(real_requests == 0 && validation_requests == 1 && controller.has_pending);
  68. fake_now += 5; scan_processes(0); act(&fake_sample);
  69. CHECK(real_requests == 0 && !controller.has_pending);
  70. rewind(log); n = fread(contents, 1, sizeof (contents) - 1, log); contents[n] = 0;
  71. CHECK(strstr(contents, "WOULD_ACTION=SIGTERM") != NULL);
  72. CHECK(strstr(contents, "WOULD_ACTION=SIGKILL") != NULL);
  73. CHECK(strstr(contents, "ACTION_INTENT=") == NULL);
  74. CHECK(fseek(log, 0, SEEK_END) == 0);
  75. puts("PASS actual daemon dry-run path records WOULD_ACTION=SIGTERM/SIGKILL; zero real requests");
  76. reset();
  77. fake_sample.arc_ok = 1;
  78. fake_sample.swap_virtual_ok = fake_sample.swap_physical_ok = fake_sample.pageout_ok = 1;
  79. for (second = 0; second <= 60; second++) {
  80. fake_sample.at = 100 + second;
  81. fake_sample.arc = UINT64_C(6000000000) + 1000 * second;
  82. fake_sample.swap_alloc = 7000000 + 3 * second;
  83. fake_sample.swap_reserved = 480000 + 2 * second;
  84. fake_sample.swap_available = 6200000 - second;
  85. fake_sample.swap_physical_used_bytes = UINT64_C(4143648768) + 4096 * second;
  86. fake_sample.anon_pageout_pages = 1000 + 2 * second;
  87. record_metrics(&fake_sample);
  88. }
  89. log_sample(&fake_sample);
  90. CHECK(fflush(log) == 0 && fseek(log, 0, SEEK_SET) == 0);
  91. n = fread(contents, 1, sizeof (contents) - 1, log); contents[n] = 0;
  92. CHECK(strstr(contents, "swap_committed_ok=1 swap_committed_pages=7480300") != NULL);
  93. CHECK(strstr(contents, "swap_physical_used_ok=1 swap_physical_used_bytes=4143894528") != NULL);
  94. CHECK(strstr(contents, "anon_pageout_ok=1 anon_pageout_pages=1120") != NULL);
  95. CHECK(strstr(contents, "swap_alloc_pages=7000180 swap_reserved_pages=480120 swap_available_pages=6199940") != NULL);
  96. CHECK(strstr(contents, "metric=swap_committed_pages d5=+25@5.00s d15=+75@15.00s d60=+300@60.00s") != NULL);
  97. CHECK(strstr(contents, "metric=swap_physical_used_bytes d5=+20480@5.00s d15=+61440@15.00s d60=+245760@60.00s") != NULL);
  98. CHECK(strstr(contents, "metric=anon_pageout_pages d5=+10@5.00s d15=+30@15.00s d60=+120@60.00s") != NULL);
  99. CHECK(strstr(contents, "swap_used_pages") == NULL);
  100. CHECK(fseek(log, 0, SEEK_END) == 0);
  101. puts("PASS continuous sample contract and 5/15/60 deltas for commitment, physical swap and pageout");
  102. reset(); cfg.armed = 1; act(&fake_sample);
  103. CHECK(real_requests == 1);
  104. fake_now += 5; scan_processes(0); act(&fake_sample); CHECK(real_requests == 2);
  105. reset(); cfg.armed = 1; started = 80; act(&fake_sample); CHECK(real_requests == 0);
  106. reset(); cfg.armed = 1; log_ok = 0; act(&fake_sample); CHECK(real_requests == 0);
  107. reset(); cfg.armed = 1; partial = 1; scan_processes(0); act(&fake_sample); CHECK(real_requests == 0);
  108. reset(); cfg.armed = 1; fail_sample = 1; act(&fake_sample); CHECK(real_requests == 0);
  109. reset(); cfg.armed = 1; fail_validation = 1; act(&fake_sample); CHECK(real_requests == 0);
  110. reset(); cfg.armed = 1; fake_sample.free = 150000; act(&fake_sample); CHECK(real_requests == 0);
  111. reset(); cfg.armed = 1; fake_now += 3; act(&fake_sample); CHECK(real_requests == 0);
  112. reset(); cfg.armed = 1; stopping = 1; act(&fake_sample); CHECK(real_requests == 0);
  113. reset(); fake_sample.free = 20000; act(&fake_sample);
  114. CHECK(!controller.has_pending && controller.nvictims == 1);
  115. puts("PASS armed-path mock requests, warmup, stale cache, logging/sampling failures, stop and fresh floor");
  116. reset(); fixtures[1] = fixtures[0]; fixtures[1].pid = 124;
  117. fixtures[1].rss_kib = 900000; fixtures[1].zid = 10;
  118. strcpy(fixtures[1].uuid, cfg.zones[1].uuid); nfixtures = 2;
  119. fake_now = 101; scan_processes(0); chosen = candidate(); CHECK(chosen && chosen->pid == 124);
  120. /* Small zone grows fast enough to outweigh a larger steady zone. */
  121. fixtures[0].rss_kib = 600000; fake_now = 161; scan_processes(0);
  122. chosen = candidate(); CHECK(chosen && chosen->pid == 123);
  123. cfg.zones[0].policy = PROTECT; fake_now = 162; scan_processes(0);
  124. chosen = candidate(); CHECK(chosen && chosen->pid == 124);
  125. fixtures[1].zid = 0; fake_now = 163; scan_processes(0); CHECK(candidate() == NULL);
  126. puts("PASS actual daemon ranking by zone/PID RSS and growth; protected zones and global zone excluded");
  127. fclose(log);
  128. printf("PASS %u runtime checks; all platform calls mocked, no signals sent\n", checks);
  129. return 0;
  130. }