Compare commits
	
		
			836 Commits
		
	
	
	| Author | SHA1 | Date | 
|---|---|---|
|  | dbac55ca9e | |
|  | 91d45d870a | |
|  | 4d22089978 | |
|  | 8007b8af25 | |
|  | 0baa4f6b09 | |
|  | a0c30df25b | |
|  | 27d03ef2e2 | |
|  | 634e42c916 | |
|  | 6e46b42bf4 | |
|  | 71ebdd9d3c | |
|  | 7604c8361f | |
|  | 94a6f3cc3a | |
|  | e3ed1ba226 | |
|  | 652bd99439 | |
|  | f731873df9 | |
|  | 088e2a3a90 | |
|  | 2035e13724 | |
|  | 04b966dfec | |
|  | 0a0be027fd | |
|  | ddc2918a48 | |
|  | 0e006bb0ff | |
|  | ce7722aed4 | |
|  | ad2dd7d787 | |
|  | 30abbe0cab | |
|  | c27541140a | |
|  | 52d65c333b | |
|  | a07dce28bb | |
|  | fb43abf1f3 | |
|  | 9c42f9f2e1 | |
|  | ad826725ce | |
|  | 4326693888 | |
|  | 469a0faec4 | |
|  | 349cc0835e | |
|  | aa14f50e45 | |
|  | ee8ca99e49 | |
|  | 6a13540076 | |
|  | ded39bede6 | |
|  | 9890c0592d | |
|  | 3b5693eecb | |
|  | e6e621a50a | |
|  | 0b2534ebc9 | |
|  | e858d67926 | |
|  | bc6c23609a | |
|  | 666d0c52c4 | |
|  | d9826e5244 | |
|  | 6f3882c482 | |
|  | e46c929241 | |
|  | d4af75d82e | |
|  | e335f53037 | |
|  | c359d14e69 | |
|  | 9d8c59aeb3 | |
|  | eef57e1a77 | |
|  | 97697e80b4 | |
|  | 27b292bdd3 | |
|  | 1dbb88cb9e | |
|  | 43f1cd0dac | |
|  | 389d842a30 | |
|  | f6f42dd4c1 | |
|  | 20e157fa72 | |
|  | cae7efa2c6 | |
|  | d6e2790db5 | |
|  | a1a8dc5606 | |
|  | 16304b5ce7 | |
|  | 32f19acc66 | |
|  | 46ee5cf9a2 | |
|  | f832b0b254 | |
|  | a33d34a036 | |
|  | 15990d492d | |
|  | 462db4dfc8 | |
|  | ea27448da5 | |
|  | 4ca37fbdf2 | |
|  | 5a960b5ebb | |
|  | 7033e299cd | |
|  | 344c242785 | |
|  | 6acaeeefc7 | |
|  | eaa3f2a3a0 | |
|  | 3c1a323381 | |
|  | fb9b96bf75 | |
|  | a325cc745a | |
|  | d4e3d2aa6f | |
|  | 75c6a94010 | |
|  | d8f1a61ab6 | |
|  | 2dab45c373 | |
|  | 7a5996f467 | |
|  | 87938ee5bf | |
|  | 2f5c981d46 | |
|  | 75e037909e | |
|  | e122615553 | |
|  | e12a892748 | |
|  | ddc872d3ee | |
|  | 7ccc177b84 | |
|  | 68787beab5 | |
|  | 4dd68f1a89 | |
|  | 790191e987 | |
|  | f6b4d87431 | |
|  | 4584cc65a9 | |
|  | f673a085b0 | |
|  | 66172ab0bd | |
|  | 7b5a02b0b6 | |
|  | 1e10417be8 | |
|  | 1ef7196115 | |
|  | 59cb1d2c8b | |
|  | fd8f76b91c | |
|  | 7e04027d19 | |
|  | 488b0956fd | |
|  | 3c14ee0652 | |
|  | 32ae917937 | |
|  | 3998f6dee6 | |
|  | 835bc2aed8 | |
|  | 8b36ea90eb | |
|  | 96d1bbcf2f | |
|  | 90b68fec1a | |
|  | 1be410ba80 | |
|  | 930c9db6e7 | |
|  | a152741a1a | |
|  | 80d848339e | |
|  | 8535a24135 | |
|  | b349ded2be | |
|  | 6276c84493 | |
|  | 4a8420ce96 | |
|  | a62ca3d853 | |
|  | 4eb038eaa1 | |
|  | b2c6992e84 | |
|  | 0a6208e38d | |
|  | 2cc793a835 | |
|  | 894732732a | |
|  | e45ac190e2 | |
|  | d0fb7206a4 | |
|  | 9afd93065f | |
|  | 3be7128f9a | |
|  | 3bda9bb240 | |
|  | ab92e4edc3 | |
|  | fa7a4f584e | |
|  | 9b51f25800 | |
|  | ea13873f14 | |
|  | a6d87c46cd | |
|  | 51c70a64c3 | |
|  | a1b8e0cc3d | |
|  | 2889029bc5 | |
|  | 87f2e00971 | |
|  | d9af241a7d | |
|  | 49490c4421 | |
|  | 109750f816 | |
|  | 9e191cdd21 | |
|  | f965dfef73 | |
|  | 4ee49fee14 | |
|  | 8075e5ee74 | |
|  | 963ae48a3f | |
|  | 98854ef9c0 | |
|  | 1987d9eb2e | |
|  | 0006dd5eb1 | |
|  | 86f1714354 | |
|  | f68bbad579 | |
|  | d3a8a34bb2 | |
|  | d515b4a6e0 | |
|  | d971fedbe8 | |
|  | 6c6d061f0a | |
|  | 5b9b9f7ca2 | |
|  | 4357525445 | |
|  | 1d1790614b | |
|  | 442d52cd56 | |
|  | b6a95ae879 | |
|  | 9968141086 | |
|  | e59d127d41 | |
|  | fb1232c13e | |
|  | 7a643a5107 | |
|  | 46cfbb6ec7 | |
|  | c9099a5a56 | |
|  | 48706584fd | |
|  | 2c0e53951b | |
|  | a7af44e042 | |
|  | f225fef921 | |
|  | 814947c60e | |
|  | 039350a0d0 | |
|  | a0fb417f69 | |
|  | f5fd831c2f | |
|  | 753afb75b9 | |
|  | 309b53143e | |
|  | 7da2d7f96a | |
|  | e06c7edc21 | |
|  | 9fba37540a | |
|  | a68aa00bd8 | |
|  | 9b053102ed | |
|  | c03fac8fdd | |
|  | d72774753c | |
|  | f7b6ad901d | |
|  | 728f05c844 | |
|  | c00465973e | |
|  | 5f23afaad3 | |
|  | 47dfed3ced | |
|  | 1f9b7541e6 | |
|  | a029b705cd | |
|  | 3fab744a4f | |
|  | fe8c3bb789 | |
|  | e40874f67f | |
|  | d7d479172d | |
|  | 31352924d7 | |
|  | 3e4201ac5f | |
|  | a44b037d6b | |
|  | e11beea49b | |
|  | bfadad0830 | |
|  | f7eb88ce9c | |
|  | 0fd8eac305 | |
|  | b78cadd901 | |
|  | 202a97ab12 | |
|  | b08d533105 | |
|  | 0bfa57ac50 | |
|  | 2831d658c4 | |
|  | 0f40f6ab26 | |
|  | 5347e2c2c8 | |
|  | 1cba9c7800 | |
|  | 2c29cfb994 | |
|  | 4f89ac5878 | |
|  | 64778a828e | |
|  | 8e484637f9 | |
|  | b202be712e | |
|  | fb11d3bfd0 | |
|  | 7793e1974a | |
|  | 8aa04dd2be | |
|  | 2939640fa9 | |
|  | 65fd04540c | |
|  | 1ae5d2b18e | |
|  | 862bc1a9dd | |
|  | 95487735a2 | |
|  | 16815230bb | |
|  | 2646456677 | |
|  | 62eca94e45 | |
|  | 510b1d82e5 | |
|  | b511953df7 | |
|  | 2117fd1892 | |
|  | e1edb84abe | |
|  | f14dbd68f1 | |
|  | bffcb32b19 | |
|  | ea2443a410 | |
|  | ba91c183b5 | |
|  | e10a1cc7a3 | |
|  | ce80adb9ab | |
|  | 1a8abb6d39 | |
|  | fdf7b6c525 | |
|  | db061b33e7 | |
|  | ead26ab18f | |
|  | 16666e1bba | |
|  | 2ae39828b2 | |
|  | cf24ab584d | |
|  | 07bff8aa1e | |
|  | ea2fb32e20 | |
|  | 6a022e5489 | |
|  | 837a1cb850 | |
|  | dce49a003d | |
|  | c8216e1396 | |
|  | 564c112b1a | |
|  | c7dce2bbb7 | |
|  | 10d79342d7 | |
|  | 64eafb58b6 | |
|  | 030efd82c5 | |
|  | f1d7c52253 | |
|  | 76d622b86b | |
|  | 0b24b0d60b | |
|  | 5e23c598a8 | |
|  | 3652932780 | |
|  | 94065d2fc5 | |
|  | b1cc4da5dc | |
|  | 8b7bfa5ffb | |
|  | 52fc819339 | |
|  | 215b245881 | |
|  | a3df23b07c | |
|  | f5c69654e7 | |
|  | abc0b678d3 | |
|  | 963ab2a748 | |
|  | 8a41a596b6 | |
|  | e10c437f46 | |
|  | a0a3916c80 | |
|  | 1c360d7e26 | |
|  | 20bb860a37 | |
|  | 6a75bc0880 | |
|  | 78271000c0 | |
|  | a36b0e58b0 | |
|  | 336e11a4e9 | |
|  | dcb64f0b9e | |
|  | 0dadfc4d37 | |
|  | dc58f6ba13 | |
|  | 06cbd632b8 | |
|  | 9f33ae1507 | |
|  | 63a6b5a7f0 | |
|  | fddc5bf1c8 | |
|  | d90ce2bed5 | |
|  | cd996e7c27 | |
|  | 297442975e | |
|  | 5271f316e6 | |
|  | 9845a934f4 | |
|  | e0a7e142e0 | |
|  | f9a11a8b0b | |
|  | fde1893494 | |
|  | 6fe8008640 | |
|  | 2fee26ddce | |
|  | 685f7162a4 | |
|  | d134dee14b | |
|  | c33ce998f4 | |
|  | 78a93566af | |
|  | 81dea9b3dc | |
|  | 7ca3df3605 | |
|  | 2343cd2d7b | |
|  | cf18cb3fb0 | |
|  | ae8b27a9a3 | |
|  | 58ee5e8c4e | |
|  | fade63a663 | |
|  | ac4056f85b | |
|  | 462d044604 | |
|  | 94934819c4 | |
|  | aac811f210 | |
|  | e7ec736738 | |
|  | 90ea691e72 | |
|  | 32a653c0ca | |
|  | c7b2dd1764 | |
|  | 80af7fc125 | |
|  | 34909f0cf1 | |
|  | 8afef51c8b | |
|  | 032443fcfd | |
|  | 91c8991835 | |
|  | c5ebe750dc | |
|  | 34fdbf1231 | |
|  | 44e9b7d8eb | |
|  | 7ab516fdab | |
|  | e571df52b5 | |
|  | 706ec17bf4 | |
|  | 30355f742b | |
|  | 8a5fb6ccb7 | |
|  | e930ba6e98 | |
|  | 5ba3805a3f | |
|  | f798cddca1 | |
|  | 367ee46122 | |
|  | f4a318fca6 | |
|  | 4ee21cb24b | |
|  | 102c9e1afa | |
|  | 73e676f951 | |
|  | 41ebb43c65 | |
|  | aa50b62c01 | |
|  | 942f773fef | |
|  | 21722a5de8 | |
|  | a2d4b95b79 | |
|  | 04fb9f4fa1 | |
|  | 8304b80955 | |
|  | 9bd4025e9c | |
|  | 94c089c407 | |
|  | 9859bbc7f2 | |
|  | c1e2c4ef9d | |
|  | 2ee15dbca3 | |
|  | a4cf626410 | |
|  | 58f4b6ff2d | |
|  | 22fbd10bd3 | |
|  | 52b97139b6 | |
|  | 3e0bc3f7be | |
|  | ba1ac0990b | |
|  | 76fe43e8e0 | |
|  | 8869ad28bb | |
|  | b86af190f7 | |
|  | 1a491cbfe5 | |
|  | 087f20fd5d | |
|  | a880114e57 | |
|  | e80bc21fa5 | |
|  | 56754094ea | |
|  | 8fa4520376 | |
|  | a804bf8b00 | |
|  | 5dea6db412 | |
|  | 2a0b770a63 | |
|  | a7ef871248 | |
|  | e45e4c53f1 | |
|  | a608abd124 | |
|  | 02d9add322 | |
|  | f5ac134787 | |
|  | 42abad5def | |
|  | 514b7da742 | |
|  | c8e3bb5ec3 | |
|  | 878c9b8b49 | |
|  | 4536707af6 | |
|  | 13802c5a6d | |
|  | 362fa5d52e | |
|  | 65184f1ed8 | |
|  | c23e31123c | |
|  | 56e1c62ac2 | |
|  | 64cedff2b4 | |
|  | 37f93b794e | |
|  | dc833e57a0 | |
|  | 5228aded87 | |
|  | f49d08e4bc | |
|  | 064039afc0 | |
|  | e5d8d65396 | |
|  | c465ace8fb | |
|  | 34f3878829 | |
|  | 44c3931d8e | |
|  | 08acb1b831 | |
|  | 40811ebe0e | |
|  | 3417c5a3a8 | |
|  | 172faa883c | |
|  | 9e6c7d019f | |
|  | 9fbcafa703 | |
|  | 2bf83d0d7f | |
|  | 19d30dea5f | |
|  | 6c66c1633f | |
|  | e55708588b | |
|  | 261d4371b5 | |
|  | bd9f32e354 | |
|  | babbfc77d5 | |
|  | 322df79617 | |
|  | 1c7c6639ed | |
|  | bcaac39a2e | |
|  | af625dd1cb | |
|  | 44969659df | |
|  | a5f98dea75 | |
|  | 1d24d3b00d | |
|  | 9994d3aa60 | |
|  | a2ea12e93c | |
|  | d7b589bed5 | |
|  | 4f293c6f79 | |
|  | c569304271 | |
|  | 068f987238 | |
|  | a462ecbe79 | |
|  | c5d6842d5f | |
|  | 947bc8ab5b | |
|  | 9d5c6e85c5 | |
|  | 2420a40c02 | |
|  | b3e7c723d2 | |
|  | 2e36db52c3 | |
|  | 5d41609bea | |
|  | e289fe43d4 | |
|  | 91fddca3f7 | |
|  | befe4cee0a | |
|  | 548acdf05c | |
|  | 41f2ca3ed9 | |
|  | 00996ec799 | |
|  | 893833fdd5 | |
|  | 7f3eef8761 | |
|  | 40c905f25d | |
|  | 2984de912c | |
|  | 1df06a69d7 | |
|  | be47190d4c | |
|  | e8d8c6f357 | |
|  | 0c091f59b6 | |
|  | a4751b74e0 | |
|  | adad3d5530 | |
|  | 70156e3fea | |
|  | 69abd51f30 | |
|  | 73e35b1dc6 | |
|  | c4178d5633 | |
|  | edf924106b | |
|  | 34ebbf74d1 | |
|  | a9af82ec78 | |
|  | b5e9e14244 | |
|  | 910269aa11 | |
|  | 149cf47c83 | |
|  | ec3afef00d | |
|  | 7d0918b6d5 | |
|  | 678eafcd67 | |
|  | b6515fe25c | |
|  | 1c7b7f467d | |
|  | 73e22a1756 | |
|  | 9b44f0051c | |
|  | 6b4250ca90 | |
|  | ced88228fc | |
|  | 44c06c21ce | |
|  | 4103fe35df | |
|  | a44fe04bef | |
|  | 274d0c874e | |
|  | 256e08eb45 | |
|  | f677fd5872 | |
|  | d9627141dc | |
|  | 3886f285f8 | |
|  | dab900462b | |
|  | dd8ec1a055 | |
|  | 8e52a6d2cf | |
|  | 9990243520 | |
|  | 08919814b1 | |
|  | facae69e0b | |
|  | 8f62e35f6b | |
|  | 55951c2bdb | |
|  | c4297d25bb | |
|  | 0774f0680c | |
|  | 92ab11b4d2 | |
|  | 7414dc6568 | |
|  | 34efb9d585 | |
|  | fbad56197f | |
|  | a5cef7e47b | |
|  | 1f4fe4681e | |
|  | 067686c684 | |
|  | df12e00c9e | |
|  | cc26593a9b | |
|  | 835eac7835 | |
|  | 01e9dd31a9 | |
|  | 803818162c | |
|  | 219ba5b477 | |
|  | b09e3a2dc9 | |
|  | 7ea60e497c | |
|  | c8918f5a7b | |
|  | d57d17f161 | |
|  | 6e69c75637 | |
|  | 882bfab569 | |
|  | 3327f620fb | |
|  | 282f2dd09c | |
|  | d67f80863e | |
|  | 4932412cd6 | |
|  | 6da1cde09c | |
|  | f9bae708c2 | |
|  | 05a3908ba6 | |
|  | 606ed1b28e | |
|  | de244a17be | |
|  | 5be307ec62 | |
|  | ee71ff14bd | |
|  | 9e93c7ee54 | |
|  | bb61bb1342 | |
|  | 23fdca4786 | |
|  | 211bacaf1e | |
|  | 0324658a3f | |
|  | c4d3cff3df | |
|  | 294bd75cf1 | |
|  | 068a427c52 | |
|  | 622eaa34f8 | |
|  | 619667fc3b | |
|  | 3e88ae2d38 | |
|  | 360957cfbc | |
|  | e1fcd63f92 | |
|  | 461c016b98 | |
|  | 2e406e3aef | |
|  | 044c8ad4d5 | |
|  | eaa451df32 | |
|  | ab04a2b616 | |
|  | d32319be50 | |
|  | 057b04763f | |
|  | bc4f4fee12 | |
|  | a6c4d84234 | |
|  | e71c64683b | |
|  | 4aadc7d128 | |
|  | 45ebcb1c0a | |
|  | 3ede9b5a01 | |
|  | 84104de74b | |
|  | aa6dab5a9a | |
|  | 086f9fd2d6 | |
|  | 2407e4f6c6 | |
|  | fc23b7d08e | |
|  | 85ec00a5a5 | |
|  | 03d4784518 | |
|  | dcfacf4f1e | |
|  | 02d84575e2 | |
|  | 3021be73c7 | |
|  | adb5bc9f66 | |
|  | 466be710ee | |
|  | acbce4b70a | |
|  | 418f719bdf | |
|  | 300e93c59d | |
|  | 0285da1a32 | |
|  | b8e5185fef | |
|  | 187479f08c | |
|  | 31244dd61b | |
|  | a8417ec67e | |
|  | 775dc60c94 | |
|  | ecd7531917 | |
|  | ad1989072e | |
|  | fe05987eea | |
|  | bd392c3665 | |
|  | 58d80a7c12 | |
|  | 212b9daec3 | |
|  | 28ea8d4e7b | |
|  | c1fb793773 | |
|  | 63d2cbfdaa | |
|  | 18077a1e83 | |
|  | 3ae9f09532 | |
|  | 96a930bfd9 | |
|  | 877c93c5c3 | |
|  | 95c324b550 | |
|  | 5e8f576f65 | |
|  | cc15ff0119 | |
|  | 8318523627 | |
|  | fcb65b046b | |
|  | 87f566e1e6 | |
|  | a786dae450 | |
|  | 666ce8f917 | |
|  | 9ba4b6b96a | |
|  | ae86b1a011 | |
|  | 154fcde7d0 | |
|  | 86d7893d61 | |
|  | 8f374d561f | |
|  | 40eec3c783 | |
|  | 0c4798b773 | |
|  | 7680cfd371 | |
|  | 3b1771385f | |
|  | cb288fc99b | |
|  | 7c81c2eec1 | |
|  | 0908715786 | |
|  | 186c98cf36 | |
|  | d328c61fc3 | |
|  | 61d1235d2a | |
|  | 3b36a81db6 | |
|  | fbdfe0df8c | |
|  | 63e8f32281 | |
|  | 2ac48038c6 | |
|  | 23c8fe4a8b | |
|  | 8505c95719 | |
|  | 3de8085b87 | |
|  | 828d51baf2 | |
|  | 0b0219b88f | |
|  | 362b6c10a3 | |
|  | 2110fa5122 | |
|  | 9eae9ac75f | |
|  | 9bb416084b | |
|  | fdb049ba1e | |
|  | 5f27548a73 | |
|  | f7fb1490dc | |
|  | 9d48c791f5 | |
|  | 371eff09ce | |
|  | cfad7a9b08 | |
|  | 6234c568bd | |
|  | 3ae3811944 | |
|  | c74ad6195f | |
|  | 332548093a | |
|  | b4e143dadc | |
|  | 93c4dd856e | |
|  | 93aea48c38 | |
|  | 14b17cca73 | |
|  | 5298c6ea29 | |
|  | 8fa08d59b1 | |
|  | 003c552c34 | |
|  | 83370d7f95 | |
|  | 7da9d0ae19 | |
|  | b56fa6a748 | |
|  | a22ee8a5f1 | |
|  | e1762ba746 | |
|  | 710e2fbc3a | |
|  | 433552770e | |
|  | ba2a32eef6 | |
|  | de0d7ad78c | |
|  | 0382f3bbd5 | |
|  | b6640a033c | |
|  | 998c028d90 | |
|  | f8dffab19d | |
|  | 7ff5b7da8c | |
|  | 6aaff4ecee | |
|  | 437d0173b0 | |
|  | a389292478 | |
|  | 6eadb03669 | |
|  | aa60021ab0 | |
|  | 50e26bd2f6 | |
|  | 2dd13b4a19 | |
|  | 35af24cf03 | |
|  | ca96b66fbe | |
|  | 4db5fbc7a1 | |
|  | add83bc7bc | |
|  | 666bba784c | |
|  | 0672ff0ff9 | |
|  | f2f22827a6 | |
|  | a3a801757d | |
|  | 0c003f20d4 | |
|  | 863760828a | |
|  | 517fae4119 | |
|  | d9e1e64dc6 | |
|  | 3c4ab2d479 | |
|  | 3ca96557a6 | |
|  | 5fd6ec4bc8 | |
|  | 6863bdb208 | |
|  | f3fcb428ae | |
|  | 41bae32a9f | |
|  | e4879e7ae4 | |
|  | e5bb130fda | |
|  | e7a21cfc53 | |
|  | 8f54644b08 | |
|  | c56d6a6c85 | |
|  | a96c3e1102 | |
|  | d29de8d454 | |
|  | 12c4d96250 | |
|  | 46a13c0626 | |
|  | e32a8054d0 | |
|  | 0deb6809b9 | |
|  | 21af1ec19d | |
|  | dfadb86d66 | |
|  | c91e76f169 | |
|  | 718232f8f4 | |
|  | c7f5f7d161 | |
|  | 33bb6902bc | |
|  | aeb0601147 | |
|  | 991c0b3211 | |
|  | 71da6d5271 | |
|  | e4fd4bc99c | |
|  | d9a8dc7e84 | |
|  | 795cf8b1de | |
|  | 0615c2adb1 | |
|  | a918e56ece | |
|  | 546b5251ed | |
|  | 74dda4ea1b | |
|  | b29816290a | |
|  | 921daff61b | |
|  | e233f7ad6a | |
|  | 623c84fa52 | |
|  | d4fb6204cb | |
|  | f8e07c7fe4 | |
|  | f73713859c | |
|  | e0a7be253e | |
|  | 915739b972 | |
|  | 4925880e5e | |
|  | c143fd50b5 | |
|  | dbd668ae2d | |
|  | 5c1be3265b | |
|  | ebcd838501 | |
|  | 6ef276b239 | |
|  | f70f325f48 | |
|  | f7c336f9dd | |
|  | ae380f5987 | |
|  | 4bf1c12a98 | |
|  | cb561d8db4 | |
|  | eaf6d2f2e2 | |
|  | 5ae7ce16e0 | |
|  | bdcde44642 | |
|  | 5116e3800e | |
|  | 4e107a4e50 | |
|  | 93238697d9 | |
|  | 48f62b4c89 | |
|  | ea94b3cc5b | |
|  | 0cac005ab2 | |
|  | 55ca7bfdf5 | |
|  | ca97f39fcb | |
|  | f0c8c07428 | |
|  | e54edea918 | |
|  | e58f82bfce | |
|  | 244e0dd987 | |
|  | 02009cef17 | |
|  | 2b5af62184 | |
|  | ec58ad19e0 | |
|  | cc9fe33ef5 | |
|  | 4a5a85fd61 | |
|  | 56b26fd751 | |
|  | 36e95dad47 | |
|  | 3724b46033 | |
|  | 538e2783d7 | |
|  | 72ca998266 | |
|  | d439ed5c81 | |
|  | 58c2bdf2bb | |
|  | fe9164b025 | |
|  | 06141b39b4 | |
|  | ac4c3fd365 | |
|  | dc29e31bcc | |
|  | 784019f3d7 | |
|  | fc55477c1c | |
|  | 3f78f71137 | |
|  | e511401e51 | |
|  | 37aa1a0b8c | |
|  | bea0775bec | |
|  | 79a494b2aa | |
|  | 97404144eb | |
|  | b77489d098 | |
|  | 4152afbd30 | |
|  | 29f621e1c8 | |
|  | 5651ba6ead | |
|  | 759cc4b47f | |
|  | 4ede0c18d0 | |
|  | 9091d9b756 | |
|  | a09c2564d9 | |
|  | a555c90fd5 | |
|  | 38644cf4e8 | |
|  | 23f357db10 | |
|  | 584745b67d | |
|  | df9592dc99 | |
|  | 8071ac7066 | |
|  | 3c33eca501 | |
|  | aa827474b2 | |
|  | c75c9f9226 | |
|  | c09a04ec01 | |
|  | 618276e3d3 | |
|  | 18dd89c884 | |
|  | 98b17dc0a5 | |
|  | c658dcfa6d | |
|  | c4996d4bbd | |
|  | 7a3fa4f362 | |
|  | 1bfd743e69 | |
|  | 734f3bd63a | |
|  | 409dc4c114 | |
|  | 4b9a6c6700 | |
|  | 86e1a4a8f3 | |
|  | 544d620bc3 | |
|  | 1cfe1974c4 | |
|  | 7e4b6ebd6d | |
|  | 11cb9b7882 | |
|  | 10b88bf070 | |
|  | 8b619e7c6f | |
|  | fea1457f12 | |
|  | 473295e3fc | |
|  | 9f6f962fc7 | |
|  | 2a475f25c7 | |
|  | dd9f25ea78 | |
|  | b8e4eee904 | |
|  | edbdef8d20 | |
|  | a190fa97bb | |
|  | bfc5ea4727 | |
|  | 5a9e8545aa | |
|  | 4446ba57e1 | |
|  | d62c8a4697 | |
|  | 946d5b1fa7 | |
|  | da6b07660e | |
|  | e3deb0d752 | |
|  | 82641e5036 | |
|  | 2fe6adf5b7 | |
|  | 736126b793 | |
|  | 6abf5bbac8 | |
|  | dc4f116bda | |
|  | cda10fd243 | |
|  | b5d1a63bdf | |
|  | 6f3e23973d | |
|  | a517c1ff66 | |
|  | 9b28e633c1 | |
|  | 8161136cbd | |
|  | a9ac5a1cbf | |
|  | d4f35cff4f | |
|  | f661249f07 | |
|  | 73e430ce54 | |
|  | 858ef8979d | |
|  | 1ce0a183a6 | |
|  | 63935d2053 | |
|  | fc63d6d26e | |
|  | 5ea08411e6 | |
|  | 067ed2e5ec | |
|  | d86bd2bcd7 | |
|  | ddd417f756 | |
|  | 0386c0734c | |
|  | af96de6184 | |
|  | abb8615796 | |
|  | bc7a3cab1b | |
|  | e2c8163b8c | |
|  | 84d16c1c12 | |
|  | 071898c96b | |
|  | f24e2fa44e | |
|  | 3c7d3d6b57 | |
|  | 23f091d7fa | |
|  | 667764e027 | |
|  | de693c4191 | |
|  | 510fc9c834 | |
|  | 7fd5e24961 | |
|  | 9974b1a2b7 | |
|  | bd91b73fd9 | |
|  | a7ae910ee4 | |
|  | 2733c36d0e | 
|  | @ -0,0 +1 @@ | |||
| *.png filter=lfs diff=lfs merge=lfs -text | ||||
|  | @ -1,15 +1,17 @@ | |||
| # Blank issues are mainly for maintainers who are known to write complete issue descriptions without need to following a form | ||||
| blank_issues_enabled: true | ||||
| blank_issues_enabled: false | ||||
| contact_links: | ||||
| - name: Feature requests for the gha-runner-scale-set (actions.github.com API group) | ||||
|   about: Feature requests associated with the actions.github.com group should be posted on the GitHub Community Support Forum | ||||
|   url: https://github.com/orgs/community/discussions/categories/actions | ||||
| - name: Sponsor ARC Maintainers | ||||
|   about: If your business relies on the continued maintainance of actions-runner-controller, please consider sponsoring the project and the maintainers. | ||||
|   url: https://github.com/actions-runner-controller/actions-runner-controller/tree/master/CODEOWNERS | ||||
|   url: https://github.com/actions/actions-runner-controller/tree/master/CODEOWNERS | ||||
| - name: Ideas and Feature Requests | ||||
|   about: Wanna request a feature? Create a discussion and collect :+1:s first. | ||||
|   url: https://github.com/actions-runner-controller/actions-runner-controller/discussions/new?category=ideas | ||||
|   url: https://github.com/actions/actions-runner-controller/discussions/new?category=ideas | ||||
| - name: Questions and User Support | ||||
|   about: Need support using ARC? We use Discussions as the place to provide community support. | ||||
|   url: https://github.com/actions-runner-controller/actions-runner-controller/discussions/new?category=questions | ||||
|   url: https://github.com/actions/actions-runner-controller/discussions/new?category=questions | ||||
| - name: Need Paid Support? | ||||
|   about: Consider contracting with any of the actions-runner-controller maintainers and contributors. | ||||
|   url: https://github.com/actions-runner-controller/actions-runner-controller/tree/master/CODEOWNERS | ||||
|   url: https://github.com/actions/actions-runner-controller/tree/master/CODEOWNERS | ||||
|  |  | |||
|  | @ -1,19 +0,0 @@ | |||
| --- | ||||
| name: Feature request | ||||
| about: Suggest an idea for this project | ||||
| title: '' | ||||
| assignees: '' | ||||
| 
 | ||||
| --- | ||||
| 
 | ||||
| **Is your feature request related to a problem? Please describe.** | ||||
| A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] | ||||
| 
 | ||||
| **Describe the solution you'd like** | ||||
| A clear and concise description of what you want to happen. | ||||
| 
 | ||||
| **Describe alternatives you've considered** | ||||
| A clear and concise description of any alternative solutions or features you've considered. | ||||
| 
 | ||||
| **Additional context** | ||||
| Add any other context or screenshots about the feature request here. | ||||
|  | @ -0,0 +1,113 @@ | |||
| name: Bug Report (actions.github.com API group) | ||||
| description: File a bug report for actions.github.com API group | ||||
| title: "<Please write what didn't work for you here>" | ||||
| labels: ["bug", "needs triage", "gha-runner-scale-set"] | ||||
| body: | ||||
| - type: checkboxes | ||||
|   id: read-troubleshooting-guide | ||||
|   attributes: | ||||
|     label: Checks | ||||
|     description: Please check all the boxes below before submitting | ||||
|     options: | ||||
|     - label: I've already read https://docs.github.com/en/actions/hosting-your-own-runners/managing-self-hosted-runners-with-actions-runner-controller/troubleshooting-actions-runner-controller-errors and I'm sure my issue is not covered in the troubleshooting guide. | ||||
|       required: true | ||||
| 
 | ||||
|     - label: I am using charts that are officially provided | ||||
| - type: input | ||||
|   id: controller-version | ||||
|   attributes: | ||||
|     label: Controller Version | ||||
|     description: Refers to semver-like release tags for controller versions. Any release tags prefixed with `gha-runner-scale-set-` are releases associated with this API group | ||||
|     placeholder: ex. 0.6.1 | ||||
|   validations: | ||||
|     required: true | ||||
| - type: dropdown | ||||
|   id: deployment-method | ||||
|   attributes: | ||||
|     label: Deployment Method | ||||
|     description: Which deployment method did you use to install ARC? | ||||
|     options: | ||||
|       - Helm | ||||
|       - Kustomize | ||||
|       - ArgoCD | ||||
|       - Other | ||||
|   validations: | ||||
|     required: true | ||||
| - type: checkboxes | ||||
|   id: checks | ||||
|   attributes: | ||||
|     label: Checks | ||||
|     description: Please check all the boxes below before submitting | ||||
|     options: | ||||
|     - label: This isn't a question or user support case (For Q&A and community support, go to [Discussions](https://github.com/actions/actions-runner-controller/discussions)). | ||||
|       required: true | ||||
|     - label: I've read the [Changelog](https://github.com/actions/actions-runner-controller/blob/master/docs/gha-runner-scale-set-controller/README.md#changelog) before submitting this issue and I'm sure it's not due to any recently-introduced backward-incompatible changes | ||||
|       required: true | ||||
| - type: textarea | ||||
|   id: reproduction-steps | ||||
|   attributes: | ||||
|     label: To Reproduce | ||||
|     description: "Steps to reproduce the behavior" | ||||
|     render: markdown | ||||
|     placeholder: | | ||||
|       1. Go to '...' | ||||
|       2. Click on '....' | ||||
|       3. Scroll down to '....' | ||||
|       4. See error | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|   id: actual-behavior | ||||
|   attributes: | ||||
|     label: Describe the bug | ||||
|     description: Also tell us, what did happen? | ||||
|     placeholder: A clear and concise description of what happened. | ||||
|   validations: | ||||
|     required: true | ||||
| 
 | ||||
| - type: textarea | ||||
|   id: expected-behavior | ||||
|   attributes: | ||||
|     label: Describe the expected behavior | ||||
|     description: Also tell us, what did you expect to happen? | ||||
|     placeholder: A clear and concise description of what the expected behavior is. | ||||
|   validations: | ||||
|     required: true | ||||
| 
 | ||||
| - type: textarea | ||||
|   id: additional-context | ||||
|   attributes: | ||||
|     label: Additional Context | ||||
|     render: yaml | ||||
|     description: | | ||||
|       Provide `values.yaml` files that are relevant for this issue. PLEASE REDACT ANY INFORMATION THAT SHOULD NOT BE PUBLICALY AVAILABLE, LIKE GITHUB TOKEN FOR EXAMPLE. | ||||
|     placeholder: | | ||||
|       PLEASE REDACT ANY INFORMATION THAT SHOULD NOT BE PUBLICALY AVAILABLE, LIKE GITHUB TOKEN FOR EXAMPLE. | ||||
|   validations: | ||||
|     required: true | ||||
| 
 | ||||
| - type: textarea | ||||
|   id: controller-logs | ||||
|   attributes: | ||||
|     label: Controller Logs | ||||
|     description: "NEVER EVER OMIT THIS! Include complete logs from `actions-runner-controller`'s controller-manager pod." | ||||
|     render: shell | ||||
|     placeholder: | | ||||
|       PROVIDE THE LOGS VIA A GIST LINK (https://gist.github.com/), NOT DIRECTLY IN THIS TEXT AREA | ||||
| 
 | ||||
|       To grab controller logs: | ||||
| 
 | ||||
|       kubectl logs -n $NAMESPACE deployments/$CONTROLLER_DEPLOYMENT | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|   id: runner-pod-logs | ||||
|   attributes: | ||||
|     label: Runner Pod Logs | ||||
|     description: "Include logs and kubectl describe output from runner pod(s)." | ||||
|     render: shell | ||||
|     placeholder: | | ||||
|       PROVIDE THE WHOLE LOGS VIA A GIST LINK (https://gist.github.com/), NOT DIRECTLY IN THIS TEXT AREA | ||||
|   validations: | ||||
|     required: true | ||||
| 
 | ||||
|  | @ -1,8 +1,18 @@ | |||
| name: Bug Report | ||||
| description: File a bug report | ||||
| title: "Bug" | ||||
| labels: ["bug"] | ||||
| name: Bug Report (actions.summerwind.net API group) | ||||
| description: File a bug report for actions.summerwind.net API group | ||||
| title: "<Please write what didn't work for you here>" | ||||
| labels: ["bug", "needs triage", "community"] | ||||
| body: | ||||
| - type: checkboxes | ||||
|   id: read-troubleshooting-guide | ||||
|   attributes: | ||||
|     label: Checks | ||||
|     description: Please check all the boxes below before submitting | ||||
|     options: | ||||
|     - label: I've already read https://github.com/actions/actions-runner-controller/blob/master/TROUBLESHOOTING.md and I'm sure my issue is not covered in the troubleshooting guide. | ||||
|       required: true | ||||
|     - label: I'm not using a custom entrypoint in my runner image | ||||
|       required: true | ||||
| - type: input | ||||
|   id: controller-version | ||||
|   attributes: | ||||
|  | @ -17,6 +27,12 @@ body: | |||
|     label: Helm Chart Version | ||||
|     description: Run `helm list` and see what's shown under CHART VERSION. Any release tags prefixed with `actions-runner-controller-` are for chart releases | ||||
|     placeholder: ex. 0.11.0 | ||||
| - type: input | ||||
|   id: cert-manager-version | ||||
|   attributes: | ||||
|     label: CertManager Version | ||||
|     description: Run `kubectl get po -o yaml $CERT_MANAGER_POD` and see the image tag, or run `helm list` and see what's shown under APP VERSION for your cert-manager Helm release. | ||||
|     placeholder: ex. 1.8 | ||||
| - type: dropdown | ||||
|   id: deployment-method | ||||
|   attributes: | ||||
|  | @ -29,19 +45,32 @@ body: | |||
|       - Other | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|   id: cert-manager | ||||
|   attributes: | ||||
|     label: cert-manager installation | ||||
|     description: Confirm that you've installed cert-manager correctly by answering a few questions | ||||
|     placeholder: | | ||||
|       - Did you follow https://github.com/actions/actions-runner-controller#installation? If not, describe the installation process so that we can reproduce your environment. | ||||
|       - Are you sure you've installed cert-manager from an official source? | ||||
|       (Note that we won't provide user support for cert-manager itself. Make sure cert-manager is fully working before testing ARC or reporting a bug | ||||
|   validations: | ||||
|     required: true | ||||
| - type: checkboxes | ||||
|   id: checks | ||||
|   attributes: | ||||
|     label: Checks | ||||
|     description: Please check the boxes below before submitting | ||||
|     description: Please check all the boxes below before submitting | ||||
|     options: | ||||
|     - label: This isn't a question or user support case (For Q&A and community support, go to [Discussions](https://github.com/actions-runner-controller/actions-runner-controller/discussions). It might also be a good idea to contract with any of contributors and maintainers if your business is so critical and therefore you need priority support | ||||
|     - label: This isn't a question or user support case (For Q&A and community support, go to [Discussions](https://github.com/actions/actions-runner-controller/discussions). It might also be a good idea to contract with any of contributors and maintainers if your business is so critical and therefore you need priority support | ||||
|       required: true | ||||
|     - label: I've read [releasenotes](https://github.com/actions-runner-controller/actions-runner-controller/tree/master/docs/releasenotes) before submitting this issue and I'm sure it's not due to any recently-introduced backward-incompatible changes | ||||
|     - label: I've read [releasenotes](https://github.com/actions/actions-runner-controller/tree/master/docs/releasenotes) before submitting this issue and I'm sure it's not due to any recently-introduced backward-incompatible changes | ||||
|       required: true | ||||
|     - label: My actions-runner-controller version (v0.x.y) does support the feature | ||||
|       required: true | ||||
|     - label: I've already upgraded ARC to the latest and it didn't fix the issue | ||||
|     - label: I've already upgraded ARC (including the CRDs, see charts/actions-runner-controller/docs/UPGRADING.md for details) to the latest and it didn't fix the issue | ||||
|       required: true | ||||
|     - label: I've migrated to the workflow job webhook event (if you using webhook driven scaling) | ||||
|       required: true | ||||
| - type: textarea | ||||
|   id: resource-definitions | ||||
|  | @ -112,10 +141,12 @@ body: | |||
| - type: textarea | ||||
|   id: controller-logs | ||||
|   attributes: | ||||
|     label: Controller Logs | ||||
|     description: "Include logs from `actions-runner-controller`'s controller-manager pod" | ||||
|     label: Whole Controller Logs | ||||
|     description: "NEVER EVER OMIT THIS! Include logs from `actions-runner-controller`'s controller-manager pod. Don't omit the parts you think irrelevant!" | ||||
|     render: shell | ||||
|     placeholder: | | ||||
|       PROVIDE THE LOGS VIA A GIST LINK (https://gist.github.com/), NOT DIRECTLY IN THIS TEXT AREA | ||||
| 
 | ||||
|       To grab controller logs: | ||||
| 
 | ||||
|       # Set NS according to your setup | ||||
|  | @ -125,17 +156,17 @@ body: | |||
|       kubectl -n $NS get po | ||||
| 
 | ||||
|       kubectl -n $NS logs $POD_NAME > arc.log | ||||
| 
 | ||||
|       Upload it to e.g. https://gist.github.com/ and paste the link to it here. | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|   id: runner-pod-logs | ||||
|   attributes: | ||||
|     label: Runner Pod Logs | ||||
|     description: "Include logs from runner pod(s)" | ||||
|     label: Whole Runner Pod Logs | ||||
|     description: "Include logs from runner pod(s). Please don't omit the parts you think irrelevant!" | ||||
|     render: shell | ||||
|     placeholder: | | ||||
|       PROVIDE THE WHOLE LOGS VIA A GIST LINK (https://gist.github.com/), NOT DIRECTLY IN THIS TEXT AREA | ||||
| 
 | ||||
|       To grab the runner pod logs: | ||||
| 
 | ||||
|       # Set NS according to your setup. It should match your RunnerDeployment's metadata.namespace. | ||||
|  | @ -147,7 +178,7 @@ body: | |||
|       kubectl -n $NS logs $POD_NAME -c runner > runnerpod_runner.log | ||||
|       kubectl -n $NS logs $POD_NAME -c docker > runnerpod_docker.log | ||||
| 
 | ||||
|       Upload it to e.g. https://gist.github.com/ and paste the link to it here. | ||||
|       If any of the containers are getting terminated immediately, try adding `--previous` to the kubectl-logs command to obtain logs emitted before the termination. | ||||
|   validations: | ||||
|     required: true | ||||
| - type: textarea | ||||
|  | @ -0,0 +1,21 @@ | |||
| --- | ||||
| name: Feature request (actions.summerwind.net API group) | ||||
| about: Suggest an idea for this project | ||||
| labels: ["enhancement", "needs triage", "community"] | ||||
| title: '' | ||||
| assignees: '' | ||||
| --- | ||||
| 
 | ||||
| ### What would you like added? | ||||
| 
 | ||||
| *A clear and concise description of what you want to happen.* | ||||
| 
 | ||||
| Note: Feature requests to integrate vendor specific cloud tools (e.g. `awscli`, `gcloud-sdk`, `azure-cli`) will likely be rejected as the Runner image aims to be vendor agnostic. | ||||
| 
 | ||||
| ### Why is this needed? | ||||
| 
 | ||||
| *A clear and concise description of any alternative solutions or features you've considered.* | ||||
| 
 | ||||
| ### Additional context | ||||
| 
 | ||||
| *Add any other context or screenshots about the feature request here.* | ||||
|  | @ -0,0 +1,215 @@ | |||
| name: 'Execute and Assert ARC E2E Test Action' | ||||
| description: 'Queue E2E test workflow and assert workflow run result to be succeed' | ||||
| 
 | ||||
| inputs: | ||||
|   auth-token: | ||||
|     description: 'GitHub access token to queue workflow run' | ||||
|     required: true | ||||
|   repo-owner: | ||||
|     description: "The repository owner name that has the test workflow file, ex: actions" | ||||
|     required: true | ||||
|   repo-name: | ||||
|     description: "The repository name that has the test workflow file, ex: test" | ||||
|     required: true | ||||
|   workflow-file: | ||||
|     description: 'The file name of the workflow yaml, ex: test.yml' | ||||
|     required: true | ||||
|   arc-name: | ||||
|     description: 'The name of the configured gha-runner-scale-set' | ||||
|     required: true | ||||
|   arc-namespace: | ||||
|     description: 'The namespace of the configured gha-runner-scale-set' | ||||
|     required: true | ||||
|   arc-controller-namespace: | ||||
|     description: 'The namespace of the configured gha-runner-scale-set-controller' | ||||
|     required: true | ||||
|   wait-to-finish: | ||||
|     description: 'Wait for the workflow run to finish' | ||||
|     required: true | ||||
|     default: "true" | ||||
|   wait-to-running: | ||||
|     description: 'Wait for the workflow run to start running' | ||||
|     required: true | ||||
|     default: "false" | ||||
| 
 | ||||
| runs: | ||||
|   using: "composite" | ||||
|   steps: | ||||
|     - name: Queue test workflow | ||||
|       shell: bash | ||||
|       id: queue_workflow | ||||
|       run: | | ||||
|         queue_time=`date +%FT%TZ` | ||||
|         echo "queue_time=$queue_time" >> $GITHUB_OUTPUT | ||||
|         curl -X POST https://api.github.com/repos/${{inputs.repo-owner}}/${{inputs.repo-name}}/actions/workflows/${{inputs.workflow-file}}/dispatches \ | ||||
|         -H "Accept: application/vnd.github.v3+json" \ | ||||
|         -H "Authorization: token ${{inputs.auth-token}}" \ | ||||
|         -d '{"ref": "main", "inputs": { "arc_name": "${{inputs.arc-name}}" } }' | ||||
| 
 | ||||
|     - name: Fetch workflow run & job ids | ||||
|       uses: actions/github-script@v7 | ||||
|       id: query_workflow | ||||
|       with: | ||||
|         script: | | ||||
|           // Try to find the workflow run triggered by the previous step using the workflow_dispatch event. | ||||
|           // - Find recently create workflow runs in the test repository | ||||
|           // - For each workflow run, list its workflow job and see if the job's labels contain `inputs.arc-name` | ||||
|           // - Since the inputs.arc-name should be unique per e2e workflow run, once we find the job with the label, we find the workflow that we just triggered. | ||||
|           function sleep(ms) { | ||||
|             return new Promise(resolve => setTimeout(resolve, ms)) | ||||
|           } | ||||
|           const owner = '${{inputs.repo-owner}}' | ||||
|           const repo = '${{inputs.repo-name}}' | ||||
|           const workflow_id = '${{inputs.workflow-file}}' | ||||
|           let workflow_run_id = 0 | ||||
|           let workflow_job_id = 0 | ||||
|           let workflow_run_html_url = "" | ||||
|           let count = 0 | ||||
|           while (count++<12) { | ||||
|             await sleep(10 * 1000); | ||||
|             let listRunResponse = await github.rest.actions.listWorkflowRuns({ | ||||
|               owner: owner, | ||||
|               repo: repo, | ||||
|               workflow_id: workflow_id, | ||||
|               created: '>${{steps.queue_workflow.outputs.queue_time}}' | ||||
|             }) | ||||
|             if (listRunResponse.data.total_count > 0) { | ||||
|               console.log(`Found some new workflow runs for ${workflow_id}`) | ||||
|               for (let i = 0; i<listRunResponse.data.total_count; i++) { | ||||
|                 let workflowRun = listRunResponse.data.workflow_runs[i] | ||||
|                 console.log(`Check if workflow run ${workflowRun.id} is triggered by us.`) | ||||
|                 let listJobResponse = await github.rest.actions.listJobsForWorkflowRun({ | ||||
|                   owner: owner, | ||||
|                   repo: repo, | ||||
|                   run_id: workflowRun.id | ||||
|                 }) | ||||
|                 console.log(`Workflow run ${workflowRun.id} has ${listJobResponse.data.total_count} jobs.`) | ||||
|                 if (listJobResponse.data.total_count > 0) { | ||||
|                   for (let j = 0; j<listJobResponse.data.total_count; j++) { | ||||
|                     let workflowJob = listJobResponse.data.jobs[j] | ||||
|                     console.log(`Check if workflow job ${workflowJob.id} is triggered by us.`) | ||||
|                     console.log(JSON.stringify(workflowJob.labels)); | ||||
|                     if (workflowJob.labels.includes('${{inputs.arc-name}}')) { | ||||
|                       console.log(`Workflow job ${workflowJob.id} (Run id: ${workflowJob.run_id}) is triggered by us.`) | ||||
|                       workflow_run_id = workflowJob.run_id | ||||
|                       workflow_job_id = workflowJob.id | ||||
|                       workflow_run_html_url = workflowRun.html_url | ||||
|                       break | ||||
|                     } | ||||
|                   } | ||||
|                 } | ||||
| 
 | ||||
|                 if (workflow_job_id > 0) { | ||||
|                   break; | ||||
|                 } | ||||
|               } | ||||
|             } | ||||
| 
 | ||||
|             if (workflow_job_id > 0) { | ||||
|               break; | ||||
|             } | ||||
|           } | ||||
|           if (workflow_job_id == 0) { | ||||
|             core.setFailed(`Can't find workflow run and workflow job triggered to 'runs-on ${{inputs.arc-name}}'`) | ||||
|           } else { | ||||
|             core.setOutput('workflow_run', workflow_run_id); | ||||
|             core.setOutput('workflow_job', workflow_job_id); | ||||
|             core.setOutput('workflow_run_url', workflow_run_html_url); | ||||
|           } | ||||
| 
 | ||||
|     - name: Generate summary about the triggered workflow run | ||||
|       shell: bash | ||||
|       run: | | ||||
|         cat <<-EOF > $GITHUB_STEP_SUMMARY | ||||
|         | **Triggered workflow run** | | ||||
|         |:--------------------------:| | ||||
|         | ${{steps.query_workflow.outputs.workflow_run_url}} | | ||||
|         EOF | ||||
| 
 | ||||
|     - name: Wait for workflow to start running | ||||
|       if: inputs.wait-to-running == 'true' && inputs.wait-to-finish == 'false' | ||||
|       uses: actions/github-script@v7 | ||||
|       with: | ||||
|         script: | | ||||
|           function sleep(ms) { | ||||
|             return new Promise(resolve => setTimeout(resolve, ms)) | ||||
|           } | ||||
|           const owner = '${{inputs.repo-owner}}' | ||||
|           const repo = '${{inputs.repo-name}}' | ||||
|           const workflow_run_id = ${{steps.query_workflow.outputs.workflow_run}} | ||||
|           const workflow_job_id = ${{steps.query_workflow.outputs.workflow_job}} | ||||
|           let count = 0 | ||||
|           while (count++<10) { | ||||
|             await sleep(30 * 1000); | ||||
|             let getRunResponse = await github.rest.actions.getWorkflowRun({ | ||||
|               owner: owner, | ||||
|               repo: repo, | ||||
|               run_id: workflow_run_id | ||||
|             }) | ||||
|             console.log(`${getRunResponse.data.html_url}: ${getRunResponse.data.status} (${getRunResponse.data.conclusion})`); | ||||
|             if (getRunResponse.data.status == 'in_progress') { | ||||
|               console.log(`Workflow run is in progress.`) | ||||
|               return | ||||
|             } | ||||
|           } | ||||
|           core.setFailed(`The triggered workflow run didn't start properly using ${{inputs.arc-name}}`) | ||||
| 
 | ||||
|     - name: Wait for workflow to finish successfully | ||||
|       if: inputs.wait-to-finish == 'true' | ||||
|       uses: actions/github-script@v7 | ||||
|       with: | ||||
|         script: | | ||||
|           // Wait 5 minutes and make sure the workflow run we triggered completed with result 'success' | ||||
|           function sleep(ms) { | ||||
|             return new Promise(resolve => setTimeout(resolve, ms)) | ||||
|           } | ||||
|           const owner = '${{inputs.repo-owner}}' | ||||
|           const repo = '${{inputs.repo-name}}' | ||||
|           const workflow_run_id = ${{steps.query_workflow.outputs.workflow_run}} | ||||
|           const workflow_job_id = ${{steps.query_workflow.outputs.workflow_job}} | ||||
|           let count = 0 | ||||
|           while (count++<10) { | ||||
|             await sleep(30 * 1000); | ||||
|             let getRunResponse = await github.rest.actions.getWorkflowRun({ | ||||
|               owner: owner, | ||||
|               repo: repo, | ||||
|               run_id: workflow_run_id | ||||
|             }) | ||||
|             console.log(`${getRunResponse.data.html_url}: ${getRunResponse.data.status} (${getRunResponse.data.conclusion})`); | ||||
|             if (getRunResponse.data.status == 'completed') { | ||||
|               if ( getRunResponse.data.conclusion == 'success') { | ||||
|                 console.log(`Workflow run finished properly.`) | ||||
|                 return | ||||
|               } else { | ||||
|                 core.setFailed(`The triggered workflow run finish with result ${getRunResponse.data.conclusion}`) | ||||
|                 return | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|           core.setFailed(`The triggered workflow run didn't finish properly using ${{inputs.arc-name}}`) | ||||
| 
 | ||||
|     - name: Gather listener logs | ||||
|       shell: bash | ||||
|       if: always() | ||||
|       run: | | ||||
|         LISTENER_POD="$(kubectl get autoscalinglisteners.actions.github.com -n arc-systems -o jsonpath='{.items[*].metadata.name}')" | ||||
|         kubectl logs $LISTENER_POD -n ${{inputs.arc-controller-namespace}} | ||||
|      | ||||
|     - name: Gather coredns logs | ||||
|       shell: bash | ||||
|       if: always() | ||||
|       run: | | ||||
|         kubectl logs deployments/coredns -n kube-system  | ||||
| 
 | ||||
|     - name: cleanup | ||||
|       if: inputs.wait-to-finish == 'true' | ||||
|       shell: bash | ||||
|       run: | | ||||
|         helm uninstall ${{ inputs.arc-name }} --namespace ${{inputs.arc-namespace}} --debug | ||||
|         kubectl wait --timeout=30s --for=delete AutoScalingRunnerSet -n ${{inputs.arc-namespace}} -l app.kubernetes.io/instance=${{ inputs.arc-name }} | ||||
| 
 | ||||
|     - name: Gather controller logs | ||||
|       shell: bash | ||||
|       if: always() | ||||
|       run: | | ||||
|         kubectl logs deployment/arc-gha-rs-controller -n ${{inputs.arc-controller-namespace}} | ||||
|  | @ -0,0 +1,65 @@ | |||
| name: "Setup ARC E2E Test Action" | ||||
| description: "Build controller image, create kind cluster, load the image, and exchange ARC configure token." | ||||
| 
 | ||||
| inputs: | ||||
|   app-id: | ||||
|     description: "GitHub App Id for exchange access token" | ||||
|     required: true | ||||
|   app-pk: | ||||
|     description: "GitHub App private key for exchange access token" | ||||
|     required: true | ||||
|   image-name: | ||||
|     description: "Local docker image name for building" | ||||
|     required: true | ||||
|   image-tag: | ||||
|     description: "Tag of ARC Docker image for building" | ||||
|     required: true | ||||
|   target-org: | ||||
|     description: "The test organization for ARC e2e test" | ||||
|     required: true | ||||
| 
 | ||||
| outputs: | ||||
|   token: | ||||
|     description: "Token to use for configure ARC" | ||||
|     value: ${{steps.config-token.outputs.token}} | ||||
| 
 | ||||
| runs: | ||||
|   using: "composite" | ||||
|   steps: | ||||
|     - name: Set up Docker Buildx | ||||
|       uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 | ||||
|       with: | ||||
|         # Pinning v0.9.1 for Buildx and BuildKit v0.10.6 | ||||
|         # BuildKit v0.11 which has a bug causing intermittent | ||||
|         # failures pushing images to GHCR | ||||
|         version: v0.9.1 | ||||
|         driver-opts: image=moby/buildkit:v0.10.6 | ||||
| 
 | ||||
|     - name: Build controller image | ||||
|       # https://github.com/docker/build-push-action/releases/tag/v6.18.0 | ||||
|       uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 | ||||
|       with: | ||||
|         file: Dockerfile | ||||
|         platforms: linux/amd64 | ||||
|         load: true | ||||
|         build-args: | | ||||
|           DOCKER_IMAGE_NAME=${{inputs.image-name}} | ||||
|           VERSION=${{inputs.image-tag}} | ||||
|         tags: | | ||||
|           ${{inputs.image-name}}:${{inputs.image-tag}} | ||||
|         no-cache: true | ||||
| 
 | ||||
|     - name: Create minikube cluster and load image | ||||
|       shell: bash | ||||
|       run: | | ||||
|         minikube start | ||||
|         minikube image load ${{inputs.image-name}}:${{inputs.image-tag}} | ||||
| 
 | ||||
|     - name: Get configure token | ||||
|       id: config-token | ||||
|       # https://github.com/peter-murray/workflow-application-token-action/releases/tag/v3.0.0 | ||||
|       uses: peter-murray/workflow-application-token-action@dc0413987a085fa17d19df9e47d4677cf81ffef3 | ||||
|       with: | ||||
|         application_id: ${{ inputs.app-id }} | ||||
|         application_private_key: ${{ inputs.app-pk }} | ||||
|         organization: ${{ inputs.target-org}} | ||||
|  | @ -14,36 +14,37 @@ inputs: | |||
|     description: "GHCR password. Usually set from the secrets.GITHUB_TOKEN variable" | ||||
|     required: true | ||||
| 
 | ||||
| outputs: | ||||
|   sha_short: | ||||
|     description: "The short SHA used for image builds" | ||||
|     value: ${{ steps.vars.outputs.sha_short }} | ||||
| 
 | ||||
| runs: | ||||
|   using: "composite" | ||||
|   steps: | ||||
|     - name: Get Short SHA | ||||
|       id: vars | ||||
|       run: | | ||||
|         echo ::set-output name=sha_short::${GITHUB_SHA::7} | ||||
|         echo "sha_short=${GITHUB_SHA::7}" >> $GITHUB_ENV | ||||
|       shell: bash | ||||
| 
 | ||||
|     - name: Set up QEMU | ||||
|       uses: docker/setup-qemu-action@v2 | ||||
|       # https://github.com/docker/setup-qemu-action/releases/tag/v3.6.0 | ||||
|       uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 | ||||
| 
 | ||||
|     - name: Set up Docker Buildx | ||||
|       uses: docker/setup-buildx-action@v2 | ||||
|       # https://github.com/docker/setup-buildx-action/releases/tag/v3.10.0 | ||||
|       uses: docker/setup-buildx-action@b5ca514318bd6ebac0fb2aedd5d36ec1b5c232a2 | ||||
|       with: | ||||
|         version: latest | ||||
| 
 | ||||
|     - name: Login to DockerHub | ||||
|       uses: docker/login-action@v2 | ||||
|       if: ${{ github.event_name == 'release' || github.event_name == 'push' && github.ref == 'refs/heads/master' && inputs.password != ''  }} | ||||
|       # https://github.com/docker/login-action/releases/tag/v3.4.0 | ||||
|       uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 | ||||
|       with: | ||||
|         username: ${{ inputs.username }} | ||||
|         password: ${{ inputs.password }} | ||||
| 
 | ||||
|     - name: Login to GitHub Container Registry | ||||
|       uses: docker/login-action@v2 | ||||
|       if: ${{ github.event_name == 'release' || github.event_name == 'push' && github.ref == 'refs/heads/master' && inputs.ghcr_password != ''  }} | ||||
|       # https://github.com/docker/login-action/releases/tag/v3.4.0 | ||||
|       uses: docker/login-action@74a5d142397b4f367a81961eba4e8cd7edddf772 | ||||
|       with: | ||||
|         registry: ghcr.io | ||||
|         username: ${{ inputs.ghcr_username }} | ||||
|  |  | |||
|  | @ -0,0 +1,23 @@ | |||
| # To get started with Dependabot version updates, you'll need to specify which | ||||
| # package ecosystems to update and where the package manifests are located. | ||||
| # Please see the documentation for all configuration options: | ||||
| # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates | ||||
| 
 | ||||
| version: 2 | ||||
| updates: | ||||
|   - package-ecosystem: "gomod" # See documentation for possible values | ||||
|     directory: "/" # Location of package manifests | ||||
|     schedule: | ||||
|       interval: "weekly" | ||||
|     groups: | ||||
|       gomod: | ||||
|         patterns: | ||||
|           - "*" | ||||
|   - package-ecosystem: github-actions | ||||
|     directory: "/" | ||||
|     schedule: | ||||
|       interval: "weekly" | ||||
|     groups: | ||||
|       actions: | ||||
|         patterns: | ||||
|           - "*" | ||||
|  | @ -1,41 +0,0 @@ | |||
| { | ||||
|   "extends": ["config:base"], | ||||
|   "labels": ["dependencies"], | ||||
|   "packageRules": [ | ||||
|     { | ||||
|       // automatically merge an update of runner | ||||
|       "matchPackageNames": ["actions/runner"], | ||||
|       "extractVersion": "^v(?<version>.*)$", | ||||
|       "automerge": true | ||||
|     } | ||||
|   ], | ||||
|   "regexManagers": [ | ||||
|     { | ||||
|       // use https://github.com/actions/runner/releases | ||||
|       "fileMatch": [ | ||||
|         ".github/workflows/runners.yaml" | ||||
|       ], | ||||
|       "matchStrings": ["RUNNER_VERSION: +(?<currentValue>.*?)\\n"], | ||||
|       "depNameTemplate": "actions/runner", | ||||
|       "datasourceTemplate": "github-releases" | ||||
|     }, | ||||
|     { | ||||
|       "fileMatch": [ | ||||
|         "runner/Makefile", | ||||
|         "Makefile" | ||||
|       ], | ||||
|       "matchStrings": ["RUNNER_VERSION \\?= +(?<currentValue>.*?)\\n"], | ||||
|       "depNameTemplate": "actions/runner", | ||||
|       "datasourceTemplate": "github-releases" | ||||
|     }, | ||||
|     { | ||||
|       "fileMatch": [ | ||||
|         "runner/actions-runner.dockerfile", | ||||
|         "runner/actions-runner-dind.dockerfile" | ||||
|       ], | ||||
|       "matchStrings": ["RUNNER_VERSION=+(?<currentValue>.*?)\\n"], | ||||
|       "depNameTemplate": "actions/runner", | ||||
|       "datasourceTemplate": "github-releases" | ||||
|     } | ||||
|   ] | ||||
| } | ||||
|  | @ -0,0 +1,212 @@ | |||
| name: Publish ARC Helm Charts | ||||
| 
 | ||||
| # Revert to https://github.com/actions-runner-controller/releases#releases | ||||
| # for details on why we use this approach | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|     paths: | ||||
|       - "charts/**" | ||||
|       - ".github/workflows/arc-publish-chart.yaml" | ||||
|       - "!charts/actions-runner-controller/docs/**" | ||||
|       - "!charts/gha-runner-scale-set-controller/**" | ||||
|       - "!charts/gha-runner-scale-set/**" | ||||
|       - "!**.md" | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       force: | ||||
|         description: "Force publish even if the chart version is not bumped" | ||||
|         type: boolean | ||||
|         required: true | ||||
|         default: false | ||||
| 
 | ||||
| env: | ||||
|   KUBE_SCORE_VERSION: 1.10.0 | ||||
|   HELM_VERSION: v3.8.0 | ||||
| 
 | ||||
| permissions: | ||||
|   contents: write | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   lint-chart: | ||||
|     name: Lint Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     outputs: | ||||
|       publish-chart: ${{ steps.publish-chart-step.outputs.publish }} | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       - name: Set up kube-score | ||||
|         run: | | ||||
|           wget https://github.com/zegl/kube-score/releases/download/v${{ env.KUBE_SCORE_VERSION }}/kube-score_${{ env.KUBE_SCORE_VERSION }}_linux_amd64 -O kube-score | ||||
|           chmod 755 kube-score | ||||
| 
 | ||||
|       - name: Kube-score generated manifests | ||||
|         run: helm template  --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score - --ignore-test pod-networkpolicy --ignore-test deployment-has-poddisruptionbudget --ignore-test deployment-has-host-podantiaffinity --ignore-test container-security-context --ignore-test pod-probes --ignore-test container-image-tag --enable-optional-test container-security-context-privileged --enable-optional-test container-security-context-readonlyrootfilesystem | ||||
| 
 | ||||
|       # python is a requirement for the chart-testing action below (supports yamllint among other tests) | ||||
|       - uses: actions/setup-python@v6 | ||||
|         with: | ||||
|           python-version: "3.11" | ||||
| 
 | ||||
|       - name: Set up chart-testing | ||||
|         uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b | ||||
| 
 | ||||
|       - name: Run chart-testing (list-changed) | ||||
|         id: list-changed | ||||
|         run: | | ||||
|           changed=$(ct list-changed --config charts/.ci/ct-config.yaml) | ||||
|           if [[ -n "$changed" ]]; then | ||||
|             echo "changed=true" >> $GITHUB_OUTPUT | ||||
|           fi | ||||
| 
 | ||||
|       - name: Run chart-testing (lint) | ||||
|         run: | | ||||
|           ct lint --config charts/.ci/ct-config.yaml | ||||
| 
 | ||||
|       - name: Create kind cluster | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 | ||||
| 
 | ||||
|       # We need cert-manager already installed in the cluster because we assume the CRDs exist | ||||
|       - name: Install cert-manager | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: | | ||||
|           helm repo add jetstack https://charts.jetstack.io --force-update | ||||
|           helm install cert-manager jetstack/cert-manager --set installCRDs=true --wait | ||||
| 
 | ||||
|       - name: Run chart-testing (install) | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: ct install --config charts/.ci/ct-config.yaml | ||||
| 
 | ||||
|       # WARNING: This relies on the latest release being at the top of the JSON from GitHub and a clean chart.yaml | ||||
|       - name: Check if Chart Publish is Needed | ||||
|         id: publish-chart-step | ||||
|         run: | | ||||
|           CHART_TEXT=$(curl -fs https://raw.githubusercontent.com/${{ github.repository }}/master/charts/actions-runner-controller/Chart.yaml) | ||||
|           NEW_CHART_VERSION=$(echo "$CHART_TEXT" | grep version: | cut -d ' ' -f 2) | ||||
|           RELEASE_LIST=$(curl -fs https://api.github.com/repos/${{ github.repository }}/releases  | jq .[].tag_name | grep actions-runner-controller | cut -d '"' -f 2 | cut -d '-' -f 4) | ||||
|           LATEST_RELEASED_CHART_VERSION=$(echo $RELEASE_LIST | cut -d ' ' -f 1) | ||||
| 
 | ||||
|           echo "CHART_VERSION_IN_MASTER=$NEW_CHART_VERSION" >> $GITHUB_ENV | ||||
|           echo "LATEST_CHART_VERSION=$LATEST_RELEASED_CHART_VERSION" >> $GITHUB_ENV | ||||
| 
 | ||||
|           # Always publish if force is true | ||||
|           if [[ $NEW_CHART_VERSION != $LATEST_RELEASED_CHART_VERSION || "${{ inputs.force }}" == "true" ]]; then | ||||
|             echo "publish=true" >> $GITHUB_OUTPUT | ||||
|           else | ||||
|             echo "publish=false" >> $GITHUB_OUTPUT | ||||
|           fi | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "Chart linting has been completed." >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Status:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- chart version in master: ${{ env.CHART_VERSION_IN_MASTER }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- latest chart version: ${{ env.LATEST_CHART_VERSION }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- publish new chart: ${{ steps.publish-chart-step.outputs.publish }}" >> $GITHUB_STEP_SUMMARY | ||||
| 
 | ||||
|   publish-chart: | ||||
|     if: needs.lint-chart.outputs.publish-chart == 'true' | ||||
|     needs: lint-chart | ||||
|     name: Publish Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: write # for helm/chart-releaser-action to push chart release and create a release | ||||
|     env: | ||||
|       CHART_TARGET_ORG: actions-runner-controller | ||||
|       CHART_TARGET_REPO: actions-runner-controller.github.io | ||||
|       CHART_TARGET_BRANCH: master | ||||
| 
 | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Configure Git | ||||
|         run: | | ||||
|           git config user.name "$GITHUB_ACTOR" | ||||
|           git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||||
| 
 | ||||
|       - name: Get Token | ||||
|         id: get_workflow_token | ||||
|         uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343 | ||||
|         with: | ||||
|           application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} | ||||
|           application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} | ||||
|           organization: ${{ env.CHART_TARGET_ORG }} | ||||
| 
 | ||||
|       - name: Install chart-releaser | ||||
|         uses: helm/chart-releaser-action@cae68fefc6b5f367a0275617c9f83181ba54714f | ||||
|         with: | ||||
|           install_only: true | ||||
|           install_dir: ${{ github.workspace }}/bin | ||||
| 
 | ||||
|       - name: Package and upload release assets | ||||
|         run: | | ||||
|           cr package \ | ||||
|             ${{ github.workspace }}/charts/actions-runner-controller/ \ | ||||
|             --package-path .cr-release-packages | ||||
| 
 | ||||
|           cr upload \ | ||||
|             --owner "$(echo ${{ github.repository }} | cut -d '/' -f 1)" \ | ||||
|             --git-repo "$(echo ${{ github.repository }} | cut -d '/' -f 2)" \ | ||||
|             --package-path .cr-release-packages \ | ||||
|             --token ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       - name: Generate updated index.yaml | ||||
|         run: | | ||||
|           cr index \ | ||||
|             --owner "$(echo ${{ github.repository }} | cut -d '/' -f 1)" \ | ||||
|             --git-repo "$(echo ${{ github.repository }} | cut -d '/' -f 2)" \ | ||||
|             --index-path ${{ github.workspace }}/index.yaml \ | ||||
|             --token ${{ secrets.GITHUB_TOKEN }} \ | ||||
|             --push \ | ||||
|             --pages-branch 'gh-pages' \ | ||||
|             --pages-index-path 'index.yaml' | ||||
| 
 | ||||
|       # Chart Release was never intended to publish to a different repo | ||||
|       # this workaround is intended to move the index.yaml to the target repo | ||||
|       # where the github pages are hosted | ||||
|       - name: Checkout target repository | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           repository: ${{ env.CHART_TARGET_ORG }}/${{ env.CHART_TARGET_REPO }} | ||||
|           path: ${{ env.CHART_TARGET_REPO }} | ||||
|           ref: ${{ env.CHART_TARGET_BRANCH }} | ||||
|           token: ${{ steps.get_workflow_token.outputs.token }} | ||||
| 
 | ||||
|       - name: Copy index.yaml | ||||
|         run: | | ||||
|           cp ${{ github.workspace }}/index.yaml ${{ env.CHART_TARGET_REPO }}/actions-runner-controller/index.yaml | ||||
| 
 | ||||
|       - name: Commit and push to target repository | ||||
|         run: | | ||||
|           git config user.name "$GITHUB_ACTOR" | ||||
|           git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||||
|           git add . | ||||
|           git commit -m "Update index.yaml" | ||||
|           git push | ||||
|         working-directory: ${{ github.workspace }}/${{ env.CHART_TARGET_REPO }} | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "New helm chart has been published" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Status:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- New [index.yaml](https://github.com/${{ env.CHART_TARGET_ORG }}/${{ env.CHART_TARGET_REPO }}/tree/master/actions-runner-controller) pushed" >> $GITHUB_STEP_SUMMARY | ||||
|  | @ -0,0 +1,109 @@ | |||
| name: Publish ARC Image | ||||
| 
 | ||||
| # Revert to https://github.com/actions-runner-controller/releases#releases | ||||
| # for details on why we use this approach | ||||
| on: | ||||
|   release: | ||||
|     types: | ||||
|       - published | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       release_tag_name: | ||||
|         description: "Tag name of the release to publish" | ||||
|         required: true | ||||
|       push_to_registries: | ||||
|         description: "Push images to registries" | ||||
|         required: true | ||||
|         type: boolean | ||||
|         default: false | ||||
| 
 | ||||
| permissions: | ||||
|   contents: write | ||||
|   packages: write | ||||
| 
 | ||||
| env: | ||||
|   TARGET_ORG: actions-runner-controller | ||||
|   TARGET_REPO: actions-runner-controller | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   release-controller: | ||||
|     name: Release | ||||
|     runs-on: ubuntu-latest | ||||
|     # gha-runner-scale-set has its own release workflow. | ||||
|     # We don't want to publish a new actions-runner-controller image | ||||
|     # we release gha-runner-scale-set. | ||||
|     if: ${{ !startsWith(github.event.inputs.release_tag_name, 'gha-runner-scale-set-') }} | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
| 
 | ||||
|       - name: Install tools | ||||
|         run: | | ||||
|           curl -L -O https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz | ||||
|           tar zxvf kubebuilder_2.2.0_linux_amd64.tar.gz | ||||
|           sudo mv kubebuilder_2.2.0_linux_amd64 /usr/local/kubebuilder | ||||
|           curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash | ||||
|           sudo mv kustomize /usr/local/bin | ||||
|           curl -L -O https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz | ||||
|           tar zxvf ghr_v0.13.0_linux_amd64.tar.gz | ||||
|           sudo mv ghr_v0.13.0_linux_amd64/ghr /usr/local/bin | ||||
| 
 | ||||
|       - name: Set version env variable | ||||
|         run: | | ||||
|           # Define the release tag name based on the event type | ||||
|           if [[ "${{ github.event_name }}" == "release" ]]; then | ||||
|             echo "VERSION=$(cat ${GITHUB_EVENT_PATH} | jq -r '.release.tag_name')" >> $GITHUB_ENV | ||||
|           elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | ||||
|             echo "VERSION=${{ inputs.release_tag_name }}" >> $GITHUB_ENV | ||||
|           fi | ||||
| 
 | ||||
|       - name: Upload artifacts | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         run: | | ||||
|           make github-release | ||||
| 
 | ||||
|       - name: Get Token | ||||
|         id: get_workflow_token | ||||
|         uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343 | ||||
|         with: | ||||
|           application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} | ||||
|           application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} | ||||
|           organization: ${{ env.TARGET_ORG }} | ||||
| 
 | ||||
|       - name: Resolve push to registries | ||||
|         run: | | ||||
|           # Define the push to registries based on the event type | ||||
|           if [[ "${{ github.event_name }}" == "release" ]]; then | ||||
|             echo "PUSH_TO_REGISTRIES=true" >> $GITHUB_ENV | ||||
|           elif [[ "${{ github.event_name }}" == "workflow_dispatch" ]]; then | ||||
|             echo "PUSH_TO_REGISTRIES=${{ inputs.push_to_registries }}" >> $GITHUB_ENV | ||||
|           fi | ||||
| 
 | ||||
|       - name: Trigger Build And Push Images To Registries | ||||
|         run: | | ||||
|           # Authenticate | ||||
|           gh auth login --with-token <<< ${{ steps.get_workflow_token.outputs.token }} | ||||
| 
 | ||||
|           # Trigger the workflow run | ||||
|           jq -n '{"event_type": "arc", "client_payload": {"release_tag_name": "${{ env.VERSION }}", "push_to_registries": "${{ env.PUSH_TO_REGISTRIES }}" }}' \ | ||||
|             | gh api -X POST /repos/actions-runner-controller/releases/dispatches --input - | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "The [publish-arc](https://github.com/actions-runner-controller/releases/blob/main/.github/workflows/publish-arc.yaml) workflow has been triggered!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Release tag: ${{ env.VERSION }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Push to registries: ${{ env.PUSH_TO_REGISTRIES }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Status:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "[https://github.com/actions-runner-controller/releases/actions/workflows/publish-arc.yaml](https://github.com/actions-runner-controller/releases/actions/workflows/publish-arc.yaml)" >> $GITHUB_STEP_SUMMARY | ||||
|  | @ -0,0 +1,81 @@ | |||
| name: Release ARC Runner Images | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| # Revert to https://github.com/actions-runner-controller/releases#releases | ||||
| # for details on why we use this approach | ||||
| on: | ||||
|   # We must do a trigger on a push: instead of a types: closed so GitHub Secrets | ||||
|   # are available to the workflow run | ||||
|   push: | ||||
|     branches: | ||||
|       - "master" | ||||
|     paths: | ||||
|       - "runner/VERSION" | ||||
|       - ".github/workflows/arc-release-runners.yaml" | ||||
| 
 | ||||
| env: | ||||
|   # Safeguard to prevent pushing images to registeries after build | ||||
|   PUSH_TO_REGISTRIES: true | ||||
|   TARGET_ORG: actions-runner-controller | ||||
|   TARGET_WORKFLOW: release-runners.yaml | ||||
|   DOCKER_VERSION: 24.0.7 | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   build-runners: | ||||
|     name: Trigger Build and Push of Runner Images | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - name: Get runner version | ||||
|         id: versions | ||||
|         run: | | ||||
|           runner_current_version="$(echo -n $(cat runner/VERSION | grep 'RUNNER_VERSION=' | cut -d '=' -f2))" | ||||
|           container_hooks_current_version="$(echo -n $(cat runner/VERSION | grep 'RUNNER_CONTAINER_HOOKS_VERSION=' | cut -d '=' -f2))" | ||||
|           echo runner_version=$runner_current_version >> $GITHUB_OUTPUT | ||||
|           echo container_hooks_version=$container_hooks_current_version >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Get Token | ||||
|         id: get_workflow_token | ||||
|         uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343 | ||||
|         with: | ||||
|           application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} | ||||
|           application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} | ||||
|           organization: ${{ env.TARGET_ORG }} | ||||
| 
 | ||||
|       - name: Trigger Build And Push Runner Images To Registries | ||||
|         env: | ||||
|           RUNNER_VERSION: ${{ steps.versions.outputs.runner_version }} | ||||
|           CONTAINER_HOOKS_VERSION: ${{ steps.versions.outputs.container_hooks_version }} | ||||
|         run: | | ||||
|           # Authenticate | ||||
|           gh auth login --with-token <<< ${{ steps.get_workflow_token.outputs.token }} | ||||
| 
 | ||||
|           # Trigger the workflow run | ||||
|           gh workflow run ${{ env.TARGET_WORKFLOW }} -R ${{ env.TARGET_ORG }}/releases \ | ||||
|             -f runner_version=${{ env.RUNNER_VERSION }} \ | ||||
|             -f docker_version=${{ env.DOCKER_VERSION }} \ | ||||
|             -f runner_container_hooks_version=${{ env.CONTAINER_HOOKS_VERSION }} \ | ||||
|             -f sha='${{ github.sha }}' \ | ||||
|             -f push_to_registries=${{ env.PUSH_TO_REGISTRIES }} | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         env: | ||||
|           RUNNER_VERSION: ${{ steps.versions.outputs.runner_version }} | ||||
|           CONTAINER_HOOKS_VERSION: ${{ steps.versions.outputs.container_hooks_version }} | ||||
|         run: | | ||||
|           echo "The [release-runners.yaml](https://github.com/actions-runner-controller/releases/blob/main/.github/workflows/release-runners.yaml) workflow has been triggered!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- runner_version: ${{ env.RUNNER_VERSION }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- docker_version: ${{ env.DOCKER_VERSION }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- runner_container_hooks_version: ${{ env.CONTAINER_HOOKS_VERSION }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- sha: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- push_to_registries: ${{ env.PUSH_TO_REGISTRIES }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Status:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "[https://github.com/actions-runner-controller/releases/actions/workflows/release-runners.yaml](https://github.com/actions-runner-controller/releases/actions/workflows/release-runners.yaml)" >> $GITHUB_STEP_SUMMARY | ||||
|  | @ -0,0 +1,158 @@ | |||
| # This workflows polls releases from actions/runner and in case of a new one it | ||||
| # updates files containing runner version and opens a pull request. | ||||
| name: Runner Updates Check (Scheduled Job) | ||||
| permissions: | ||||
|   pull-requests: write | ||||
|   contents: write | ||||
| 
 | ||||
| on: | ||||
|   schedule: | ||||
|     # run daily | ||||
|     - cron: "0 9 * * *" | ||||
|   workflow_dispatch: | ||||
| 
 | ||||
| jobs: | ||||
|   # check_versions compares our current version and the latest available runner | ||||
|   # version and sets them as outputs. | ||||
|   check_versions: | ||||
|     runs-on: ubuntu-latest | ||||
|     env: | ||||
|       GH_TOKEN: ${{ github.token }} | ||||
|     outputs: | ||||
|       runner_current_version: ${{ steps.runner_versions.outputs.runner_current_version }} | ||||
|       runner_latest_version: ${{ steps.runner_versions.outputs.runner_latest_version }} | ||||
|       container_hooks_current_version: ${{ steps.container_hooks_versions.outputs.container_hooks_current_version }} | ||||
|       container_hooks_latest_version: ${{ steps.container_hooks_versions.outputs.container_hooks_latest_version }} | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: Get runner current and latest versions | ||||
|         id: runner_versions | ||||
|         run: | | ||||
|           CURRENT_VERSION="$(echo -n $(cat runner/VERSION | grep 'RUNNER_VERSION=' | cut -d '=' -f2))" | ||||
|           echo "Current version: $CURRENT_VERSION" | ||||
|           echo runner_current_version=$CURRENT_VERSION >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|           LATEST_VERSION=$(gh release list --exclude-drafts --exclude-pre-releases --limit 1 -R actions/runner | grep -oP '(?<=v)[0-9.]+' | head -1) | ||||
|           echo "Latest version: $LATEST_VERSION" | ||||
|           echo runner_latest_version=$LATEST_VERSION >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Get container-hooks current and latest versions | ||||
|         id: container_hooks_versions | ||||
|         run: | | ||||
|           CURRENT_VERSION="$(echo -n $(cat runner/VERSION | grep 'RUNNER_CONTAINER_HOOKS_VERSION=' | cut -d '=' -f2))" | ||||
|           echo "Current version: $CURRENT_VERSION" | ||||
|           echo container_hooks_current_version=$CURRENT_VERSION >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|           LATEST_VERSION=$(gh release list --exclude-drafts --exclude-pre-releases --limit 1 -R actions/runner-container-hooks | grep -oP '(?<=v)[0-9.]+' | head -1) | ||||
|           echo "Latest version: $LATEST_VERSION" | ||||
|           echo container_hooks_latest_version=$LATEST_VERSION >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|   # check_pr checks if a PR for the same update already exists. It only runs if | ||||
|   # runner latest version != our current version. If no existing PR is found, | ||||
|   # it sets a PR name as output. | ||||
|   check_pr: | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: read | ||||
|     needs: check_versions | ||||
|     if: needs.check_versions.outputs.runner_current_version != needs.check_versions.outputs.runner_latest_version || needs.check_versions.outputs.container_hooks_current_version != needs.check_versions.outputs.container_hooks_latest_version | ||||
|     outputs: | ||||
|       pr_name: ${{ steps.pr_name.outputs.pr_name }} | ||||
|     env: | ||||
|       GH_TOKEN: ${{ github.token }} | ||||
|     steps: | ||||
|       - name: debug | ||||
|         run: | ||||
|           echo "RUNNER_CURRENT_VERSION=${{ needs.check_versions.outputs.runner_current_version }}" | ||||
|           echo "RUNNER_LATEST_VERSION=${{ needs.check_versions.outputs.runner_latest_version }}" | ||||
|           echo "CONTAINER_HOOKS_CURRENT_VERSION=${{ needs.check_versions.outputs.container_hooks_current_version }}" | ||||
|           echo "CONTAINER_HOOKS_LATEST_VERSION=${{ needs.check_versions.outputs.container_hooks_latest_version }}" | ||||
| 
 | ||||
|       - uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: PR Name | ||||
|         id: pr_name | ||||
|         env: | ||||
|           RUNNER_CURRENT_VERSION: ${{ needs.check_versions.outputs.runner_current_version }} | ||||
|           RUNNER_LATEST_VERSION: ${{ needs.check_versions.outputs.runner_latest_version }} | ||||
|           CONTAINER_HOOKS_CURRENT_VERSION: ${{ needs.check_versions.outputs.container_hooks_current_version }} | ||||
|           CONTAINER_HOOKS_LATEST_VERSION: ${{ needs.check_versions.outputs.container_hooks_latest_version }} | ||||
|         # Generate a PR name with the following title: | ||||
|         # Updates: runner to v2.304.0 and container-hooks to v0.3.1 | ||||
|         run: | | ||||
|           RUNNER_MESSAGE="runner to v${RUNNER_LATEST_VERSION}" | ||||
|           CONTAINER_HOOKS_MESSAGE="container-hooks to v${CONTAINER_HOOKS_LATEST_VERSION}" | ||||
| 
 | ||||
|           PR_NAME="Updates:" | ||||
|           if [ "$RUNNER_CURRENT_VERSION" != "$RUNNER_LATEST_VERSION" ] | ||||
|           then | ||||
|             PR_NAME="$PR_NAME $RUNNER_MESSAGE" | ||||
|           fi | ||||
|           if [ "$CONTAINER_HOOKS_CURRENT_VERSION" != "$CONTAINER_HOOKS_LATEST_VERSION" ] | ||||
|           then | ||||
|             PR_NAME="$PR_NAME $CONTAINER_HOOKS_MESSAGE" | ||||
|           fi | ||||
| 
 | ||||
|           result=$(gh pr list --search "$PR_NAME" --json number --jq ".[].number" --limit 1) | ||||
|           if [ -z "$result" ] | ||||
|           then | ||||
|             echo "No existing PRs found, setting output with pr_name=$PR_NAME" | ||||
|             echo pr_name=$PR_NAME >> $GITHUB_OUTPUT | ||||
|           else | ||||
|             echo "Found a PR with title '$PR_NAME' already existing: ${{ github.server_url }}/${{ github.repository }}/pull/$result" | ||||
|           fi | ||||
| 
 | ||||
|   # update_version updates runner version in the files listed below, commits | ||||
|   # the changes and opens a pull request as `github-actions` bot. | ||||
|   update_version: | ||||
|     runs-on: ubuntu-latest | ||||
|     needs: | ||||
|       - check_versions | ||||
|       - check_pr | ||||
|     if: needs.check_pr.outputs.pr_name | ||||
|     permissions: | ||||
|       pull-requests: write | ||||
|       contents: write | ||||
|       actions: write | ||||
|     env: | ||||
|       GH_TOKEN: ${{ github.token }} | ||||
|       RUNNER_CURRENT_VERSION: ${{ needs.check_versions.outputs.runner_current_version }} | ||||
|       RUNNER_LATEST_VERSION: ${{ needs.check_versions.outputs.runner_latest_version }} | ||||
|       CONTAINER_HOOKS_CURRENT_VERSION: ${{ needs.check_versions.outputs.container_hooks_current_version }} | ||||
|       CONTAINER_HOOKS_LATEST_VERSION: ${{ needs.check_versions.outputs.container_hooks_latest_version }} | ||||
|       PR_NAME: ${{ needs.check_pr.outputs.pr_name }} | ||||
| 
 | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: New branch | ||||
|         run: git checkout -b update-runner-"$(date +%Y-%m-%d)" | ||||
| 
 | ||||
|       - name: Update files | ||||
|         run: | | ||||
|           CURRENT_VERSION="${RUNNER_CURRENT_VERSION//./\\.}" | ||||
|           LATEST_VERSION="${RUNNER_LATEST_VERSION//./\\.}" | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" runner/VERSION | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" runner/Makefile | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" Makefile | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" test/e2e/e2e_test.go | ||||
| 
 | ||||
|           CURRENT_VERSION="${CONTAINER_HOOKS_CURRENT_VERSION//./\\.}" | ||||
|           LATEST_VERSION="${CONTAINER_HOOKS_LATEST_VERSION//./\\.}" | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" runner/VERSION | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" runner/Makefile | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" Makefile | ||||
|           sed -i "s/$CURRENT_VERSION/$LATEST_VERSION/g" test/e2e/e2e_test.go | ||||
| 
 | ||||
|       - name: Commit changes | ||||
|         run: | | ||||
|           # from https://github.com/orgs/community/discussions/26560 | ||||
|           git config user.email "41898282+github-actions[bot]@users.noreply.github.com" | ||||
|           git config user.name "github-actions[bot]" | ||||
|           git add . | ||||
|           git commit -m "$PR_NAME" | ||||
|           git push -u origin HEAD | ||||
| 
 | ||||
|       - name: Create pull request | ||||
|         run: gh pr create -f -l "runners update" | ||||
|  | @ -1,12 +1,24 @@ | |||
| name: Validate Helm Chart | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|     paths: | ||||
|       - "charts/**" | ||||
|       - ".github/workflows/arc-validate-chart.yaml" | ||||
|       - "!charts/actions-runner-controller/docs/**" | ||||
|       - "!**.md" | ||||
|       - "!charts/gha-runner-scale-set-controller/**" | ||||
|       - "!charts/gha-runner-scale-set/**" | ||||
|   push: | ||||
|     paths: | ||||
|       - 'charts/**' | ||||
|       - '.github/workflows/validate-chart.yaml' | ||||
|       - '!charts/actions-runner-controller/docs/**' | ||||
|       - '!**.md' | ||||
|       - "charts/**" | ||||
|       - ".github/workflows/arc-validate-chart.yaml" | ||||
|       - "!charts/actions-runner-controller/docs/**" | ||||
|       - "!**.md" | ||||
|       - "!charts/gha-runner-scale-set-controller/**" | ||||
|       - "!charts/gha-runner-scale-set/**" | ||||
|   workflow_dispatch: | ||||
| env: | ||||
|   KUBE_SCORE_VERSION: 1.10.0 | ||||
|  | @ -15,51 +27,42 @@ env: | |||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   validate-chart: | ||||
|     name: Lint Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@v2.1 | ||||
|         uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       - name: Set up kube-score | ||||
|         run: | | ||||
|           wget https://github.com/zegl/kube-score/releases/download/v${{ env.KUBE_SCORE_VERSION }}/kube-score_${{ env.KUBE_SCORE_VERSION }}_linux_amd64 -O kube-score | ||||
|           chmod 755 kube-score | ||||
| 
 | ||||
|       - name: Kube-score generated manifests | ||||
|         run: helm template  --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score - | ||||
|               --ignore-test pod-networkpolicy | ||||
|               --ignore-test deployment-has-poddisruptionbudget | ||||
|               --ignore-test deployment-has-host-podantiaffinity | ||||
|               --ignore-test container-security-context | ||||
|               --ignore-test pod-probes | ||||
|               --ignore-test container-image-tag | ||||
|               --enable-optional-test container-security-context-privileged | ||||
|               --enable-optional-test container-security-context-readonlyrootfilesystem | ||||
| 
 | ||||
|       # python is a requirement for the chart-testing action below (supports yamllint among other tests) | ||||
|       - uses: actions/setup-python@v4 | ||||
|       - uses: actions/setup-python@v6 | ||||
|         with: | ||||
|           python-version: '3.7' | ||||
|           python-version: "3.11" | ||||
| 
 | ||||
|       - name: Set up chart-testing | ||||
|         uses: helm/chart-testing-action@v2.2.1 | ||||
|         uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b | ||||
| 
 | ||||
|       - name: Run chart-testing (list-changed) | ||||
|         id: list-changed | ||||
|         run: | | ||||
|           changed=$(ct list-changed --config charts/.ci/ct-config.yaml) | ||||
|           if [[ -n "$changed" ]]; then | ||||
|             echo "::set-output name=changed::true" | ||||
|             echo "changed=true" >> $GITHUB_OUTPUT | ||||
|           fi | ||||
| 
 | ||||
|       - name: Run chart-testing (lint) | ||||
|  | @ -67,7 +70,7 @@ jobs: | |||
|           ct lint --config charts/.ci/ct-config.yaml | ||||
| 
 | ||||
|       - name: Create kind cluster | ||||
|         uses: helm/kind-action@v1.2.0 | ||||
|         uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
| 
 | ||||
|       # We need cert-manager already installed in the cluster because we assume the CRDs exist | ||||
|  | @ -78,5 +81,6 @@ jobs: | |||
|           helm install cert-manager jetstack/cert-manager --set installCRDs=true --wait | ||||
| 
 | ||||
|       - name: Run chart-testing (install) | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: | | ||||
|           ct install --config charts/.ci/ct-config.yaml | ||||
|  | @ -0,0 +1,40 @@ | |||
| name: Validate ARC Runners | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - "**" | ||||
|     paths: | ||||
|       - "runner/**" | ||||
|       - "test/startup/**" | ||||
|       - "!**.md" | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   shellcheck: | ||||
|     name: runner / shellcheck | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - name: "Run shellcheck" | ||||
|         run: make shellcheck | ||||
| 
 | ||||
|   test-runner-entrypoint: | ||||
|     name: Test entrypoint | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: Run tests | ||||
|         run: | | ||||
|           make acceptance/runner/startup | ||||
|  | @ -0,0 +1,993 @@ | |||
| name: (gha) E2E Tests | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|   workflow_dispatch: | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| env: | ||||
|   TARGET_ORG: actions-runner-controller | ||||
|   TARGET_REPO: arc_e2e_test_dummy | ||||
|   IMAGE_NAME: "arc-test-image" | ||||
|   IMAGE_VERSION: "0.13.0" | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   default-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   single-namespace-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           kubectl create namespace arc-runners | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           --set flags.watchSingleNamespace=arc-runners \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   dind-mode-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: arc-test-dind-workflow.yaml | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set containerMode.type="dind" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   kubernetes-mode-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-kubernetes-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           echo "Install openebs/dynamic-localpv-provisioner" | ||||
|           helm repo add openebs https://openebs.github.io/charts | ||||
|           helm repo update | ||||
|           helm install openebs openebs/openebs -n openebs --create-namespace | ||||
| 
 | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n openebs -l name=openebs-localpv-provisioner | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set containerMode.type="kubernetes" \ | ||||
|           --set containerMode.kubernetesModeWorkVolumeClaim.accessModes={"ReadWriteOnce"} \ | ||||
|           --set containerMode.kubernetesModeWorkVolumeClaim.storageClassName="openebs-hostpath" \ | ||||
|           --set containerMode.kubernetesModeWorkVolumeClaim.resources.requests.storage="1Gi" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   auth-proxy-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           docker run -d \ | ||||
|             --name squid \ | ||||
|             --publish 3128:3128 \ | ||||
|             huangtingluo/squid-proxy:latest | ||||
|           kubectl create namespace arc-runners | ||||
|           kubectl create secret generic proxy-auth \ | ||||
|             --namespace=arc-runners \ | ||||
|             --from-literal=username=github \ | ||||
|             --from-literal=password='actions' | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set proxy.https.url="http://host.minikube.internal:3128" \ | ||||
|           --set proxy.https.credentialSecretRef="proxy-auth" \ | ||||
|           --set "proxy.noProxy[0]=10.96.0.1:443" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   anonymous-proxy-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           docker run -d \ | ||||
|             --name squid \ | ||||
|             --publish 3128:3128 \ | ||||
|             ubuntu/squid:latest | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set proxy.https.url="http://host.minikube.internal:3128" \ | ||||
|           --set "proxy.noProxy[0]=10.96.0.1:443" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   self-signed-ca-setup: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-workflow.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           docker run -d \ | ||||
|             --rm \ | ||||
|             --name mitmproxy \ | ||||
|             --publish 8080:8080 \ | ||||
|             -v ${{ github.workspace }}/mitmproxy:/home/mitmproxy/.mitmproxy \ | ||||
|             mitmproxy/mitmproxy:latest \ | ||||
|             mitmdump | ||||
|           count=0 | ||||
|           while true; do | ||||
|             if [ -f "${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.pem" ]; then | ||||
|               echo "CA cert generated" | ||||
|               cat ${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.pem | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for mitmproxy generate its CA cert" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           sudo cp ${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.pem ${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.crt | ||||
|           sudo chown runner ${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.crt | ||||
|           kubectl create namespace arc-runners | ||||
|           kubectl -n arc-runners create configmap ca-cert --from-file="${{ github.workspace }}/mitmproxy/mitmproxy-ca-cert.crt" | ||||
|           kubectl -n arc-runners get configmap ca-cert -o yaml | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set proxy.https.url="http://host.minikube.internal:8080" \ | ||||
|           --set "proxy.noProxy[0]=10.96.0.1:443" \ | ||||
|           --set "githubServerTLS.certificateFrom.configMapKeyRef.name=ca-cert" \ | ||||
|           --set "githubServerTLS.certificateFrom.configMapKeyRef.key=mitmproxy-ca-cert.crt" \ | ||||
|           --set "githubServerTLS.runnerMountPath=/usr/local/share/ca-certificates/" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Test ARC E2E | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
| 
 | ||||
|   update-strategy-tests: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: "arc-test-sleepy-matrix.yaml" | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{github.head_ref}} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           --set flags.updateStrategy="eventual" \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
| 
 | ||||
|           sleep 60 | ||||
| 
 | ||||
|       - name: Trigger long running jobs and wait for runners to pick them up | ||||
|         uses: ./.github/actions/execute-assert-arc-e2e | ||||
|         timeout-minutes: 10 | ||||
|         with: | ||||
|           auth-token: ${{ steps.setup.outputs.token }} | ||||
|           repo-owner: ${{ env.TARGET_ORG }} | ||||
|           repo-name: ${{env.TARGET_REPO}} | ||||
|           workflow-file: ${{env.WORKFLOW_FILE}} | ||||
|           arc-name: ${{steps.install_arc.outputs.ARC_NAME}} | ||||
|           arc-namespace: "arc-runners" | ||||
|           arc-controller-namespace: "arc-systems" | ||||
|           wait-to-running: "true" | ||||
|           wait-to-finish: "false" | ||||
| 
 | ||||
|       - name: Upgrade the gha-runner-scale-set | ||||
|         shell: bash | ||||
|         run: | | ||||
|           helm upgrade --install "${{ steps.install_arc.outputs.ARC_NAME }}" \ | ||||
|             --namespace "arc-runners" \ | ||||
|             --create-namespace \ | ||||
|             --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{ env.TARGET_REPO }}" \ | ||||
|             --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|             --set template.spec.containers[0].name="runner" \ | ||||
|             --set template.spec.containers[0].image="ghcr.io/actions/actions-runner:latest" \ | ||||
|             --set template.spec.containers[0].command={"/home/runner/run.sh"} \ | ||||
|             --set template.spec.containers[0].env[0].name="TEST" \ | ||||
|             --set template.spec.containers[0].env[0].value="E2E TESTS" \ | ||||
|             ./charts/gha-runner-scale-set \ | ||||
|             --debug | ||||
| 
 | ||||
|       - name: Assert that the listener is deleted while jobs are running | ||||
|         shell: bash | ||||
|         run: | | ||||
|           count=0 | ||||
|           while true; do | ||||
|             LISTENER_COUNT="$(kubectl get pods -l actions.github.com/scale-set-name=${{ steps.install_arc.outputs.ARC_NAME }} -n arc-systems --field-selector=status.phase=Running -o=jsonpath='{.items}' | jq 'length')" | ||||
|             RUNNERS_COUNT="$(kubectl get pods -l app.kubernetes.io/component=runner -n arc-runners --field-selector=status.phase=Running -o=jsonpath='{.items}' | jq 'length')" | ||||
|             RESOURCES="$(kubectl get pods -A)" | ||||
| 
 | ||||
|             if [ "$LISTENER_COUNT" -eq 0 ]; then | ||||
|               echo "Listener has been deleted" | ||||
|               echo "$RESOURCES" | ||||
|               exit 0 | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener to be deleted" | ||||
|               echo "$RESOURCES" | ||||
|               exit 1 | ||||
|             fi | ||||
| 
 | ||||
|             echo "Waiting for listener to be deleted" | ||||
|             echo "Listener count: $LISTENER_COUNT target: 0 | Runners count: $RUNNERS_COUNT target: 3" | ||||
| 
 | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
| 
 | ||||
|       - name: Assert that the listener goes back up after the jobs are done | ||||
|         shell: bash | ||||
|         run: | | ||||
|           count=0 | ||||
|           while true; do | ||||
|             LISTENER_COUNT="$(kubectl get pods -l actions.github.com/scale-set-name=${{ steps.install_arc.outputs.ARC_NAME }} -n arc-systems --field-selector=status.phase=Running -o=jsonpath='{.items}' | jq 'length')" | ||||
|             RUNNERS_COUNT="$(kubectl get pods -l app.kubernetes.io/component=runner -n arc-runners --field-selector=status.phase=Running -o=jsonpath='{.items}' | jq 'length')" | ||||
|             RESOURCES="$(kubectl get pods -A)" | ||||
| 
 | ||||
|             if [ "$LISTENER_COUNT" -eq 1 ]; then | ||||
|               echo "Listener is up!" | ||||
|               echo "$RESOURCES" | ||||
|               exit 0 | ||||
|             fi | ||||
|             if [ "$count" -ge 120 ]; then | ||||
|               echo "Timeout waiting for listener to be recreated" | ||||
|               echo "$RESOURCES" | ||||
|               exit 1 | ||||
|             fi | ||||
| 
 | ||||
|             echo "Waiting for listener to be recreated" | ||||
|             echo "Listener count: $LISTENER_COUNT target: 1 | Runners count: $RUNNERS_COUNT target: 0" | ||||
| 
 | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
| 
 | ||||
|       - name: Gather logs and cleanup | ||||
|         shell: bash | ||||
|         if: always() | ||||
|         run: | | ||||
|           helm uninstall "${{ steps.install_arc.outputs.ARC_NAME }}" --namespace "arc-runners" --debug | ||||
|           kubectl wait --timeout=10s --for=delete AutoScalingRunnerSet -n "${{ steps.install_arc.outputs.ARC_NAME }}" -l app.kubernetes.io/instance="${{ steps.install_arc.outputs.ARC_NAME }}" | ||||
|           kubectl logs deployment/arc-gha-rs-controller -n "arc-systems" | ||||
| 
 | ||||
|   init-with-min-runners: | ||||
|     runs-on: ubuntu-latest | ||||
|     timeout-minutes: 20 | ||||
|     if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.id == github.repository_id | ||||
|     env: | ||||
|       WORKFLOW_FILE: arc-test-workflow.yaml | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|         with: | ||||
|           ref: ${{ github.head_ref }} | ||||
| 
 | ||||
|       - uses: ./.github/actions/setup-arc-e2e | ||||
|         id: setup | ||||
|         with: | ||||
|           app-id: ${{secrets.E2E_TESTS_ACCESS_APP_ID}} | ||||
|           app-pk: ${{secrets.E2E_TESTS_ACCESS_PK}} | ||||
|           image-name: ${{env.IMAGE_NAME}} | ||||
|           image-tag: ${{env.IMAGE_VERSION}} | ||||
|           target-org: ${{env.TARGET_ORG}} | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set-controller | ||||
|         id: install_arc_controller | ||||
|         run: | | ||||
|           helm install arc \ | ||||
|           --namespace "arc-systems" \ | ||||
|           --create-namespace \ | ||||
|           --set image.repository=${{ env.IMAGE_NAME }} \ | ||||
|           --set image.tag=${{ env.IMAGE_VERSION }} \ | ||||
|           --set flags.updateStrategy="eventual" \ | ||||
|           ./charts/gha-runner-scale-set-controller \ | ||||
|           --debug | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l app.kubernetes.io/name=gha-rs-controller -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for controller pod with label app.kubernetes.io/name=gha-rs-controller" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l app.kubernetes.io/name=gha-rs-controller | ||||
|           kubectl get pod -n arc-systems | ||||
|           kubectl describe deployment arc-gha-rs-controller -n arc-systems | ||||
| 
 | ||||
|       - name: Install gha-runner-scale-set | ||||
|         id: install_arc | ||||
|         run: | | ||||
|           ARC_NAME=${{github.job}}-$(date +'%M%S')$((($RANDOM + 100) % 100 + 1)) | ||||
|           helm install "$ARC_NAME" \ | ||||
|           --namespace "arc-runners" \ | ||||
|           --create-namespace \ | ||||
|           --set githubConfigUrl="https://github.com/${{ env.TARGET_ORG }}/${{env.TARGET_REPO}}" \ | ||||
|           --set githubConfigSecret.github_token="${{ steps.setup.outputs.token }}" \ | ||||
|           --set minRunners=5 \ | ||||
|           ./charts/gha-runner-scale-set \ | ||||
|           --debug | ||||
|           echo "ARC_NAME=$ARC_NAME" >> $GITHUB_OUTPUT | ||||
|           count=0 | ||||
|           while true; do | ||||
|             POD_NAME=$(kubectl get pods -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME -o name) | ||||
|             if [ -n "$POD_NAME" ]; then | ||||
|               echo "Pod found: $POD_NAME" | ||||
|               break | ||||
|             fi | ||||
|             if [ "$count" -ge 60 ]; then | ||||
|               echo "Timeout waiting for listener pod with label actions.github.com/scale-set-name=$ARC_NAME" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|           kubectl wait --timeout=30s --for=condition=ready pod -n arc-systems -l actions.github.com/scale-set-name=$ARC_NAME | ||||
|           kubectl get pod -n arc-systems | ||||
|       - name: Ensure 5 runners are up | ||||
|         run: | | ||||
|           count=0 | ||||
|           while true; do | ||||
|             pod_count=$(kubectl get pods -n arc-runners --no-headers | wc -l) | ||||
|             if [[ "$pod_count" = 5 ]]; then | ||||
|               echo "5 pods are up!" | ||||
|               break | ||||
|             fi | ||||
|             if [[ "$count" -ge 12 ]]; then | ||||
|               echo "Timeout waiting for 5 pods to be created" | ||||
|               exit 1 | ||||
|             fi | ||||
|             sleep 1 | ||||
|             count=$((count+1)) | ||||
|           done | ||||
|  | @ -0,0 +1,208 @@ | |||
| name: (gha) Publish Helm Charts | ||||
| 
 | ||||
| on: | ||||
|   workflow_dispatch: | ||||
|     inputs: | ||||
|       ref: | ||||
|         description: "The branch, tag or SHA to cut a release from" | ||||
|         required: false | ||||
|         type: string | ||||
|         default: "" | ||||
|       release_tag_name: | ||||
|         description: "The name to tag the controller image with" | ||||
|         required: true | ||||
|         type: string | ||||
|         default: "canary" | ||||
|       push_to_registries: | ||||
|         description: "Push images to registries" | ||||
|         required: true | ||||
|         type: boolean | ||||
|         default: false | ||||
|       publish_gha_runner_scale_set_controller_chart: | ||||
|         description: "Publish new helm chart for gha-runner-scale-set-controller" | ||||
|         required: true | ||||
|         type: boolean | ||||
|         default: false | ||||
|       publish_gha_runner_scale_set_chart: | ||||
|         description: "Publish new helm chart for gha-runner-scale-set" | ||||
|         required: true | ||||
|         type: boolean | ||||
|         default: false | ||||
| 
 | ||||
| env: | ||||
|   HELM_VERSION: v3.8.0 | ||||
| 
 | ||||
| permissions: | ||||
|   packages: write | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   build-push-image: | ||||
|     name: Build and push controller image | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           # If inputs.ref is empty, it'll resolve to the default branch | ||||
|           ref: ${{ inputs.ref }} | ||||
| 
 | ||||
|       - name: Check chart versions | ||||
|         # Binary version and chart versions need to match. | ||||
|         # In case of an upgrade, the controller will try to clean up | ||||
|         # resources with older versions that should have been cleaned up | ||||
|         # during the upgrade process | ||||
|         run: ./hack/check-gh-chart-versions.sh ${{ inputs.release_tag_name }} | ||||
| 
 | ||||
|       - name: Resolve parameters | ||||
|         id: resolve_parameters | ||||
|         run: | | ||||
|           resolvedRef="${{ inputs.ref }}" | ||||
|           if [ -z "$resolvedRef" ] | ||||
|           then | ||||
|             resolvedRef="${{ github.ref }}" | ||||
|           fi | ||||
|           echo "resolved_ref=$resolvedRef" >> $GITHUB_OUTPUT | ||||
|           echo "INFO: Resolving short SHA for $resolvedRef" | ||||
|           echo "short_sha=$(git rev-parse --short $resolvedRef)" >> $GITHUB_OUTPUT | ||||
|           echo "INFO: Normalizing repository name (lowercase)" | ||||
|           echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 | ||||
| 
 | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | ||||
|         with: | ||||
|           # Pinning v0.9.1 for Buildx and BuildKit v0.10.6 | ||||
|           # BuildKit v0.11 which has a bug causing intermittent | ||||
|           # failures pushing images to GHCR | ||||
|           version: v0.9.1 | ||||
|           driver-opts: image=moby/buildkit:v0.10.6 | ||||
| 
 | ||||
|       - name: Login to GitHub Container Registry | ||||
|         uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef | ||||
|         with: | ||||
|           registry: ghcr.io | ||||
|           username: ${{ github.actor }} | ||||
|           password: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       - name: Build & push controller image | ||||
|         uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 | ||||
|         with: | ||||
|           file: Dockerfile | ||||
|           platforms: linux/amd64,linux/arm64 | ||||
|           build-args: VERSION=${{ inputs.release_tag_name }} | ||||
|           push: ${{ inputs.push_to_registries }} | ||||
|           tags: | | ||||
|             ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }} | ||||
|             ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:${{ inputs.release_tag_name }}-${{ steps.resolve_parameters.outputs.short_sha }} | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "The [gha-publish-chart.yaml](https://github.com/actions/actions-runner-controller/blob/main/.github/workflows/gha-publish-chart.yaml) workflow run was completed successfully!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Ref: ${{ steps.resolve_parameters.outputs.resolvedRef }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Short SHA: ${{ steps.resolve_parameters.outputs.short_sha }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Release tag: ${{ inputs.release_tag_name }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Push to registries: ${{ inputs.push_to_registries }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
| 
 | ||||
|   publish-helm-chart-gha-runner-scale-set-controller: | ||||
|     if: ${{ inputs.publish_gha_runner_scale_set_controller_chart == true }} | ||||
|     needs: build-push-image | ||||
|     name: Publish Helm chart for gha-runner-scale-set-controller | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           # If inputs.ref is empty, it'll resolve to the default branch | ||||
|           ref: ${{ inputs.ref }} | ||||
| 
 | ||||
|       - name: Resolve parameters | ||||
|         id: resolve_parameters | ||||
|         run: | | ||||
|           resolvedRef="${{ inputs.ref }}" | ||||
|           if [ -z "$resolvedRef" ] | ||||
|           then | ||||
|             resolvedRef="${{ github.ref }}" | ||||
|           fi | ||||
|           echo "INFO: Resolving short SHA for $resolvedRef" | ||||
|           echo "short_sha=$(git rev-parse --short $resolvedRef)" >> $GITHUB_OUTPUT | ||||
|           echo "INFO: Normalizing repository name (lowercase)" | ||||
|           echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       - name: Publish new helm chart for gha-runner-scale-set-controller | ||||
|         run: | | ||||
|           echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin | ||||
|           GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG=$(cat charts/gha-runner-scale-set-controller/Chart.yaml | grep version: | cut -d " " -f 2) | ||||
|           echo "GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG=${GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG}" >> $GITHUB_ENV | ||||
|           helm package charts/gha-runner-scale-set-controller/ --version="${GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG}" | ||||
|           helm push gha-runner-scale-set-controller-"${GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG}".tgz oci://ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/actions-runner-controller-charts | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "New helm chart for gha-runner-scale-set-controller published successfully!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Ref: ${{ steps.resolve_parameters.outputs.resolvedRef }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Short SHA: ${{ steps.resolve_parameters.outputs.short_sha }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- gha-runner-scale-set-controller Chart version: ${{ env.GHA_RUNNER_SCALE_SET_CONTROLLER_CHART_VERSION_TAG }}" >> $GITHUB_STEP_SUMMARY | ||||
| 
 | ||||
|   publish-helm-chart-gha-runner-scale-set: | ||||
|     if: ${{ inputs.publish_gha_runner_scale_set_chart == true }} | ||||
|     needs: build-push-image | ||||
|     name: Publish Helm chart for gha-runner-scale-set | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           # If inputs.ref is empty, it'll resolve to the default branch | ||||
|           ref: ${{ inputs.ref }} | ||||
| 
 | ||||
|       - name: Resolve parameters | ||||
|         id: resolve_parameters | ||||
|         run: | | ||||
|           resolvedRef="${{ inputs.ref }}" | ||||
|           if [ -z "$resolvedRef" ] | ||||
|           then | ||||
|             resolvedRef="${{ github.ref }}" | ||||
|           fi | ||||
|           echo "INFO: Resolving short SHA for $resolvedRef" | ||||
|           echo "short_sha=$(git rev-parse --short $resolvedRef)" >> $GITHUB_OUTPUT | ||||
|           echo "INFO: Normalizing repository name (lowercase)" | ||||
|           echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       - name: Publish new helm chart for gha-runner-scale-set | ||||
|         run: | | ||||
|           echo ${{ secrets.GITHUB_TOKEN }} | helm registry login ghcr.io --username ${{ github.actor }} --password-stdin | ||||
| 
 | ||||
|           GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG=$(cat charts/gha-runner-scale-set/Chart.yaml | grep version: | cut -d " " -f 2) | ||||
|           echo "GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG=${GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG}" >> $GITHUB_ENV | ||||
|           helm package charts/gha-runner-scale-set/ --version="${GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG}" | ||||
|           helm push gha-runner-scale-set-"${GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG}".tgz oci://ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/actions-runner-controller-charts | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "New helm chart for gha-runner-scale-set published successfully!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Ref: ${{ steps.resolve_parameters.outputs.resolvedRef }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Short SHA: ${{ steps.resolve_parameters.outputs.short_sha }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- gha-runner-scale-set Chart version: ${{ env.GHA_RUNNER_SCALE_SET_CHART_VERSION_TAG }}" >> $GITHUB_STEP_SUMMARY | ||||
|  | @ -0,0 +1,122 @@ | |||
| name: (gha) Validate Helm Charts | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|     paths: | ||||
|       - "charts/**" | ||||
|       - ".github/workflows/gha-validate-chart.yaml" | ||||
|       - "!charts/actions-runner-controller/**" | ||||
|       - "!**.md" | ||||
|   push: | ||||
|     paths: | ||||
|       - "charts/**" | ||||
|       - ".github/workflows/gha-validate-chart.yaml" | ||||
|       - "!charts/actions-runner-controller/**" | ||||
|       - "!**.md" | ||||
|   workflow_dispatch: | ||||
| env: | ||||
|   KUBE_SCORE_VERSION: 1.16.1 | ||||
|   HELM_VERSION: v3.17.0 | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   validate-chart: | ||||
|     name: Lint Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       # python is a requirement for the chart-testing action below (supports yamllint among other tests) | ||||
|       - uses: actions/setup-python@v6 | ||||
|         with: | ||||
|           python-version: "3.11" | ||||
| 
 | ||||
|       - name: Set up chart-testing | ||||
|         uses: helm/chart-testing-action@0d28d3144d3a25ea2cc349d6e59901c4ff469b3b | ||||
| 
 | ||||
|       - name: Run chart-testing (list-changed) | ||||
|         id: list-changed | ||||
|         run: | | ||||
|           ct version | ||||
|           changed=$(ct list-changed --config charts/.ci/ct-config-gha.yaml) | ||||
|           if [[ -n "$changed" ]]; then | ||||
|             echo "changed=true" >> $GITHUB_OUTPUT | ||||
|           fi | ||||
| 
 | ||||
|       - name: Run chart-testing (lint) | ||||
|         run: | | ||||
|           ct lint --config charts/.ci/ct-config-gha.yaml | ||||
| 
 | ||||
|       - name: Set up docker buildx | ||||
|         uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         with: | ||||
|           version: latest | ||||
| 
 | ||||
|       - name: Build controller image | ||||
|         uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         with: | ||||
|           file: Dockerfile | ||||
|           platforms: linux/amd64 | ||||
|           load: true | ||||
|           build-args: | | ||||
|             DOCKER_IMAGE_NAME=test-arc | ||||
|             VERSION=dev | ||||
|           tags: | | ||||
|             test-arc:dev | ||||
|           cache-from: type=gha | ||||
|           cache-to: type=gha,mode=max | ||||
| 
 | ||||
|       - name: Create kind cluster | ||||
|         uses: helm/kind-action@a1b0e391336a6ee6713a0583f8c6240d70863de3 | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         with: | ||||
|           cluster_name: chart-testing | ||||
| 
 | ||||
|       - name: Load image into cluster | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: | | ||||
|           export DOCKER_IMAGE_NAME=test-arc | ||||
|           export VERSION=dev | ||||
|           export IMG_RESULT=load | ||||
|           make docker-buildx | ||||
|           kind load docker-image test-arc:dev --name chart-testing | ||||
| 
 | ||||
|       - name: Run chart-testing (install) | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: | | ||||
|           ct install --config charts/.ci/ct-config-gha.yaml | ||||
|   test-chart: | ||||
|     name: Test Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
|           cache: false | ||||
|       - name: Test gha-runner-scale-set | ||||
|         run: go test ./charts/gha-runner-scale-set/... | ||||
|       - name: Test gha-runner-scale-set-controller | ||||
|         run: go test ./charts/gha-runner-scale-set-controller/... | ||||
|  | @ -0,0 +1,133 @@ | |||
| name: Publish Canary Images | ||||
| 
 | ||||
| # Revert to https://github.com/actions-runner-controller/releases#releases | ||||
| # for details on why we use this approach | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|     paths-ignore: | ||||
|       - "**.md" | ||||
|       - ".github/actions/**" | ||||
|       - ".github/ISSUE_TEMPLATE/**" | ||||
|       - ".github/workflows/e2e-test-dispatch-workflow.yaml" | ||||
|       - ".github/workflows/gha-e2e-tests.yaml" | ||||
|       - ".github/workflows/arc-publish.yaml" | ||||
|       - ".github/workflows/arc-publish-chart.yaml" | ||||
|       - ".github/workflows/gha-publish-chart.yaml" | ||||
|       - ".github/workflows/arc-release-runners.yaml" | ||||
|       - ".github/workflows/global-run-codeql.yaml" | ||||
|       - ".github/workflows/global-run-first-interaction.yaml" | ||||
|       - ".github/workflows/global-run-stale.yaml" | ||||
|       - ".github/workflows/arc-update-runners-scheduled.yaml" | ||||
|       - ".github/workflows/validate-arc.yaml" | ||||
|       - ".github/workflows/arc-validate-chart.yaml" | ||||
|       - ".github/workflows/gha-validate-chart.yaml" | ||||
|       - ".github/workflows/arc-validate-runners.yaml" | ||||
|       - ".github/dependabot.yml" | ||||
|       - ".github/RELEASE_NOTE_TEMPLATE.md" | ||||
|       - "runner/**" | ||||
|       - ".gitignore" | ||||
|       - "PROJECT" | ||||
|       - "LICENSE" | ||||
|       - "Makefile" | ||||
| 
 | ||||
| # https://docs.github.com/en/rest/overview/permissions-required-for-github-apps | ||||
| permissions: | ||||
|   contents: read | ||||
|   packages: write | ||||
| 
 | ||||
| concurrency: | ||||
|   group: ${{ github.workflow }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| env: | ||||
|   # Safeguard to prevent pushing images to registeries after build | ||||
|   PUSH_TO_REGISTRIES: true | ||||
| 
 | ||||
| jobs: | ||||
|   legacy-canary-build: | ||||
|     name: Build and Publish Legacy Canary Image | ||||
|     runs-on: ubuntu-latest | ||||
|     env: | ||||
|       DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} | ||||
|       TARGET_ORG: actions-runner-controller | ||||
|       TARGET_REPO: actions-runner-controller | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: Get Token | ||||
|         id: get_workflow_token | ||||
|         uses: peter-murray/workflow-application-token-action@d17e3a9a36850ea89f35db16c1067dd2b68ee343 | ||||
|         with: | ||||
|           application_id: ${{ secrets.ACTIONS_ACCESS_APP_ID }} | ||||
|           application_private_key: ${{ secrets.ACTIONS_ACCESS_PK }} | ||||
|           organization: ${{ env.TARGET_ORG }} | ||||
| 
 | ||||
|       - name: Trigger Build And Push Images To Registries | ||||
|         run: | | ||||
|           # Authenticate | ||||
|           gh auth login --with-token <<< ${{ steps.get_workflow_token.outputs.token }} | ||||
| 
 | ||||
|           # Trigger the workflow run | ||||
|           jq -n '{"event_type": "canary", "client_payload": {"sha": "${{ github.sha }}", "push_to_registries": ${{ env.PUSH_TO_REGISTRIES }}}}' \ | ||||
|             | gh api -X POST /repos/actions-runner-controller/releases/dispatches --input - | ||||
| 
 | ||||
|       - name: Job summary | ||||
|         run: | | ||||
|           echo "The [publish-canary](https://github.com/actions-runner-controller/releases/blob/main/.github/workflows/publish-canary.yaml) workflow has been triggered!" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Parameters:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- sha: ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "- Push to registries: ${{ env.PUSH_TO_REGISTRIES }}" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "**Status:**" >> $GITHUB_STEP_SUMMARY | ||||
|           echo "[https://github.com/actions-runner-controller/releases/actions/workflows/publish-canary.yaml](https://github.com/actions-runner-controller/releases/actions/workflows/publish-canary.yaml)" >> $GITHUB_STEP_SUMMARY | ||||
| 
 | ||||
|   canary-build: | ||||
|     name: Build and Publish gha-runner-scale-set-controller Canary Image | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: Login to GitHub Container Registry | ||||
|         uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef | ||||
|         with: | ||||
|           registry: ghcr.io | ||||
|           username: ${{ github.actor }} | ||||
|           password: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       # Normalization is needed because upper case characters are not allowed in the repository name | ||||
|       # and the short sha is needed for image tagging | ||||
|       - name: Resolve parameters | ||||
|         id: resolve_parameters | ||||
|         run: | | ||||
|           echo "INFO: Resolving short sha" | ||||
|           echo "short_sha=$(git rev-parse --short ${{ github.ref }})" >> $GITHUB_OUTPUT | ||||
|           echo "INFO: Normalizing repository name (lowercase)" | ||||
|           echo "repository_owner=$(echo ${{ github.repository_owner }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_OUTPUT | ||||
| 
 | ||||
|       - name: Set up QEMU | ||||
|         uses: docker/setup-qemu-action@29109295f81e9208d7d86ff1c6c12d2833863392 | ||||
| 
 | ||||
|       - name: Set up Docker Buildx | ||||
|         uses: docker/setup-buildx-action@e468171a9de216ec08956ac3ada2f0791b6bd435 | ||||
|         with: | ||||
|           version: latest | ||||
| 
 | ||||
|       # Unstable builds - run at your own risk | ||||
|       - name: Build and Push | ||||
|         uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 | ||||
|         with: | ||||
|           context: . | ||||
|           file: ./Dockerfile | ||||
|           platforms: linux/amd64,linux/arm64 | ||||
|           build-args: VERSION=canary-${{ steps.resolve_parameters.outputs.short_sha }} | ||||
|           push: ${{ env.PUSH_TO_REGISTRIES }} | ||||
|           tags: | | ||||
|             ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:canary | ||||
|             ghcr.io/${{ steps.resolve_parameters.outputs.repository_owner }}/gha-runner-scale-set-controller:canary-${{ steps.resolve_parameters.outputs.short_sha }} | ||||
|           cache-from: type=gha | ||||
|           cache-to: type=gha,mode=max | ||||
|  | @ -0,0 +1,44 @@ | |||
| name: Run CodeQL | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|   schedule: | ||||
|     - cron: '30 1 * * 0' | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   analyze: | ||||
|     name: Analyze | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       security-events: write | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v5 | ||||
| 
 | ||||
|       - name: Install Go | ||||
|         uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: go.mod | ||||
| 
 | ||||
|       - name: Initialize CodeQL | ||||
|         uses: github/codeql-action/init@v4 | ||||
|         with: | ||||
|           languages: go, actions | ||||
| 
 | ||||
|       - name: Autobuild | ||||
|         uses: github/codeql-action/autobuild@v4 | ||||
| 
 | ||||
|       - name: Perform CodeQL Analysis | ||||
|         uses: github/codeql-action/analyze@v4 | ||||
|  | @ -0,0 +1,34 @@ | |||
| name: First Interaction | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
|   issues: write | ||||
|   pull-requests: write | ||||
| 
 | ||||
| on: | ||||
|   issues: | ||||
|     types: [opened] | ||||
|   pull_request: | ||||
|     branches: [master] | ||||
|     types: [opened] | ||||
| 
 | ||||
| jobs: | ||||
|   check_for_first_interaction: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/first-interaction@v3 | ||||
|         with: | ||||
|           repo_token: ${{ secrets.GITHUB_TOKEN }} | ||||
|           issue_message: | | ||||
|             Hello! Thank you for filing an issue. | ||||
| 
 | ||||
|             The maintainers will triage your issue shortly. | ||||
| 
 | ||||
|             In the meantime, please take a look at the [troubleshooting guide](https://github.com/actions/actions-runner-controller/blob/master/TROUBLESHOOTING.md) for bug reports. | ||||
| 
 | ||||
|             If this is a feature request, please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md). | ||||
|           pr_message: | | ||||
|             Hello! Thank you for your contribution. | ||||
| 
 | ||||
|             Please review our [contribution guidelines](https://github.com/actions/actions-runner-controller/blob/master/CONTRIBUTING.md) to understand the project's testing and code conventions. | ||||
|  | @ -14,7 +14,7 @@ jobs: | |||
|       issues: write         # for actions/stale to close stale issues | ||||
|       pull-requests: write  # for actions/stale to close stale PRs | ||||
|     steps: | ||||
|       - uses: actions/stale@v5 | ||||
|       - uses: actions/stale@v10 | ||||
|         with: | ||||
|           stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.' | ||||
|           # turn off stale for both issues and PRs | ||||
|  | @ -0,0 +1,88 @@ | |||
| name: Go | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|     paths: | ||||
|       - ".github/workflows/go.yaml" | ||||
|       - "**.go" | ||||
|       - "go.mod" | ||||
|       - "go.sum" | ||||
|   pull_request: | ||||
|     paths: | ||||
|       - ".github/workflows/go.yaml" | ||||
|       - "**.go" | ||||
|       - "go.mod" | ||||
|       - "go.sum" | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| concurrency: | ||||
|   # This will make sure we only apply the concurrency limits on pull requests | ||||
|   # but not pushes to master branch by making the concurrency group name unique | ||||
|   # for pushes | ||||
|   group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} | ||||
|   cancel-in-progress: true | ||||
| 
 | ||||
| jobs: | ||||
|   fmt: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
|           cache: false | ||||
|       - name: fmt | ||||
|         run: go fmt ./... | ||||
|       - name: Check diff | ||||
|         run: git diff --exit-code | ||||
| 
 | ||||
|   lint: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
|           cache: false | ||||
|       - name: golangci-lint | ||||
|         uses: golangci/golangci-lint-action@4afd733a84b1f43292c63897423277bb7f4313a9 | ||||
|         with: | ||||
|           only-new-issues: true | ||||
|           version: v2.5.0 | ||||
| 
 | ||||
|   generate: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
|           cache: false | ||||
|       - name: Generate | ||||
|         run: make generate | ||||
|       - name: Check diff | ||||
|         run: git diff --exit-code | ||||
| 
 | ||||
|   test: | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|       - uses: actions/checkout@v5 | ||||
|       - uses: actions/setup-go@v6 | ||||
|         with: | ||||
|           go-version-file: "go.mod" | ||||
|       - run: make manifests | ||||
|       - name: Check diff | ||||
|         run: git diff --exit-code | ||||
|       - name: Install kubebuilder | ||||
|         run: | | ||||
|           curl -D headers.txt -fsL "https://storage.googleapis.com/kubebuilder-tools/kubebuilder-tools-1.26.1-linux-amd64.tar.gz" -o kubebuilder-tools | ||||
|           echo "$(grep -i etag headers.txt -m 1 | cut -d'"' -f2) kubebuilder-tools" > sum | ||||
|           md5sum -c sum | ||||
|           tar -zvxf kubebuilder-tools | ||||
|           sudo mv kubebuilder /usr/local/ | ||||
|       - name: Run go tests | ||||
|         run: | | ||||
|           go test -short `go list ./... | grep -v ./test_e2e_arc` | ||||
|  | @ -1,63 +0,0 @@ | |||
| name: Publish ARC | ||||
| 
 | ||||
| on: | ||||
|   release: | ||||
|     types: | ||||
|       - published | ||||
| 
 | ||||
| jobs: | ||||
|   release-controller: | ||||
|     name: Release | ||||
|     runs-on: ubuntu-latest | ||||
|     env: | ||||
|       DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }} | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - uses: actions/setup-go@v3 | ||||
|         with: | ||||
|           go-version: '1.18.2' | ||||
| 
 | ||||
|       - name: Install tools | ||||
|         run: | | ||||
|           curl -L -O https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.2.0/kubebuilder_2.2.0_linux_amd64.tar.gz | ||||
|           tar zxvf kubebuilder_2.2.0_linux_amd64.tar.gz | ||||
|           sudo mv kubebuilder_2.2.0_linux_amd64 /usr/local/kubebuilder | ||||
|           curl -s https://raw.githubusercontent.com/kubernetes-sigs/kustomize/master/hack/install_kustomize.sh | bash | ||||
|           sudo mv kustomize /usr/local/bin | ||||
|           curl -L -O https://github.com/tcnksm/ghr/releases/download/v0.13.0/ghr_v0.13.0_linux_amd64.tar.gz | ||||
|           tar zxvf ghr_v0.13.0_linux_amd64.tar.gz | ||||
|           sudo mv ghr_v0.13.0_linux_amd64/ghr /usr/local/bin | ||||
| 
 | ||||
|       - name: Set version | ||||
|         run: echo "VERSION=$(cat ${GITHUB_EVENT_PATH} | jq -r '.release.tag_name')" >> $GITHUB_ENV | ||||
| 
 | ||||
|       - name: Upload artifacts | ||||
|         env: | ||||
|           GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | ||||
|         run: | | ||||
|           make github-release | ||||
| 
 | ||||
|       - name: Setup Docker Environment | ||||
|         id: vars | ||||
|         uses: ./.github/actions/setup-docker-environment | ||||
|         with: | ||||
|           username: ${{ env.DOCKERHUB_USERNAME }} | ||||
|           password: ${{ secrets.DOCKER_ACCESS_TOKEN }} | ||||
|           ghcr_username: ${{ github.actor }} | ||||
|           ghcr_password: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       - name: Build and Push | ||||
|         uses: docker/build-push-action@v3 | ||||
|         with: | ||||
|           file: Dockerfile | ||||
|           platforms: linux/amd64,linux/arm64 | ||||
|           push: true | ||||
|           tags: | | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:latest | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:${{ env.VERSION }} | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:${{ env.VERSION }}-${{ steps.vars.outputs.sha_short }} | ||||
|           cache-from: type=gha | ||||
|           cache-to: type=gha,mode=max | ||||
| 
 | ||||
|  | @ -1,57 +0,0 @@ | |||
| name: Publish Canary Image | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|     paths-ignore: | ||||
|       - '**.md' | ||||
|       - '.github/ISSUE_TEMPLATE/**' | ||||
|       - '.github/workflows/validate-chart.yaml' | ||||
|       - '.github/workflows/publish-chart.yaml' | ||||
|       - '.github/workflows/publish-arc.yaml' | ||||
|       - '.github/workflows/runners.yaml' | ||||
|       - '.github/workflows/validate-entrypoint.yaml' | ||||
|       - '.github/renovate.*' | ||||
|       - 'runner/**' | ||||
|       - '.gitignore' | ||||
|       - 'PROJECT' | ||||
|       - 'LICENSE' | ||||
|       - 'Makefile' | ||||
| 
 | ||||
| # https://docs.github.com/en/rest/overview/permissions-required-for-github-apps | ||||
| permissions: | ||||
|   contents: read | ||||
|   packages: write   | ||||
| 
 | ||||
| jobs: | ||||
|   canary-build: | ||||
|     name: Build and Publish Canary Image   | ||||
|     runs-on: ubuntu-latest | ||||
|     env: | ||||
|       DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }} | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - name: Setup Docker Environment | ||||
|         id: vars | ||||
|         uses: ./.github/actions/setup-docker-environment | ||||
|         with: | ||||
|           username: ${{ env.DOCKERHUB_USERNAME }} | ||||
|           password: ${{ secrets.DOCKER_ACCESS_TOKEN }} | ||||
|           ghcr_username: ${{ github.actor }} | ||||
|           ghcr_password: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       # Considered unstable builds | ||||
|       # See Issue #285, PR #286, and PR #323 for more information | ||||
|       - name: Build and Push | ||||
|         uses: docker/build-push-action@v3 | ||||
|         with: | ||||
|           file: Dockerfile | ||||
|           platforms: linux/amd64,linux/arm64 | ||||
|           push: true | ||||
|           tags: | | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/actions-runner-controller:canary | ||||
|           cache-from: type=gha,scope=arc-canary | ||||
|           cache-to: type=gha,mode=max,scope=arc-canary | ||||
|  | @ -1,127 +0,0 @@ | |||
| name: Publish Helm Chart | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches: | ||||
|       - master | ||||
|     paths: | ||||
|       - 'charts/**' | ||||
|       - '.github/workflows/publish-chart.yaml' | ||||
|       - '!charts/actions-runner-controller/docs/**' | ||||
|       - '!**.md' | ||||
|   workflow_dispatch: | ||||
| 
 | ||||
| env: | ||||
|   KUBE_SCORE_VERSION: 1.10.0 | ||||
|   HELM_VERSION: v3.8.0 | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| jobs: | ||||
|   lint-chart: | ||||
|     name: Lint Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     outputs: | ||||
|       publish-chart: ${{ steps.publish-chart-step.outputs.publish }} | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Set up Helm | ||||
|         uses: azure/setup-helm@v2.1 | ||||
|         with: | ||||
|           version: ${{ env.HELM_VERSION }} | ||||
| 
 | ||||
|       - name: Set up kube-score | ||||
|         run: | | ||||
|           wget https://github.com/zegl/kube-score/releases/download/v${{ env.KUBE_SCORE_VERSION }}/kube-score_${{ env.KUBE_SCORE_VERSION }}_linux_amd64 -O kube-score | ||||
|           chmod 755 kube-score | ||||
| 
 | ||||
|       - name: Kube-score generated manifests | ||||
|         run: helm template  --values charts/.ci/values-kube-score.yaml charts/* | ./kube-score score - | ||||
|               --ignore-test pod-networkpolicy | ||||
|               --ignore-test deployment-has-poddisruptionbudget | ||||
|               --ignore-test deployment-has-host-podantiaffinity | ||||
|               --ignore-test container-security-context | ||||
|               --ignore-test pod-probes | ||||
|               --ignore-test container-image-tag | ||||
|               --enable-optional-test container-security-context-privileged | ||||
|               --enable-optional-test container-security-context-readonlyrootfilesystem | ||||
| 
 | ||||
|       # python is a requirement for the chart-testing action below (supports yamllint among other tests) | ||||
|       - uses: actions/setup-python@v4 | ||||
|         with: | ||||
|           python-version: '3.7' | ||||
| 
 | ||||
|       - name: Set up chart-testing | ||||
|         uses: helm/chart-testing-action@v2.2.1 | ||||
| 
 | ||||
|       - name: Run chart-testing (list-changed) | ||||
|         id: list-changed | ||||
|         run: | | ||||
|           changed=$(ct list-changed --config charts/.ci/ct-config.yaml) | ||||
|           if [[ -n "$changed" ]]; then | ||||
|             echo "::set-output name=changed::true" | ||||
|           fi | ||||
| 
 | ||||
|       - name: Run chart-testing (lint) | ||||
|         run: | | ||||
|           ct lint --config charts/.ci/ct-config.yaml | ||||
| 
 | ||||
|       - name: Create kind cluster | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         uses: helm/kind-action@v1.2.0 | ||||
| 
 | ||||
|       # We need cert-manager already installed in the cluster because we assume the CRDs exist | ||||
|       - name: Install cert-manager | ||||
|         if: steps.list-changed.outputs.changed == 'true'       | ||||
|         run: | | ||||
|           helm repo add jetstack https://charts.jetstack.io --force-update | ||||
|           helm install cert-manager jetstack/cert-manager --set installCRDs=true --wait | ||||
| 
 | ||||
|       - name: Run chart-testing (install) | ||||
|         if: steps.list-changed.outputs.changed == 'true' | ||||
|         run: ct install --config charts/.ci/ct-config.yaml | ||||
| 
 | ||||
|       # WARNING: This relies on the latest release being inat the top of the JSON from GitHub and a clean chart.yaml | ||||
|       - name: Check if Chart Publish is Needed | ||||
|         id: publish-chart-step | ||||
|         run: | | ||||
|           CHART_TEXT=$(curl -fs https://raw.githubusercontent.com/actions-runner-controller/actions-runner-controller/master/charts/actions-runner-controller/Chart.yaml) | ||||
|           NEW_CHART_VERSION=$(echo "$CHART_TEXT" | grep version: | cut -d ' ' -f 2) | ||||
|           RELEASE_LIST=$(curl -fs https://api.github.com/repos/actions-runner-controller/actions-runner-controller/releases  | jq .[].tag_name | grep actions-runner-controller | cut -d '"' -f 2 | cut -d '-' -f 4) | ||||
|           LATEST_RELEASED_CHART_VERSION=$(echo $RELEASE_LIST | cut -d ' ' -f 1) | ||||
|           echo "Chart version in master : $NEW_CHART_VERSION" | ||||
|           echo "Latest release chart version : $LATEST_RELEASED_CHART_VERSION" | ||||
|           if [[ $NEW_CHART_VERSION != $LATEST_RELEASED_CHART_VERSION ]]; then | ||||
|             echo "::set-output name=publish::true" | ||||
|           fi | ||||
| 
 | ||||
|   publish-chart: | ||||
|     if: needs.lint-chart.outputs.publish-chart == 'true' | ||||
|     needs: lint-chart | ||||
|     name: Publish Chart | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       contents: write  # for helm/chart-releaser-action to push chart release and create a release | ||||
|      | ||||
| 
 | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
|         with: | ||||
|           fetch-depth: 0 | ||||
| 
 | ||||
|       - name: Configure Git | ||||
|         run: | | ||||
|           git config user.name "$GITHUB_ACTOR" | ||||
|           git config user.email "$GITHUB_ACTOR@users.noreply.github.com" | ||||
| 
 | ||||
|       - name: Run chart-releaser | ||||
|         uses: helm/chart-releaser-action@v1.4.0 | ||||
|         env: | ||||
|           CR_TOKEN: "${{ secrets.GITHUB_TOKEN }}" | ||||
| 
 | ||||
|  | @ -1,32 +0,0 @@ | |||
| name: Run CodeQL | ||||
| 
 | ||||
| on: | ||||
|   push: | ||||
|     branches:  | ||||
|       - master | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|   schedule: | ||||
|     - cron: '30 1 * * 0' | ||||
| 
 | ||||
| jobs: | ||||
|   analyze: | ||||
|     name: Analyze | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       security-events: write | ||||
|     steps: | ||||
|       - name: Checkout repository | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - name: Initialize CodeQL | ||||
|         uses: github/codeql-action/init@v2 | ||||
|         with: | ||||
|           languages: go | ||||
| 
 | ||||
|       - name: Autobuild | ||||
|         uses: github/codeql-action/autobuild@v2 | ||||
| 
 | ||||
|       - name: Perform CodeQL Analysis | ||||
|         uses: github/codeql-action/analyze@v2 | ||||
|  | @ -1,72 +0,0 @@ | |||
| name: Runners | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     types: | ||||
|       - opened | ||||
|       - synchronize | ||||
|       - reopened | ||||
|       - closed | ||||
|     branches: | ||||
|       - 'master' | ||||
|     paths: | ||||
|       - 'runner/**' | ||||
|       - '!runner/Makefile' | ||||
|       - '.github/workflows/runners.yaml' | ||||
|       - '!**.md' | ||||
| 
 | ||||
| env: | ||||
|   RUNNER_VERSION: 2.293.0 | ||||
|   DOCKER_VERSION: 20.10.12 | ||||
|   DOCKERHUB_USERNAME: ${{ secrets.DOCKER_USER }} | ||||
| 
 | ||||
| jobs: | ||||
|   build-runners: | ||||
|     name: Build ${{ matrix.name }}-${{ matrix.os-name }}-${{ matrix.os-version }} | ||||
|     runs-on: ubuntu-latest | ||||
|     permissions: | ||||
|       packages: write | ||||
|       contents: read | ||||
|     strategy: | ||||
|       fail-fast: false | ||||
|       matrix: | ||||
|         include: | ||||
|           - name: actions-runner | ||||
|             os-name: ubuntu | ||||
|             os-version: 20.04 | ||||
|           - name: actions-runner-dind | ||||
|             os-name: ubuntu | ||||
|             os-version: 20.04 | ||||
| 
 | ||||
|     steps: | ||||
|       - name: Checkout | ||||
|         uses: actions/checkout@v3 | ||||
| 
 | ||||
|       - name: Setup Docker Environment | ||||
|         id: vars | ||||
|         uses: ./.github/actions/setup-docker-environment | ||||
|         with: | ||||
|           username: ${{ env.DOCKERHUB_USERNAME }} | ||||
|           password: ${{ secrets.DOCKER_ACCESS_TOKEN }} | ||||
|           ghcr_username: ${{ github.actor }} | ||||
|           ghcr_password: ${{ secrets.GITHUB_TOKEN }} | ||||
| 
 | ||||
|       - name: Build and Push Versioned Tags | ||||
|         uses: docker/build-push-action@v3 | ||||
|         with: | ||||
|           context: ./runner | ||||
|           file: ./runner/${{ matrix.name }}.dockerfile | ||||
|           platforms: linux/amd64,linux/arm64 | ||||
|           push: ${{ github.ref == 'master' && github.event.pull_request.merged == true }} | ||||
|           build-args: | | ||||
|             RUNNER_VERSION=${{ env.RUNNER_VERSION }} | ||||
|             DOCKER_VERSION=${{ env.DOCKER_VERSION }} | ||||
|           tags: | | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }} | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}-${{ steps.vars.outputs.sha_short }} | ||||
|             ${{ env.DOCKERHUB_USERNAME }}/${{ matrix.name }}:latest | ||||
|             ghcr.io/${{ github.repository }}/${{ matrix.name }}:latest | ||||
|             ghcr.io/${{ github.repository }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }} | ||||
|             ghcr.io/${{ github.repository }}/${{ matrix.name }}:v${{ env.RUNNER_VERSION }}-${{ matrix.os-name }}-${{ matrix.os-version }}-${{ steps.vars.outputs.sha_short }} | ||||
|           cache-from: type=gha,scope=build-${{ matrix.name }} | ||||
|           cache-to: type=gha,mode=max,scope=build-${{ matrix.name }} | ||||
|  | @ -1,60 +0,0 @@ | |||
| name: Validate ARC | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - master | ||||
|     paths-ignore: | ||||
|       - '**.md' | ||||
|       - '.github/ISSUE_TEMPLATE/**' | ||||
|       - '.github/workflows/publish-canary.yaml' | ||||
|       - '.github/workflows/validate-chart.yaml' | ||||
|       - '.github/workflows/publish-chart.yaml' | ||||
|       - '.github/workflows/runners.yaml' | ||||
|       - '.github/workflows/publish-arc.yaml' | ||||
|       - '.github/workflows/validate-entrypoint.yaml' | ||||
|       - '.github/renovate.*' | ||||
|       - 'runner/**' | ||||
|       - '.gitignore' | ||||
|       - 'PROJECT' | ||||
|       - 'LICENSE' | ||||
|       - 'Makefile' | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| jobs: | ||||
|   test-controller: | ||||
|     name: Test ARC | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: Checkout | ||||
|       uses: actions/checkout@v3 | ||||
| 
 | ||||
|     - name: Set-up Go | ||||
|       uses: actions/setup-go@v3 | ||||
|       with: | ||||
|         go-version: '1.18.2' | ||||
|         check-latest: false | ||||
|      | ||||
|     - uses: actions/cache@v3 | ||||
|       with: | ||||
|         path: ~/go/pkg/mod | ||||
|         key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }} | ||||
|         restore-keys: | | ||||
|           ${{ runner.os }}-go- | ||||
| 
 | ||||
|     - name: Install kubebuilder | ||||
|       run: | | ||||
|         curl -L -O https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_linux_amd64.tar.gz | ||||
|         tar zxvf kubebuilder_2.3.2_linux_amd64.tar.gz | ||||
|         sudo mv kubebuilder_2.3.2_linux_amd64 /usr/local/kubebuilder | ||||
| 
 | ||||
|     - name: Run tests | ||||
|       run: | | ||||
|         make test | ||||
| 
 | ||||
|     - name: Verify manifests are up-to-date | ||||
|       run: | | ||||
|         make manifests | ||||
|         git diff --exit-code | ||||
|  | @ -1,25 +0,0 @@ | |||
| name: Validate Runners | ||||
| 
 | ||||
| on: | ||||
|   pull_request: | ||||
|     branches: | ||||
|       - '**' | ||||
|     paths: | ||||
|       - 'runner/**' | ||||
|       - 'test/entrypoint/**' | ||||
|       - '!**.md' | ||||
| 
 | ||||
| permissions: | ||||
|   contents: read | ||||
| 
 | ||||
| jobs: | ||||
|   test-runner-entrypoint: | ||||
|     name: Test entrypoint | ||||
|     runs-on: ubuntu-latest | ||||
|     steps: | ||||
|     - name: Checkout | ||||
|       uses: actions/checkout@v3 | ||||
| 
 | ||||
|     - name: Run tests | ||||
|       run: | | ||||
|         make acceptance/runner/entrypoint | ||||
|  | @ -29,8 +29,10 @@ bin | |||
| .env | ||||
| .test.env | ||||
| *.pem | ||||
| !github/actions/testdata/*.pem | ||||
| 
 | ||||
| # OS | ||||
| .DS_STORE | ||||
| 
 | ||||
| /test-assets | ||||
| /.tools | ||||
|  |  | |||
|  | @ -0,0 +1,14 @@ | |||
| version: "2" | ||||
| run: | ||||
|   timeout: 5m | ||||
| linters: | ||||
|   settings: | ||||
|     errcheck: | ||||
|       exclude-functions: | ||||
|         - (net/http.ResponseWriter).Write | ||||
|         - (*net/http.Server).Shutdown | ||||
|         - (*github.com/actions/actions-runner-controller/simulator.VisibleRunnerGroups).Add | ||||
|         - (*github.com/actions/actions-runner-controller/testing.Kind).Stop | ||||
|   exclusions: | ||||
|     presets: | ||||
|       - std-error-handling | ||||
|  | @ -1,2 +1,2 @@ | |||
| # actions-runner-controller maintainers | ||||
| * @mumoshu @toast-gear | ||||
| * @mumoshu @toast-gear @actions/actions-launch @actions/actions-compute @nikola-jokic @rentziass | ||||
|  |  | |||
|  | @ -0,0 +1,74 @@ | |||
| # Contributor Covenant Code of Conduct | ||||
| 
 | ||||
| ## Our Pledge | ||||
| 
 | ||||
| In the interest of fostering an open and welcoming environment, we as | ||||
| contributors and maintainers pledge to making participation in our project and | ||||
| our community a harassment-free experience for everyone, regardless of age, body | ||||
| size, disability, ethnicity, gender identity and expression, level of experience, | ||||
| nationality, personal appearance, race, religion, or sexual identity and | ||||
| orientation. | ||||
| 
 | ||||
| ## Our Standards | ||||
| 
 | ||||
| Examples of behavior that contributes to creating a positive environment | ||||
| include: | ||||
| 
 | ||||
| * Using welcoming and inclusive language | ||||
| * Being respectful of differing viewpoints and experiences | ||||
| * Gracefully accepting constructive criticism | ||||
| * Focusing on what is best for the community | ||||
| * Showing empathy towards other community members | ||||
| 
 | ||||
| Examples of unacceptable behavior by participants include: | ||||
| 
 | ||||
| * The use of sexualized language or imagery and unwelcome sexual attention or | ||||
| advances | ||||
| * Trolling, insulting/derogatory comments, and personal or political attacks | ||||
| * Public or private harassment | ||||
| * Publishing others' private information, such as a physical or electronic | ||||
|   address, without explicit permission | ||||
| * Other conduct which could reasonably be considered inappropriate in a | ||||
|   professional setting | ||||
| 
 | ||||
| ## Our Responsibilities | ||||
| 
 | ||||
| Project maintainers are responsible for clarifying the standards of acceptable | ||||
| behavior and are expected to take appropriate and fair corrective action in | ||||
| response to any instances of unacceptable behavior. | ||||
| 
 | ||||
| Project maintainers have the right and responsibility to remove, edit, or | ||||
| reject comments, commits, code, wiki edits, issues, and other contributions | ||||
| that are not aligned to this Code of Conduct, or to ban temporarily or | ||||
| permanently any contributor for other behaviors that they deem inappropriate, | ||||
| threatening, offensive, or harmful. | ||||
| 
 | ||||
| ## Scope | ||||
| 
 | ||||
| This Code of Conduct applies both within project spaces and in public spaces | ||||
| when an individual is representing the project or its community. Examples of | ||||
| representing a project or community include using an official project e-mail | ||||
| address, posting via an official social media account, or acting as an appointed | ||||
| representative at an online or offline event. Representation of a project may be | ||||
| further defined and clarified by project maintainers. | ||||
| 
 | ||||
| ## Enforcement | ||||
| 
 | ||||
| Instances of abusive, harassing, or otherwise unacceptable behavior may be | ||||
| reported by contacting the project team at opensource@github.com. All | ||||
| complaints will be reviewed and investigated and will result in a response that | ||||
| is deemed necessary and appropriate to the circumstances. The project team is | ||||
| obligated to maintain confidentiality with regard to the reporter of an incident. | ||||
| Further details of specific enforcement policies may be posted separately. | ||||
| 
 | ||||
| Project maintainers who do not follow or enforce the Code of Conduct in good | ||||
| faith may face temporary or permanent repercussions as determined by other | ||||
| members of the project's leadership. | ||||
| 
 | ||||
| ## Attribution | ||||
| 
 | ||||
| This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, | ||||
| available at [http://contributor-covenant.org/version/1/4][version] | ||||
| 
 | ||||
| [homepage]: http://contributor-covenant.org | ||||
| [version]: http://contributor-covenant.org/version/1/4/ | ||||
							
								
								
									
										368
									
								
								CONTRIBUTING.md
								
								
								
								
							
							
						
						
									
										368
									
								
								CONTRIBUTING.md
								
								
								
								
							|  | @ -1,85 +1,60 @@ | |||
| ## Contributing | ||||
| # Contribution Guide | ||||
| 
 | ||||
| ### Testing Controller Built from a Pull Request | ||||
| - [Contribution Guide](#contribution-guide) | ||||
|   - [Welcome](#welcome) | ||||
|   - [Before contributing code](#before-contributing-code) | ||||
|   - [How to Contribute a Patch](#how-to-contribute-a-patch) | ||||
|     - [Developing the Controller](#developing-the-controller) | ||||
|     - [Developing the Runners](#developing-the-runners) | ||||
|       - [Tests](#tests) | ||||
|       - [Running Ginkgo Tests](#running-ginkgo-tests) | ||||
|     - [Running End to End Tests](#running-end-to-end-tests) | ||||
|       - [Rerunning a failed test](#rerunning-a-failed-test) | ||||
|       - [Testing in a non-kind cluster](#testing-in-a-non-kind-cluster) | ||||
|     - [Code conventions](#code-conventions) | ||||
|     - [Opening the Pull Request](#opening-the-pull-request) | ||||
|   - [Helm Version Changes](#helm-version-changes) | ||||
|   - [Testing Controller Built from a Pull Request](#testing-controller-built-from-a-pull-request) | ||||
|   - [Release process](#release-process) | ||||
|     - [Workflow structure](#workflow-structure) | ||||
|       - [Releasing legacy actions-runner-controller image and helm charts](#releasing-legacy-actions-runner-controller-image-and-helm-charts) | ||||
|       - [Release actions-runner-controller runner images](#release-actions-runner-controller-runner-images) | ||||
|       - [Release gha-runner-scale-set-controller image and helm charts](#release-gha-runner-scale-set-controller-image-and-helm-charts) | ||||
|       - [Release actions/runner image](#release-actionsrunner-image) | ||||
|       - [Canary releases](#canary-releases) | ||||
| 
 | ||||
| We always appreciate your help in testing open pull requests by deploying custom builds of actions-runner-controller onto your own environment, so that we are extra sure we didn't break anything. | ||||
| ## Welcome | ||||
| 
 | ||||
| It is especially true when the pull request is about GitHub Enterprise, both GHEC and GHES, as [maintainers don't have GitHub Enterprise environments for testing](/README.md#github-enterprise-support). | ||||
| This document is the single source of truth for how to contribute to the code base. | ||||
| Feel free to browse the [open issues](https://github.com/actions/actions-runner-controller/issues) or file a new one, all feedback is welcome! | ||||
| By reading this guide, we hope to give you all of the information you need to be able to pick up issues, contribute new features, and get your work | ||||
| reviewed and merged. | ||||
| 
 | ||||
| The process would look like the below: | ||||
| ## Before contributing code | ||||
| 
 | ||||
| - Clone this repository locally | ||||
| - Checkout the branch. If you use the `gh` command, run `gh pr checkout $PR_NUMBER` | ||||
| - Run `NAME=$DOCKER_USER/actions-runner-controller VERSION=canary make docker-build docker-push` for a custom container image build | ||||
| - Update your actions-runner-controller's controller-manager deployment to use the new image, `$DOCKER_USER/actions-runner-controller:canary` | ||||
| We welcome code patches, but to make sure things are well coordinated you should discuss any significant change before starting the work. The maintainers ask that you signal your intention to contribute to the project using the issue tracker. If there is an existing issue that you want to work on, please let us know so we can get it assigned to you. If you noticed a bug or want to add a new feature, there are issue templates you can fill out. | ||||
| 
 | ||||
| Please also note that you need to replace `$DOCKER_USER` with your own DockerHub account name. | ||||
| When filing a feature request, the maintainers will review the change and give you a decision on whether we are willing to accept the feature into the project. | ||||
| 
 | ||||
| ### How to Contribute a Patch | ||||
| For significantly large and/or complex features, we may request that you write up an architectural decision record ([ADR](https://github.blog/2020-08-13-why-write-adrs/)) detailing the change. | ||||
| 
 | ||||
| Depending on what you are patching depends on how you should go about it. Below are some guides on how to test patches locally as well as develop the controller and runners. | ||||
| Please use the [template](/docs/adrs/yyyy-mm-dd-TEMPLATE) as guidance. | ||||
| 
 | ||||
| When submitting a PR for a change please provide evidence that your change works as we still need to work on improving the CI of the project. Some resources are provided for helping achieve this, see this guide for details. | ||||
| <!--  | ||||
|   TODO: Add a pre-requisite section describing what developers should | ||||
|   install in order get started on ARC. | ||||
| --> | ||||
| 
 | ||||
| #### Running an End to End Test | ||||
| ## How to Contribute a Patch | ||||
| 
 | ||||
| > **Notes for Ubuntu 20.04+ users** | ||||
| > | ||||
| > If you're using Ubuntu 20.04 or greater, you might have installed `docker` with `snap`. | ||||
| > | ||||
| > If you want to stick with `snap`-provided `docker`, do not forget to set `TMPDIR` to | ||||
| > somewhere under `$HOME`. | ||||
| > Otherwise `kind load docker-image` fail while running `docker save`. | ||||
| > See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap for more information. | ||||
| Depending on what you are patching depends on how you should go about it. | ||||
| Below are some guides on how to test patches locally as well as develop the controller and runners. | ||||
| 
 | ||||
| To test your local changes against both PAT and App based authentication please run the `acceptance` make target with the authentication configuration details provided: | ||||
| When submitting a PR for a change please provide evidence that your change works as we still need to work on improving the CI of the project. | ||||
| 
 | ||||
| ```shell | ||||
| # This sets `VERSION` envvar to some appropriate value | ||||
| . hack/make-env.sh | ||||
| Some resources are provided for helping achieve this, see this guide for details. | ||||
| 
 | ||||
| DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   APP_ID=*** \ | ||||
|   PRIVATE_KEY_FILE_PATH=path/to/pem/file \ | ||||
|   INSTALLATION_ID=*** \ | ||||
|   make acceptance | ||||
| ``` | ||||
| 
 | ||||
| **Rerunning a failed test** | ||||
| 
 | ||||
| When one of tests run by `make acceptance` failed, you'd probably like to rerun only the failed one. | ||||
| 
 | ||||
| It can be done by `make acceptance/run` and by setting the combination of `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm|kubectl` and `ACCEPTANCE_TEST_SECRET_TYPE=token|app` values that failed (note, you just need to set the corresponding authentication configuration in this circumstance) | ||||
| 
 | ||||
| In the example below, we rerun the test for the combination `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token` only: | ||||
| 
 | ||||
| ```shell | ||||
| DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm | ||||
|   ACCEPTANCE_TEST_SECRET_TYPE=token \ | ||||
|   make acceptance/run | ||||
| ``` | ||||
| 
 | ||||
| **Testing in a non-kind cluster** | ||||
| 
 | ||||
| If you prefer to test in a non-kind cluster, you can instead run: | ||||
| 
 | ||||
| ```shell | ||||
| KUBECONFIG=path/to/kubeconfig \ | ||||
|   DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   APP_ID=*** \ | ||||
|   PRIVATE_KEY_FILE_PATH=path/to/pem/file \ | ||||
|   INSTALLATION_ID=*** \ | ||||
|   ACCEPTANCE_TEST_SECRET_TYPE=token \ | ||||
|   make docker-build acceptance/setup \ | ||||
|        acceptance/deploy \ | ||||
|        acceptance/tests | ||||
| ``` | ||||
| 
 | ||||
| #### Developing the Controller | ||||
| ### Developing the Controller | ||||
| 
 | ||||
| Rerunning the whole acceptance test suite from scratch on every little change to the controller, the runner, and the chart would be counter-productive. | ||||
| 
 | ||||
|  | @ -98,7 +73,7 @@ To make your development cycle faster, use the below command to update deploy an | |||
| # Makefile | ||||
| VERSION=controller1 \ | ||||
|   RUNNER_TAG=runner1 \ | ||||
|   make acceptance/pull acceptance/kind docker-build acceptance/load acceptance/deploy | ||||
|   make acceptance/pull acceptance/kind docker-buildx acceptance/load acceptance/deploy | ||||
| ``` | ||||
| 
 | ||||
| If you've already deployed actions-runner-controller and only want to recreate pods to use the newer image, you can run: | ||||
|  | @ -119,13 +94,14 @@ NAME=$DOCKER_USER/actions-runner make \ | |||
|   (kubectl get po -ojsonpath={.items[*].metadata.name} | xargs -n1 kubectl delete po) | ||||
| ``` | ||||
| 
 | ||||
| #### Developing the Runners | ||||
| ### Developing the Runners | ||||
| 
 | ||||
| **Tests** | ||||
| #### Tests | ||||
| 
 | ||||
| A set of example pipelines (./acceptance/pipelines) are provided in this repository which you can use to validate your runners are working as expected. When raising a PR please run the relevant suites to prove your change hasn't broken anything. | ||||
| A set of example pipelines (./acceptance/pipelines) are provided in this repository which you can use to validate your runners are working as expected. | ||||
| When raising a PR please run the relevant suites to prove your change hasn't broken anything. | ||||
| 
 | ||||
| **Running Ginkgo Tests** | ||||
| #### Running Ginkgo Tests | ||||
| 
 | ||||
| You can run the integration test suite that is written in Ginkgo with: | ||||
| 
 | ||||
|  | @ -135,13 +111,14 @@ make test-with-deps | |||
| 
 | ||||
| This will firstly install a few binaries required to setup the integration test environment and then runs `go test` to start the Ginkgo test. | ||||
| 
 | ||||
| If you don't want to use `make`, like when you're running tests from your IDE, install required binaries to `/usr/local/kubebuilder/bin`. That's the directory in which controller-runtime's `envtest` framework locates the binaries. | ||||
| If you don't want to use `make`, like when you're running tests from your IDE, install required binaries to `/usr/local/kubebuilder/bin`. | ||||
| That's the directory in which controller-runtime's `envtest` framework locates the binaries. | ||||
| 
 | ||||
| ```shell | ||||
| sudo mkdir -p /usr/local/kubebuilder/bin | ||||
| make kube-apiserver etcd | ||||
| sudo mv test-assets/{etcd,kube-apiserver} /usr/local/kubebuilder/bin/ | ||||
| go test -v -run TestAPIs github.com/actions-runner-controller/actions-runner-controller/controllers | ||||
| go test -v -run TestAPIs github.com/actions/actions-runner-controller/controllers/actions.summerwind.net | ||||
| ``` | ||||
| 
 | ||||
| To run Ginkgo tests selectively, set the pattern of target test names to `GINKGO_FOCUS`. | ||||
|  | @ -149,9 +126,244 @@ All the Ginkgo test that matches `GINKGO_FOCUS` will be run. | |||
| 
 | ||||
| ```shell | ||||
| GINKGO_FOCUS='[It] should create a new Runner resource from the specified template, add a another Runner on replicas increased, and removes all the replicas when set to 0' \ | ||||
|   go test -v -run TestAPIs github.com/actions-runner-controller/actions-runner-controller/controllers | ||||
|   go test -v -run TestAPIs github.com/actions/actions-runner-controller/controllers/actions.summerwind.net | ||||
| ``` | ||||
| 
 | ||||
| #### Helm Version Bumps | ||||
| ### Running End to End Tests | ||||
| 
 | ||||
| In general we ask you not to bump the version in your PR, the maintainers in general manage the publishing of a new chart. | ||||
| > **Notes for Ubuntu 20.04+ users** | ||||
| > | ||||
| > If you're using Ubuntu 20.04 or greater, you might have installed `docker` with `snap`. | ||||
| > | ||||
| > If you want to stick with `snap`-provided `docker`, do not forget to set `TMPDIR` to somewhere under `$HOME`. | ||||
| > Otherwise `kind load docker-image` fail while running `docker save`. | ||||
| > See <https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap> for more information. | ||||
| 
 | ||||
| To test your local changes against both PAT and App based authentication please run the `acceptance` make target with the authentication configuration details provided: | ||||
| 
 | ||||
| ```shell | ||||
| # This sets `VERSION` envvar to some appropriate value | ||||
| . hack/make-env.sh | ||||
| 
 | ||||
| DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   APP_ID=*** \ | ||||
|   PRIVATE_KEY_FILE_PATH=path/to/pem/file \ | ||||
|   INSTALLATION_ID=*** \ | ||||
|   make acceptance | ||||
| ``` | ||||
| 
 | ||||
| #### Rerunning a failed test | ||||
| 
 | ||||
| When one of tests run by `make acceptance` failed, you'd probably like to rerun only the failed one. | ||||
| 
 | ||||
| It can be done by `make acceptance/run` and by setting the combination of `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm|kubectl` and `ACCEPTANCE_TEST_SECRET_TYPE=token|app` values that failed (note, you just need to set the corresponding authentication configuration in this circumstance) | ||||
| 
 | ||||
| In the example below, we rerun the test for the combination `ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm ACCEPTANCE_TEST_SECRET_TYPE=token` only: | ||||
| 
 | ||||
| ```shell | ||||
| DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   ACCEPTANCE_TEST_DEPLOYMENT_TOOL=helm \ | ||||
|   ACCEPTANCE_TEST_SECRET_TYPE=token \ | ||||
|   make acceptance/run | ||||
| ``` | ||||
| 
 | ||||
| #### Testing in a non-kind cluster | ||||
| 
 | ||||
| If you prefer to test in a non-kind cluster, you can instead run: | ||||
| 
 | ||||
| ```shell | ||||
| KUBECONFIG=path/to/kubeconfig \ | ||||
|   DOCKER_USER=*** \ | ||||
|   GITHUB_TOKEN=*** \ | ||||
|   APP_ID=*** \ | ||||
|   PRIVATE_KEY_FILE_PATH=path/to/pem/file \ | ||||
|   INSTALLATION_ID=*** \ | ||||
|   ACCEPTANCE_TEST_SECRET_TYPE=token \ | ||||
|   make docker-build acceptance/setup \ | ||||
|        acceptance/deploy \ | ||||
|        acceptance/tests | ||||
| ``` | ||||
| 
 | ||||
| ### Code conventions | ||||
| 
 | ||||
| Before shipping your PR, please check the following items to make sure CI passes. | ||||
| 
 | ||||
| - Run `go mod tidy` if you made changes to dependencies. | ||||
| - Format the code using `gofmt` | ||||
| - Run the `golangci-lint` tool locally. | ||||
|   - We recommend you use `make lint` to run the tool using a Docker container matching the CI version. | ||||
| 
 | ||||
| ### Opening the Pull Request | ||||
| 
 | ||||
| Send PR, add issue number to description | ||||
| 
 | ||||
| ## Helm Version Changes | ||||
| 
 | ||||
| In general we ask you not to bump the version in your PR. | ||||
| The maintainers will manage releases and publishing new charts. | ||||
| 
 | ||||
| ## Testing Controller Built from a Pull Request | ||||
| 
 | ||||
| We always appreciate your help in testing open pull requests by deploying custom builds of actions-runner-controller onto your own environment, so that we are extra sure we didn't break anything. | ||||
| 
 | ||||
| It is especially true when the pull request is about GitHub Enterprise, both GHEC and GHES, as [maintainers don't have GitHub Enterprise environments for testing](docs/about-arc.md#github-enterprise-support). | ||||
| 
 | ||||
| The process would look like the below: | ||||
| 
 | ||||
| - Clone this repository locally | ||||
| - Checkout the branch. If you use the `gh` command, run `gh pr checkout $PR_NUMBER` | ||||
| - Run `NAME=$DOCKER_USER/actions-runner-controller VERSION=canary make docker-build docker-push` for a custom container image build | ||||
| - Update your actions-runner-controller's controller-manager deployment to use the new image, `$DOCKER_USER/actions-runner-controller:canary` | ||||
| 
 | ||||
| Please also note that you need to replace `$DOCKER_USER` with your own DockerHub account name. | ||||
| 
 | ||||
| ## Release process | ||||
| 
 | ||||
| Only the maintainers can release a new version of actions-runner-controller, publish a new version of the helm charts, and runner images. | ||||
| 
 | ||||
| All release workflows have been moved to [actions-runner-controller/releases](https://github.com/actions-runner-controller/releases) since the packages are owned by the former organization. | ||||
| 
 | ||||
| ### Workflow structure | ||||
| 
 | ||||
| Following the migration of actions-runner-controller into GitHub actions, all the workflows had to be modified to accommodate the move to a new organization. The following table describes the workflows, their purpose and dependencies. | ||||
| 
 | ||||
| | Filename                          | Workflow name                        | Purpose                                                                                                                                                                                                                                                         | | ||||
| |-----------------------------------|--------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | ||||
| | gha-e2e-tests.yaml                | (gha) E2E Tests                      | Tests the Autoscaling Runner Set mode end to end. Coverage is restricted to this mode. Legacy modes are not tested.                                                                                                                                          | | ||||
| | go.yaml                           | Format, Lint, Unit Tests             | Formats, lints and runs unit tests for the entire codebase.                                                                                                                                                                                                     | | ||||
| | arc-publish.yaml                  | Publish ARC Image                    | Uploads release/actions-runner-controller.yaml as an artifact to the newly created release and triggers the [build and publication of the controller image](https://github.com/actions-runner-controller/releases/blob/main/.github/workflows/publish-arc.yaml) | | ||||
| | global-publish-canary.yaml        | Publish Canary Images                | Builds and publishes canary controller container images for both new and legacy modes.                                                                                                                                                                          | | ||||
| | arc-publish-chart.yaml            | Publish ARC Helm Charts              | Packages and publishes charts/actions-runner-controller (via GitHub Pages)                                                                                                                                                                                      | | ||||
| | gha-publish-chart.yaml            | (gha) Publish Helm Charts            | Packages and publishes charts/gha-runner-scale-set-controller and charts/gha-runner-scale-set charts (OCI to GHCR)                                                                                                                                              | | ||||
| | arc-release-runners.yaml          | Release ARC Runner Images            | Triggers [release-runners.yaml](https://github.com/actions-runner-controller/releases/blob/main/.github/workflows/release-runners.yaml) which will build and push new runner images used with the legacy ARC modes.                                             | | ||||
| | global-run-codeql.yaml            | Run CodeQL                           | Run CodeQL on all the codebase                                                                                                                                                                                                                                  | | ||||
| | global-run-first-interaction.yaml | First Interaction                    | Informs first time contributors what to expect when they open a new issue / PR                                                                                                                                                                                  | | ||||
| | global-run-stale.yaml             | Run Stale Bot                        | Closes issues / PRs without activity                                                                                                                                                                                                                            | | ||||
| | arc-update-runners-scheduled.yaml | Runner Updates Check (Scheduled Job) | Polls [actions/runner](https://github.com/actions/runner) and [actions/runner-container-hooks](https://github.com/actions/runner-container-hooks) for new releases. If found, a PR is created to publish new runner images                                      | | ||||
| | arc-validate-chart.yaml           | Validate Helm Chart                  | Run helm chart validators for charts/actions-runner-controller                                                                                                                                                                                                  | | ||||
| | gha-validate-chart.yaml           | (gha) Validate Helm Charts           | Run helm chart validators for charts/gha-runner-scale-set-controller and charts/gha-runner-scale-set charts                                                                                                                                                     | | ||||
| | arc-validate-runners.yaml         | Validate ARC Runners                 | Run validators for runners                                                                                                                                                                                                                                      | | ||||
| 
 | ||||
| There are 7 components that we release regularly: | ||||
| 
 | ||||
| 1. legacy [actions-runner-controller controller image](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller) | ||||
| 2. legacy [actions-runner-controller helm charts](https://actions-runner-controller.github.io/actions-runner-controller/) | ||||
| 3. legacy actions-runner-controller runner images | ||||
|    1. [ubuntu-20.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner) | ||||
|    2. [ubuntu-22.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner) | ||||
|    3. [dind-ubuntu-20.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner-dind) | ||||
|    4. [dind-ubuntu-22.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner-dind) | ||||
|    5. [dind-rootless-ubuntu-20.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner-dind-rootless) | ||||
|    6. [dind-rootless-ubuntu-22.04](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner-dind-rootless) | ||||
| 4. [gha-runner-scale-set-controller image](https://github.com/actions/actions-runner-controller/pkgs/container/gha-runner-scale-set-controller) | ||||
| 5. [gha-runner-scale-set-controller helm charts](https://github.com/actions/actions-runner-controller/pkgs/container/actions-runner-controller-charts%2Fgha-runner-scale-set-controller) | ||||
| 6. [gha-runner-scale-set runner helm charts](https://github.com/actions/actions-runner-controller/pkgs/container/actions-runner-controller-charts%2Fgha-runner-scale-set) | ||||
| 7. [actions/runner image](https://github.com/actions/actions-runner-controller/pkgs/container/actions-runner-controller%2Factions-runner) | ||||
| 
 | ||||
| #### Releasing legacy actions-runner-controller image and helm charts | ||||
| 
 | ||||
| 1. Start by making sure the master branch is stable and all CI jobs are passing | ||||
| 2. Create a new release in <https://github.com/actions/actions-runner-controller/releases> (Draft a new release) | ||||
| 3. Bump up the `version` and `appVersion` in charts/actions-runner-controller/Chart.yaml - make sure the `version` matches the release version you just created. (Example: <https://github.com/actions/actions-runner-controller/pull/2577>) | ||||
| 4. When the workflows finish execution, you will see: | ||||
|    1. A new controller image published to: <https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller> | ||||
|    2. Helm charts published to: <https://github.com/actions-runner-controller/actions-runner-controller.github.io/tree/master/actions-runner-controller> (the index.yaml file is updated) | ||||
| 
 | ||||
| When a new release is created, the [Publish ARC Image](https://github.com/actions/actions-runner-controller/blob/master/.github/workflows/arc-publish.yaml) workflow is triggered. | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|     subgraph repository: actions/actions-runner-controller | ||||
|     event_a{{"release: published"}} -- triggers --> workflow_a["arc-publish.yaml"] | ||||
|     event_b{{"workflow_dispatch"}} -- triggers --> workflow_a["arc-publish.yaml"] | ||||
|     workflow_a["arc-publish.yaml"] -- uploads --> package["actions-runner-controller.tar.gz"] | ||||
|     end | ||||
|     subgraph repository: actions-runner-controller/releases | ||||
|     workflow_a["arc-publish.yaml"] -- triggers --> event_d{{"repository_dispatch"}} --> workflow_b["publish-arc.yaml"] | ||||
|     workflow_b["publish-arc.yaml"] -- push --> A["GHCR: \nactions-runner-controller/actions-runner-controller:*"] | ||||
|     workflow_b["publish-arc.yaml"] -- push --> B["DockerHub: \nsummerwind/actions-runner-controller:*"] | ||||
|     end | ||||
| ``` | ||||
| 
 | ||||
| #### Release actions-runner-controller runner images | ||||
| 
 | ||||
| **Manual steps:** | ||||
| 
 | ||||
| 1. Navigate to the [actions-runner-controller/releases](https://github.com/actions-runner-controller/releases) repository | ||||
| 2. Trigger [the release-runners.yaml](https://github.com/actions-runner-controller/releases/actions/workflows/release-runners.yaml) workflow. | ||||
|    1. The list of input prameters for this workflow is defined in the table below (always inspect the workflow file for the latest version) | ||||
| 
 | ||||
| <!-- Table of Paramters --> | ||||
| | Parameter                        | Description                                                                                                                                                                                                                         | Default       | | ||||
| |----------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------| | ||||
| | `runner_version`                 | The version of the [actions/runner](https://github.com/actions/runner) to use                                                                                                                                                       | `2.300.2`     | | ||||
| | `docker_version`                 | The version of docker to use                                                                                                                                                                                                        | `20.10.12`    | | ||||
| | `runner_container_hooks_version` | The version of [actions/runner-container-hooks](https://github.com/actions/runner-container-hooks) to use                                                                                                                           | `0.2.0`       | | ||||
| | `sha`                            | The commit sha from [actions/actions-runner-controller](https://github.com/actions/actions-runner-controller) to be used to build the runner images. This will be provided to `actions/checkout` & used to tag the container images | Empty string. | | ||||
| | `push_to_registries`             | Whether to push the images to the registries. Use false to test the build                                                                                                                                                           | false         | | ||||
| 
 | ||||
| **Automated steps:** | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|     workflow["release-runners.yaml"] -- workflow_dispatch* --> workflow_b["release-runners.yaml"] | ||||
|     subgraph repository: actions/actions-runner-controller | ||||
|     runner_updates_check["arc-update-runners-scheduled.yaml"] -- "polls (daily)" --> runner_releases["actions/runner/releases"] | ||||
|     runner_updates_check -- creates --> runner_update_pr["PR: update /runner/VERSION"]**** | ||||
|     runner_update_pr --> runner_update_pr_merge{{"merge"}} | ||||
|     runner_update_pr_merge -- triggers --> workflow["release-runners.yaml"] | ||||
|     end | ||||
|     subgraph repository: actions-runner-controller/releases | ||||
|     workflow_b["release-runners.yaml"] -- push --> A["GHCR: \n actions-runner-controller/actions-runner:* \n actions-runner-controller/actions-runner-dind:* \n actions-runner-controller/actions-runner-dind-rootless:*"] | ||||
|     workflow_b["release-runners.yaml"] -- push --> B["DockerHub: \n summerwind/actions-runner:* \n summerwind/actions-runner-dind:* \n summerwind/actions-runner-dind-rootless:*"] | ||||
|     event_b{{"workflow_dispatch"}} -- triggers --> workflow_b["release-runners.yaml"] | ||||
|     end | ||||
| ``` | ||||
| 
 | ||||
| #### Release gha-runner-scale-set-controller image and helm charts | ||||
| 
 | ||||
| 1. Make sure the master branch is stable and all CI jobs are passing | ||||
| 1. Prepare a release PR (example: <https://github.com/actions/actions-runner-controller/pull/2467>) | ||||
|    1. Bump up the version of the chart in: charts/gha-runner-scale-set-controller/Chart.yaml | ||||
|    2. Bump up the version of the chart in: charts/gha-runner-scale-set/Chart.yaml | ||||
|       1. Make sure that `version`, `appVersion` of both charts are always the same. These versions cannot diverge. | ||||
|    3. Update the quickstart guide to reflect the latest versions: docs/preview/gha-runner-scale-set-controller/README.md | ||||
|    4. Add changelog to the PR as well as the quickstart guide | ||||
| 1. Merge the release PR | ||||
| 1. Manually trigger the [(gha) Publish Helm Charts](https://github.com/actions/actions-runner-controller/actions/workflows/gha-publish-chart.yaml) workflow | ||||
| 1. Manually create a tag and release in [actions/actions-runner-controller](https://github.com/actions/actions-runner-controller/releases) with the format: `gha-runner-scale-set-x.x.x` where the version (x.x.x) matches that of the Helm chart | ||||
| 
 | ||||
| | Parameter                                       | Description                                                                                            | Default        | | ||||
| |-------------------------------------------------|--------------------------------------------------------------------------------------------------------|----------------| | ||||
| | `ref`                                           | The branch, tag or SHA to cut a release from.                                                          | default branch | | ||||
| | `release_tag_name`                              | The tag of the controller image. This is not a git tag.                                                | canary         | | ||||
| | `push_to_registries`                            | Push images to registries. Use false to test the build process.                                        | false          | | ||||
| | `publish_gha_runner_scale_set_controller_chart` | Publish new helm chart for gha-runner-scale-set-controller. This will push the new OCI archive to GHCR | false          | | ||||
| | `publish_gha_runner_scale_set_chart`            | Publish new helm chart for gha-runner-scale-set. This will push the new OCI archive to GHCR            | false          | | ||||
| 
 | ||||
| #### Release actions/runner image | ||||
| 
 | ||||
| A new runner image is built and published to <https://github.com/actions/runner/pkgs/container/actions-runner> whenever a new runner binary has been released. There's nothing to do here. | ||||
| 
 | ||||
| #### Canary releases | ||||
| 
 | ||||
| We publish canary images for both the legacy actions-runner-controller and gha-runner-scale-set-controller images. | ||||
| 
 | ||||
| ```mermaid | ||||
| flowchart LR | ||||
|     subgraph org: actions | ||||
|     event_a{{"push: [master]"}} -- triggers --> workflow_a["publish-canary.yaml"] | ||||
|     end | ||||
|     subgraph org: actions-runner-controller | ||||
|     workflow_a["publish-canary.yaml"] -- triggers --> event_d{{"repository_dispatch"}} --> workflow_b["publish-canary.yaml"] | ||||
|     workflow_b["publish-canary.yaml"] -- push --> A["GHCR: \nactions-runner-controller/actions-runner-controller:canary"] | ||||
|     workflow_b["publish-canary.yaml"] -- push --> B["DockerHub: \nsummerwind/actions-runner-controller:canary"] | ||||
|     end | ||||
| ``` | ||||
| 
 | ||||
| 1. [actions-runner-controller canary image](https://github.com/actions-runner-controller/actions-runner-controller/pkgs/container/actions-runner-controller) | ||||
| 2. [gha-runner-scale-set-controller image](https://github.com/actions/actions-runner-controller/pkgs/container/gha-runner-scale-set-controller) | ||||
| 
 | ||||
| These canary images are automatically built and released on each push to the master branch. | ||||
|  |  | |||
							
								
								
									
										19
									
								
								Dockerfile
								
								
								
								
							
							
						
						
									
										19
									
								
								Dockerfile
								
								
								
								
							|  | @ -1,11 +1,10 @@ | |||
| # Build the manager binary | ||||
| FROM --platform=$BUILDPLATFORM golang:1.18.2 as builder | ||||
| FROM --platform=$BUILDPLATFORM golang:1.25.1 AS builder | ||||
| 
 | ||||
| WORKDIR /workspace | ||||
| 
 | ||||
| # Make it runnable on a distroless image/without libc | ||||
| ENV CGO_ENABLED=0 | ||||
| 
 | ||||
| # Copy the Go Modules manifests | ||||
| COPY go.mod go.sum ./ | ||||
| 
 | ||||
|  | @ -25,20 +24,23 @@ RUN go mod download | |||
| # With the above commmand, | ||||
| # TARGETOS can be "linux", TARGETARCH can be "amd64", "arm64", and "arm", TARGETVARIANT can be "v7". | ||||
| 
 | ||||
| ARG TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT | ||||
| ARG TARGETPLATFORM TARGETOS TARGETARCH TARGETVARIANT VERSION=dev COMMIT_SHA=dev | ||||
| 
 | ||||
| # We intentionally avoid `--mount=type=cache,mode=0777,target=/go/pkg/mod` in the `go mod download` and the `go build` runs | ||||
| # to avoid https://github.com/moby/buildkit/issues/2334 | ||||
| # We can use docker layer cache so the build is fast enogh anyway | ||||
| # We also use per-platform GOCACHE for the same reason. | ||||
| env GOCACHE /build/${TARGETPLATFORM}/root/.cache/go-build | ||||
| ENV GOCACHE="/build/${TARGETPLATFORM}/root/.cache/go-build" | ||||
| 
 | ||||
| # Build | ||||
| RUN --mount=target=. \ | ||||
|   --mount=type=cache,mode=0777,target=${GOCACHE} \ | ||||
|   export GOOS=${TARGETOS} GOARCH=${TARGETARCH} GOARM=${TARGETVARIANT#v} && \ | ||||
|   go build -o /out/manager main.go && \ | ||||
|   go build -o /out/github-webhook-server ./cmd/githubwebhookserver | ||||
|   go build -trimpath -ldflags="-s -w -X 'github.com/actions/actions-runner-controller/build.Version=${VERSION}' -X 'github.com/actions/actions-runner-controller/build.CommitSHA=${COMMIT_SHA}'" -o /out/manager main.go && \ | ||||
|   go build -trimpath -ldflags="-s -w -X 'github.com/actions/actions-runner-controller/build.Version=${VERSION}' -X 'github.com/actions/actions-runner-controller/build.CommitSHA=${COMMIT_SHA}'" -o /out/ghalistener ./cmd/ghalistener && \ | ||||
|   go build -trimpath -ldflags="-s -w" -o /out/github-webhook-server ./cmd/githubwebhookserver && \ | ||||
|   go build -trimpath -ldflags="-s -w" -o /out/actions-metrics-server ./cmd/actionsmetricsserver && \ | ||||
|   go build -trimpath -ldflags="-s -w" -o /out/sleep ./cmd/sleep | ||||
| 
 | ||||
| # Use distroless as minimal base image to package the manager binary | ||||
| # Refer to https://github.com/GoogleContainerTools/distroless for more details | ||||
|  | @ -48,7 +50,10 @@ WORKDIR / | |||
| 
 | ||||
| COPY --from=builder /out/manager . | ||||
| COPY --from=builder /out/github-webhook-server . | ||||
| COPY --from=builder /out/actions-metrics-server . | ||||
| COPY --from=builder /out/ghalistener . | ||||
| COPY --from=builder /out/sleep . | ||||
| 
 | ||||
| USER nonroot:nonroot | ||||
| USER 65532:65532 | ||||
| 
 | ||||
| ENTRYPOINT ["/manager"] | ||||
|  |  | |||
							
								
								
									
										176
									
								
								Makefile
								
								
								
								
							
							
						
						
									
										176
									
								
								Makefile
								
								
								
								
							|  | @ -1,11 +1,12 @@ | |||
| ifdef DOCKER_USER | ||||
| 	NAME ?= ${DOCKER_USER}/actions-runner-controller | ||||
| 	DOCKER_IMAGE_NAME ?= ${DOCKER_USER}/actions-runner-controller | ||||
| else | ||||
| 	NAME ?= summerwind/actions-runner-controller | ||||
| 	DOCKER_IMAGE_NAME ?= summerwind/actions-runner-controller | ||||
| endif | ||||
| DOCKER_USER ?= $(shell echo ${NAME} | cut -d / -f1) | ||||
| VERSION ?= latest | ||||
| RUNNER_VERSION ?= 2.293.0 | ||||
| DOCKER_USER ?= $(shell echo ${DOCKER_IMAGE_NAME} | cut -d / -f1) | ||||
| VERSION ?= dev | ||||
| COMMIT_SHA = $(shell git rev-parse HEAD) | ||||
| RUNNER_VERSION ?= 2.329.0 | ||||
| TARGETPLATFORM ?= $(shell arch) | ||||
| RUNNER_NAME ?= ${DOCKER_USER}/actions-runner | ||||
| RUNNER_TAG  ?= ${VERSION} | ||||
|  | @ -19,9 +20,10 @@ KUBECONTEXT ?= kind-acceptance | |||
| CLUSTER ?= acceptance | ||||
| CERT_MANAGER_VERSION ?= v1.1.1 | ||||
| KUBE_RBAC_PROXY_VERSION ?= v0.11.0 | ||||
| SHELLCHECK_VERSION ?= 0.10.0 | ||||
| 
 | ||||
| # Produce CRDs that work back to Kubernetes 1.11 (no version conversion)
 | ||||
| CRD_OPTIONS ?= "crd:generateEmbeddedObjectMeta=true" | ||||
| CRD_OPTIONS ?= "crd:generateEmbeddedObjectMeta=true,allowDangerousTypes=true" | ||||
| 
 | ||||
| # Get the currently used golang install path (in GOPATH/bin, unless GOBIN is set)
 | ||||
| ifeq (,$(shell go env GOBIN)) | ||||
|  | @ -31,6 +33,20 @@ GOBIN=$(shell go env GOBIN) | |||
| endif | ||||
| 
 | ||||
| TEST_ASSETS=$(PWD)/test-assets | ||||
| TOOLS_PATH=$(PWD)/.tools | ||||
| 
 | ||||
| OS_NAME := $(shell uname -s | tr A-Z a-z) | ||||
| 
 | ||||
| # The etcd packages that coreos maintain use different extensions for each *nix OS on their github release page.
 | ||||
| # ETCD_EXTENSION: the storage format file extension listed on the release page.
 | ||||
| # EXTRACT_COMMAND: the  appropriate CLI command for extracting this file format.
 | ||||
| ifeq ($(OS_NAME), darwin) | ||||
| ETCD_EXTENSION:=zip | ||||
| EXTRACT_COMMAND:=unzip | ||||
| else | ||||
| ETCD_EXTENSION:=tar.gz | ||||
| EXTRACT_COMMAND:=tar -xzf | ||||
| endif | ||||
| 
 | ||||
| # default list of platforms for which multiarch image is built
 | ||||
| ifeq (${PLATFORMS}, ) | ||||
|  | @ -51,12 +67,15 @@ endif | |||
| 
 | ||||
| all: manager | ||||
| 
 | ||||
| lint: | ||||
| 	docker run --rm -v $(PWD):/app -w /app golangci/golangci-lint:v2.5.0 golangci-lint run | ||||
| 
 | ||||
| GO_TEST_ARGS ?= -short | ||||
| 
 | ||||
| # Run tests
 | ||||
| test: generate fmt vet manifests | ||||
| 	go test $(GO_TEST_ARGS) ./... -coverprofile cover.out | ||||
| 	go test -fuzz=Fuzz -fuzztime=10s -run=Fuzz* ./controllers | ||||
| test: generate fmt vet manifests shellcheck | ||||
| 	go test $(GO_TEST_ARGS) `go list ./... | grep -v ./test_e2e_arc` -coverprofile cover.out | ||||
| 	go test -fuzz=Fuzz -fuzztime=10s -run=Fuzz* ./controllers/actions.summerwind.net | ||||
| 
 | ||||
| test-with-deps: kube-apiserver etcd kubectl | ||||
| 	# See https://pkg.go.dev/sigs.k8s.io/controller-runtime/pkg/envtest#pkg-constants | ||||
|  | @ -68,14 +87,21 @@ test-with-deps: kube-apiserver etcd kubectl | |||
| # Build manager binary
 | ||||
| manager: generate fmt vet | ||||
| 	go build -o bin/manager main.go | ||||
| 	go build -o bin/github-runnerscaleset-listener ./cmd/ghalistener | ||||
| 
 | ||||
| # Run against the configured Kubernetes cluster in ~/.kube/config
 | ||||
| run: generate fmt vet manifests | ||||
| 	go run ./main.go | ||||
| 
 | ||||
| run-scaleset: generate fmt vet | ||||
| 	CONTROLLER_MANAGER_POD_NAMESPACE=default \
 | ||||
| 	CONTROLLER_MANAGER_CONTAINER_IMAGE="${DOCKER_IMAGE_NAME}:${VERSION}" \
 | ||||
| 	go run -ldflags="-s -w -X 'github.com/actions/actions-runner-controller/build.Version=$(VERSION)'" \
 | ||||
| 	./main.go --auto-scaling-runner-set-only | ||||
| 
 | ||||
| # Install CRDs into a cluster
 | ||||
| install: manifests | ||||
| 	kustomize build config/crd | kubectl apply -f - | ||||
| 	kustomize build config/crd | kubectl apply --server-side -f - | ||||
| 
 | ||||
| # Uninstall CRDs from a cluster
 | ||||
| uninstall: manifests | ||||
|  | @ -83,20 +109,83 @@ uninstall: manifests | |||
| 
 | ||||
| # Deploy controller in the configured Kubernetes cluster in ~/.kube/config
 | ||||
| deploy: manifests | ||||
| 	cd config/manager && kustomize edit set image controller=${NAME}:${VERSION} | ||||
| 	kustomize build config/default | kubectl apply -f - | ||||
| 	cd config/manager && kustomize edit set image controller=${DOCKER_IMAGE_NAME}:${VERSION} | ||||
| 	kustomize build config/default | kubectl apply --server-side -f - | ||||
| 
 | ||||
| # Generate manifests e.g. CRD, RBAC etc.
 | ||||
| manifests: manifests-gen-crds chart-crds | ||||
| 
 | ||||
| manifests-gen-crds: controller-gen yq | ||||
| 	$(CONTROLLER_GEN) $(CRD_OPTIONS) rbac:roleName=manager-role webhook paths="./..." output:crd:artifacts:config=config/crd/bases | ||||
| 	for YAMLFILE in config/crd/bases/actions*.yaml; do \
 | ||||
| 		$(YQ) write --inplace "$$YAMLFILE" spec.preserveUnknownFields false; \
 | ||||
| 	done | ||||
| 	make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-type | ||||
| 	make manifests-gen-crds-fix DELETE_KEY=x-kubernetes-list-map-keys | ||||
| 
 | ||||
| manifests-gen-crds-fix: DELETE_KEY ?= | ||||
| manifests-gen-crds-fix: | ||||
| 	#runners | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.sidecarContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.dockerdContainerResources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.workVolumeClaimTemplate.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runners.yaml | ||||
| 	#runnerreplicasets | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.sidecarContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.dockerdContainerResources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.workVolumeClaimTemplate.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerreplicasets.yaml | ||||
| 	#runnerdeployments | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.sidecarContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.dockerdContainerResources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.workVolumeClaimTemplate.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnerdeployments.yaml | ||||
| 	#runnersets | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.volumeClaimTemplates.items.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.workVolumeClaimTemplate.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.summerwind.dev_runnersets.yaml | ||||
| 	#autoscalingrunnersets | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	#ehemeralrunnersets | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.template.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.ephemeralRunnerSpec.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.ephemeralRunnerSpec.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.ephemeralRunnerSpec.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.ephemeralRunnerSpec.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	# ephemeralrunners | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.spec.properties.ephemeralContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.spec.properties.containers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.spec.properties.initContainers.items.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunners.yaml | ||||
| 	$(YQ) 'del(.spec.versions[].schema.openAPIV3Schema.properties.spec.properties.spec.properties.volumes.items.properties.ephemeral.properties.volumeClaimTemplate.properties.spec.properties.resources.properties.claims.$(DELETE_KEY))' --inplace config/crd/bases/actions.github.com_ephemeralrunners.yaml | ||||
| 
 | ||||
| chart-crds: | ||||
| 	cp config/crd/bases/*.yaml charts/actions-runner-controller/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_autoscalingrunnersets.yaml charts/gha-runner-scale-set-controller/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_autoscalinglisteners.yaml charts/gha-runner-scale-set-controller/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_ephemeralrunnersets.yaml charts/gha-runner-scale-set-controller/crds/ | ||||
| 	cp config/crd/bases/actions.github.com_ephemeralrunners.yaml charts/gha-runner-scale-set-controller/crds/ | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_autoscalingrunnersets.yaml | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_autoscalinglisteners.yaml | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_ephemeralrunnersets.yaml | ||||
| 	rm charts/actions-runner-controller/crds/actions.github.com_ephemeralrunners.yaml | ||||
| 
 | ||||
| # Run go fmt against code
 | ||||
| fmt: | ||||
|  | @ -110,6 +199,10 @@ vet: | |||
| generate: controller-gen | ||||
| 	$(CONTROLLER_GEN) object:headerFile=./hack/boilerplate.go.txt paths="./..." | ||||
| 
 | ||||
| # Run shellcheck on runner scripts
 | ||||
| shellcheck: shellcheck-install | ||||
| 	$(TOOLS_PATH)/shellcheck --shell bash --source-path runner runner/*.sh runner/update-status hack/*.sh | ||||
| 
 | ||||
| docker-buildx: | ||||
| 	export DOCKER_CLI_EXPERIMENTAL=enabled ;\
 | ||||
| 	export DOCKER_BUILDKIT=1 | ||||
|  | @ -119,18 +212,20 @@ docker-buildx: | |||
| 	docker buildx build --platform ${PLATFORMS} \
 | ||||
| 		--build-arg RUNNER_VERSION=${RUNNER_VERSION} \
 | ||||
| 		--build-arg DOCKER_VERSION=${DOCKER_VERSION} \
 | ||||
| 		-t "${NAME}:${VERSION}" \
 | ||||
| 		--build-arg VERSION=${VERSION} \
 | ||||
| 		--build-arg COMMIT_SHA=${COMMIT_SHA} \
 | ||||
| 		-t "${DOCKER_IMAGE_NAME}:${VERSION}" \
 | ||||
| 		-f Dockerfile \
 | ||||
| 		. ${PUSH_ARG} | ||||
| 
 | ||||
| # Push the docker image
 | ||||
| docker-push: | ||||
| 	docker push ${NAME}:${VERSION} | ||||
| 	docker push ${DOCKER_IMAGE_NAME}:${VERSION} | ||||
| 	docker push ${RUNNER_NAME}:${RUNNER_TAG} | ||||
| 
 | ||||
| # Generate the release manifest file
 | ||||
| release: manifests | ||||
| 	cd config/manager && kustomize edit set image controller=${NAME}:${VERSION} | ||||
| 	cd config/manager && kustomize edit set image controller=${DOCKER_IMAGE_NAME}:${VERSION} | ||||
| 	mkdir -p release | ||||
| 	kustomize build config/default > release/actions-runner-controller.yaml | ||||
| 
 | ||||
|  | @ -154,7 +249,7 @@ acceptance/kind: | |||
| # Otherwise `load docker-image` fail while running `docker save`.
 | ||||
| # See https://kind.sigs.k8s.io/docs/user/known-issues/#docker-installed-with-snap
 | ||||
| acceptance/load: | ||||
| 	kind load docker-image ${NAME}:${VERSION} --name ${CLUSTER} | ||||
| 	kind load docker-image ${DOCKER_IMAGE_NAME}:${VERSION} --name ${CLUSTER} | ||||
| 	kind load docker-image quay.io/brancz/kube-rbac-proxy:$(KUBE_RBAC_PROXY_VERSION) --name ${CLUSTER} | ||||
| 	kind load docker-image ${RUNNER_NAME}:${RUNNER_TAG} --name ${CLUSTER} | ||||
| 	kind load docker-image docker:dind --name ${CLUSTER} | ||||
|  | @ -184,7 +279,7 @@ acceptance/teardown: | |||
| 	kind delete cluster --name ${CLUSTER} | ||||
| 
 | ||||
| acceptance/deploy: | ||||
| 	NAME=${NAME} DOCKER_USER=${DOCKER_USER} VERSION=${VERSION} RUNNER_NAME=${RUNNER_NAME} RUNNER_TAG=${RUNNER_TAG} TEST_REPO=${TEST_REPO} \
 | ||||
| 	DOCKER_IMAGE_NAME=${DOCKER_IMAGE_NAME} DOCKER_USER=${DOCKER_USER} VERSION=${VERSION} RUNNER_NAME=${RUNNER_NAME} RUNNER_TAG=${RUNNER_TAG} TEST_REPO=${TEST_REPO} \
 | ||||
| 	TEST_ORG=${TEST_ORG} TEST_ORG_REPO=${TEST_ORG_REPO} SYNC_PERIOD=${SYNC_PERIOD} \
 | ||||
| 	USE_RUNNERSET=${USE_RUNNERSET} \
 | ||||
| 	TEST_EPHEMERAL=${TEST_EPHEMERAL} \
 | ||||
|  | @ -193,8 +288,8 @@ acceptance/deploy: | |||
| acceptance/tests: | ||||
| 	acceptance/checks.sh | ||||
| 
 | ||||
| acceptance/runner/entrypoint: | ||||
| 	cd test/entrypoint/ && bash test.sh | ||||
| acceptance/runner/startup: | ||||
| 	cd test/startup/ && bash test.sh | ||||
| 
 | ||||
| # We use -count=1 instead of `go clean -testcache`
 | ||||
| # See https://terratest.gruntwork.io/docs/testing-best-practices/avoid-test-caching/
 | ||||
|  | @ -212,7 +307,7 @@ github-release: release | |||
| # Otherwise we get errors like the below:
 | ||||
| #   Error: failed to install CRD crds/actions.summerwind.dev_runnersets.yaml: CustomResourceDefinition.apiextensions.k8s.io "runnersets.actions.summerwind.dev" is invalid: [spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[containers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property, spec.validation.openAPIV3Schema.properties[spec].properties[template].properties[spec].properties[initContainers].items.properties[ports].items.properties[protocol].default: Required value: this property is in x-kubernetes-list-map-keys, so it must have a default or be a required property]
 | ||||
| #
 | ||||
| # Note that controller-gen newer than 0.6.0 is needed due to https://github.com/kubernetes-sigs/controller-tools/issues/448
 | ||||
| # Note that controller-gen newer than 0.8.0 is needed due to https://github.com/kubernetes-sigs/controller-tools/issues/448
 | ||||
| # Otherwise ObjectMeta embedded in Spec results in empty on the storage.
 | ||||
| controller-gen: | ||||
| ifeq (, $(shell which controller-gen)) | ||||
|  | @ -222,7 +317,7 @@ ifeq (, $(wildcard $(GOBIN)/controller-gen)) | |||
| 	CONTROLLER_GEN_TMP_DIR=$$(mktemp -d) ;\
 | ||||
| 	cd $$CONTROLLER_GEN_TMP_DIR ;\
 | ||||
| 	go mod init tmp ;\
 | ||||
| 	go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.7.0 ;\
 | ||||
| 	go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.19.0 ;\
 | ||||
| 	rm -rf $$CONTROLLER_GEN_TMP_DIR ;\
 | ||||
| 	} | ||||
| endif | ||||
|  | @ -242,13 +337,30 @@ ifeq (, $(wildcard $(GOBIN)/yq)) | |||
| 	YQ_TMP_DIR=$$(mktemp -d) ;\
 | ||||
| 	cd $$YQ_TMP_DIR ;\
 | ||||
| 	go mod init tmp ;\
 | ||||
| 	go install github.com/mikefarah/yq/v3@3.4.0 ;\
 | ||||
| 	go install github.com/mikefarah/yq/v4@v4.25.3 ;\
 | ||||
| 	rm -rf $$YQ_TMP_DIR ;\
 | ||||
| 	} | ||||
| endif | ||||
| YQ=$(GOBIN)/yq | ||||
| 
 | ||||
| OS_NAME := $(shell uname -s | tr A-Z a-z) | ||||
| # find or download shellcheck
 | ||||
| # download shellcheck if necessary
 | ||||
| shellcheck-install: | ||||
| ifeq (, $(wildcard $(TOOLS_PATH)/shellcheck)) | ||||
| 	echo "Downloading shellcheck" | ||||
| 	@{ \
 | ||||
| 	set -e ;\
 | ||||
| 	SHELLCHECK_TMP_DIR=$$(mktemp -d) ;\
 | ||||
| 	cd $$SHELLCHECK_TMP_DIR ;\
 | ||||
| 	curl -LO https://github.com/koalaman/shellcheck/releases/download/v$(SHELLCHECK_VERSION)/shellcheck-v$(SHELLCHECK_VERSION).$(OS_NAME).x86_64.tar.xz ;\
 | ||||
| 	tar Jxvf shellcheck-v$(SHELLCHECK_VERSION).$(OS_NAME).x86_64.tar.xz ;\
 | ||||
| 	cd $(CURDIR) ;\
 | ||||
| 	mkdir -p $(TOOLS_PATH) ;\
 | ||||
| 	mv $$SHELLCHECK_TMP_DIR/shellcheck-v$(SHELLCHECK_VERSION)/shellcheck $(TOOLS_PATH)/ ;\
 | ||||
| 	rm -rf $$SHELLCHECK_TMP_DIR ;\
 | ||||
| 	} | ||||
| endif | ||||
| SHELLCHECK=$(TOOLS_PATH)/shellcheck | ||||
| 
 | ||||
| # find or download etcd
 | ||||
| etcd: | ||||
|  | @ -258,12 +370,10 @@ ifeq (, $(wildcard $(TEST_ASSETS)/etcd)) | |||
| 	set -xe ;\
 | ||||
| 	INSTALL_TMP_DIR=$$(mktemp -d) ;\
 | ||||
| 	cd $$INSTALL_TMP_DIR ;\
 | ||||
| 	wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	wget https://github.com/coreos/etcd/releases/download/v3.4.22/etcd-v3.4.22-$(OS_NAME)-amd64.$(ETCD_EXTENSION);\
 | ||||
| 	mkdir -p $(TEST_ASSETS) ;\
 | ||||
| 	tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
 | ||||
| 	$(EXTRACT_COMMAND) etcd-v3.4.22-$(OS_NAME)-amd64.$(ETCD_EXTENSION) ;\
 | ||||
| 	mv etcd-v3.4.22-$(OS_NAME)-amd64/etcd $(TEST_ASSETS)/etcd ;\
 | ||||
| 	rm -rf $$INSTALL_TMP_DIR ;\
 | ||||
| 	} | ||||
| ETCD_BIN=$(TEST_ASSETS)/etcd | ||||
|  | @ -285,9 +395,7 @@ ifeq (, $(wildcard $(TEST_ASSETS)/kube-apiserver)) | |||
| 	wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	mkdir -p $(TEST_ASSETS) ;\
 | ||||
| 	tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
 | ||||
| 	rm -rf $$INSTALL_TMP_DIR ;\
 | ||||
| 	} | ||||
| KUBE_APISERVER_BIN=$(TEST_ASSETS)/kube-apiserver | ||||
|  | @ -309,8 +417,6 @@ ifeq (, $(wildcard $(TEST_ASSETS)/kubectl)) | |||
| 	wget https://github.com/kubernetes-sigs/kubebuilder/releases/download/v2.3.2/kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	mkdir -p $(TEST_ASSETS) ;\
 | ||||
| 	tar zxvf kubebuilder_2.3.2_$(OS_NAME)_amd64.tar.gz ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/etcd $(TEST_ASSETS)/etcd ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kube-apiserver $(TEST_ASSETS)/kube-apiserver ;\
 | ||||
| 	mv kubebuilder_2.3.2_$(OS_NAME)_amd64/bin/kubectl $(TEST_ASSETS)/kubectl ;\
 | ||||
| 	rm -rf $$INSTALL_TMP_DIR ;\
 | ||||
| 	} | ||||
|  |  | |||
							
								
								
									
										14
									
								
								PROJECT
								
								
								
								
							
							
						
						
									
										14
									
								
								PROJECT
								
								
								
								
							|  | @ -1,5 +1,5 @@ | |||
| domain: summerwind.dev | ||||
| repo: github.com/actions-runner-controller/actions-runner-controller | ||||
| repo: github.com/actions/actions-runner-controller | ||||
| resources: | ||||
| - group: actions | ||||
|   kind: Runner | ||||
|  | @ -10,4 +10,16 @@ resources: | |||
| - group: actions | ||||
|   kind: RunnerDeployment | ||||
|   version: v1alpha1 | ||||
| - group: actions | ||||
|   kind: AutoscalingRunnerSet | ||||
|   version: v1alpha1 | ||||
| - group: actions | ||||
|   kind: EphemeralRunnerSet | ||||
|   version: v1alpha1 | ||||
| - group: actions | ||||
|   kind: EphemeralRunner | ||||
|   version: v1alpha1 | ||||
| - group: actions | ||||
|   kind: AutoscalingListener | ||||
|   version: v1alpha1 | ||||
| version: "2" | ||||
|  |  | |||
							
								
								
									
										35
									
								
								SECURITY.md
								
								
								
								
							
							
						
						
									
										35
									
								
								SECURITY.md
								
								
								
								
							|  | @ -1,22 +1,31 @@ | |||
| # Security Policy | ||||
| Thanks for helping make GitHub safe for everyone. | ||||
| 
 | ||||
| ##  Sponsoring the project | ||||
| ## Security | ||||
| 
 | ||||
| This project is maintained by a small team of two and therefore lacks the resource to provide security fixes in a timely manner. | ||||
| GitHub takes the security of our software products and services seriously, including all of the open source code repositories managed through our GitHub organizations, such as [GitHub](https://github.com/GitHub). | ||||
| 
 | ||||
| If you have important business(es) that relies on this project, please consider sponsoring the project so that the maintainer(s) can commit to providing such service. | ||||
| Even though [open source repositories are outside of the scope of our bug bounty program](https://bounty.github.com/index.html#scope) and therefore not eligible for bounty rewards, we will ensure that your finding gets passed along to the appropriate maintainers for remediation.  | ||||
| 
 | ||||
| Please refer to https://github.com/sponsors/actions-runner-controller for available tiers. | ||||
| ## Reporting Security Issues | ||||
| 
 | ||||
| ## Supported Versions | ||||
| If you believe you have found a security vulnerability in any GitHub-owned repository, please report it to us through coordinated disclosure. | ||||
| 
 | ||||
| | Version | Supported          | | ||||
| | ------- | ------------------ | | ||||
| | 0.23.0  | :white_check_mark: | | ||||
| | < 0.23.0| :x:                | | ||||
| **Please do not report security vulnerabilities through public GitHub issues, discussions, or pull requests.** | ||||
| 
 | ||||
| ## Reporting a Vulnerability | ||||
| Instead, please send an email to opensource-security[@]github.com. | ||||
| 
 | ||||
| To report a security issue, please email ykuoka+arcsecurity(at)gmail.com with a description of the issue, the steps you took to create the issue, affected versions, and, if known, mitigations for the issue. | ||||
| Please include as much of the information listed below as you can to help us better understand and resolve the issue: | ||||
| 
 | ||||
| A maintainer will try to respond within 5 working days. If the issue is confirmed as a vulnerability, a Security Advisory will be opened. This project tries to follow a 90 day disclosure timeline. | ||||
|   * The type of issue (e.g., buffer overflow, SQL injection, or cross-site scripting) | ||||
|   * Full paths of source file(s) related to the manifestation of the issue | ||||
|   * The location of the affected source code (tag/branch/commit or direct URL) | ||||
|   * Any special configuration required to reproduce the issue | ||||
|   * Step-by-step instructions to reproduce the issue | ||||
|   * Proof-of-concept or exploit code (if possible) | ||||
|   * Impact of the issue, including how an attacker might exploit the issue | ||||
| 
 | ||||
| This information will help us triage your report more quickly. | ||||
| 
 | ||||
| ## Policy | ||||
| 
 | ||||
| See [GitHub's Safe Harbor Policy](https://docs.github.com/en/github/site-policy/github-bug-bounty-program-legal-safe-harbor#1-safe-harbor-terms) | ||||
|  | @ -2,59 +2,61 @@ | |||
| 
 | ||||
| * [Tools](#tools) | ||||
| * [Installation](#installation) | ||||
|   * [InternalError when calling webhook: context deadline exceeded](#internalerror-when-calling-webhook-context-deadline-exceeded) | ||||
|   * [Invalid header field value](#invalid-header-field-value) | ||||
|   * [Deployment fails on GKE due to webhooks](#deployment-fails-on-gke-due-to-webhooks) | ||||
|   * [Helm chart install failure: certificate signed by unknown authority](#helm-chart-install-failure-certificate-signed-by-unknown-authority) | ||||
| * [Operations](#operations) | ||||
|   * [Stuck runner kind or backing pod](#stuck-runner-kind-or-backing-pod) | ||||
|   * [Delay in jobs being allocated to runners](#delay-in-jobs-being-allocated-to-runners) | ||||
|   * [Runner coming up before network available](#runner-coming-up-before-network-available) | ||||
|   * [Outgoing network action hangs indefinitely](#outgoing-network-action-hangs-indefinitely) | ||||
|   * [Unable to scale to zero with TotalNumberOfQueuedAndInProgressWorkflowRuns](#unable-to-scale-to-zero-with-totalnumberofqueuedandinprogressworkflowruns) | ||||
|   * [Slow / failure to boot dind sidecar (default runner)](#slow--failure-to-boot-dind-sidecar-default-runner) | ||||
| 
 | ||||
| ## Tools | ||||
| 
 | ||||
| A list of tools which are helpful for troubleshooting | ||||
| 
 | ||||
| * https://github.com/rewanthtammana/kubectl-fields Kubernetes resources hierarchy parsing tool | ||||
| * https://github.com/stern/stern Multi pod and container log tailing for Kubernetes | ||||
| * [Kubernetes resources hierarchy parsing tool `kubectl-fields`](https://github.com/rewanthtammana/kubectl-fields) | ||||
| * [Multi pod and container log tailing for Kubernetes `stern`](https://github.com/stern/stern) | ||||
| 
 | ||||
| ## Installation | ||||
| 
 | ||||
| Troubeshooting runbooks that relate to ARC installation problems | ||||
| 
 | ||||
| ### Invalid header field value | ||||
| ### InternalError when calling webhook: context deadline exceeded | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| ```json | ||||
| 2020-11-12T22:17:30.693Z	ERROR	controller-runtime.controller	Reconciler error	 | ||||
| { | ||||
|   "controller": "runner", | ||||
|   "request": "actions-runner-system/runner-deployment-dk7q8-dk5c9", | ||||
|   "error": "failed to create registration token: Post \"https://api.github.com/orgs/$YOUR_ORG_HERE/actions/runners/registration-token\": net/http: invalid header field value \"Bearer $YOUR_TOKEN_HERE\\n\" for key Authorization" | ||||
| } | ||||
| This issue can come up for various reasons like leftovers from previous installations or not being able to access the K8s service's clusterIP associated with the admission webhook server (of ARC). | ||||
| 
 | ||||
| ```text | ||||
| Internal error occurred: failed calling webhook "mutate.runnerdeployment.actions.summerwind.dev": | ||||
| Post "https://actions-runner-controller-webhook.actions-runner-system.svc:443/mutate-actions-summerwind-dev-v1alpha1-runnerdeployment?timeout=10s": context deadline exceeded | ||||
| ``` | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| Your base64'ed PAT token has a new line at the end, it needs to be created without a `\n` added, either: | ||||
| * `echo -n $TOKEN | base64` | ||||
| * Create the secret as described in the docs using the shell and documented flags | ||||
| First we will try the common solution of checking webhook leftovers from previous installations: | ||||
| 
 | ||||
| 1. ```bash | ||||
|    kubectl get validatingwebhookconfiguration -A | ||||
|    kubectl get mutatingwebhookconfiguration -A | ||||
|    ``` | ||||
| 
 | ||||
| ### Deployment fails on GKE due to webhooks | ||||
| 2. If you see any webhooks related to actions-runner-controller, delete them: | ||||
| 
 | ||||
| **Problem** | ||||
|     ```bash | ||||
|     kubectl delete mutatingwebhookconfiguration actions-runner-controller-mutating-webhook-configuration | ||||
|     kubectl delete validatingwebhookconfiguration actions-runner-controller-validating-webhook-configuration | ||||
|     ``` | ||||
| 
 | ||||
| Due to GKEs firewall settings you may run into the following errors when trying to deploy runners on a private GKE cluster: | ||||
| If that didn't work then probably your K8s control-plane is somehow unable to access the K8s service's clusterIP associated with the admission webhook server: | ||||
| 
 | ||||
| ``` | ||||
| Internal error occurred: failed calling webhook "mutate.runner.actions.summerwind.dev":  | ||||
| Post https://webhook-service.actions-runner-system.svc:443/mutate-actions-summerwind-dev-v1alpha1-runner?timeout=10s:  | ||||
| context deadline exceeded | ||||
| ``` | ||||
| 1. You're running apiserver as a binary and you didn't make service cluster IPs available to the host network.  | ||||
| 2. You're running the apiserver in the pod but your pod network (i.e. CNI plugin installation and config) is not good so your pods(like kube-apiserver) in the K8s control-plane nodes can't access ARC's admission webhook server pod(s) in probably data-plane nodes. | ||||
| 
 | ||||
| **Solution**<br /> | ||||
| Another reason could be due to GKEs firewall settings you may run into the following errors when trying to deploy runners on a private GKE cluster: | ||||
| 
 | ||||
| To fix this, you may either: | ||||
| 
 | ||||
|  | @ -63,7 +65,7 @@ To fix this, you may either: | |||
| 
 | ||||
|    ```sh | ||||
|    # With helm, you'd set `webhookPort` to the port number of your choice | ||||
|    # See https://github.com/actions-runner-controller/actions-runner-controller/pull/1410/files for more information | ||||
|    # See https://github.com/actions/actions-runner-controller/pull/1410/files for more information | ||||
|    helm upgrade --install --namespace actions-runner-system --create-namespace \ | ||||
|                 --wait actions-runner-controller actions-runner-controller/actions-runner-controller \ | ||||
|                 --set webhookPort=10250 | ||||
|  | @ -88,6 +90,58 @@ To fix this, you may either: | |||
|    gcloud compute firewall-rules create k8s-cert-manager --source-ranges $SOURCE --target-tags $WORKER_NODES_TAG  --allow TCP:9443 --network $NETWORK | ||||
|    ``` | ||||
| 
 | ||||
| ### Invalid header field value | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| ```json | ||||
| 2020-11-12T22:17:30.693Z ERROR controller-runtime.controller Reconciler error  | ||||
| { | ||||
|   "controller": "runner", | ||||
|   "request": "actions-runner-system/runner-deployment-dk7q8-dk5c9", | ||||
|   "error": "failed to create registration token: Post \"https://api.github.com/orgs/$YOUR_ORG_HERE/actions/runners/registration-token\": net/http: invalid header field value \"Bearer $YOUR_TOKEN_HERE\\n\" for key Authorization" | ||||
| } | ||||
| ``` | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| Your base64'ed PAT token has a new line at the end, it needs to be created without a `\n` added, either: | ||||
| 
 | ||||
| * `echo -n $TOKEN | base64` | ||||
| * Create the secret as described in the docs using the shell and documented flags | ||||
| 
 | ||||
| ### Helm chart install failure: certificate signed by unknown authority | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| ```text | ||||
| Error: UPGRADE FAILED: failed to create resource: Internal error occurred: failed calling webhook "webhook.cert-manager.io": failed to call webhook: Post "https://cert-manager-webhook.cert-manager.svc:443/mutate?timeout=10s": x509: certificate signed by unknown authority | ||||
| ``` | ||||
| 
 | ||||
| Apparently, it's failing while `helm` is creating one of resources defined in the ARC chart and the cause was that cert-manager's webhook is not working correctly, due to the missing or the invalid CA certficate. | ||||
| 
 | ||||
| You'd try to tail logs from the `cert-manager-cainjector` and see it's failing with an error like: | ||||
| 
 | ||||
| ```text | ||||
| $ kubectl -n cert-manager logs cert-manager-cainjector-7cdbb9c945-g6bt4 | ||||
| I0703 03:31:55.159339       1 start.go:91] "starting" version="v1.1.1" revision="3ac7418070e22c87fae4b22603a6b952f797ae96" | ||||
| I0703 03:31:55.615061       1 leaderelection.go:243] attempting to acquire leader lease  kube-system/cert-manager-cainjector-leader-election... | ||||
| I0703 03:32:10.738039       1 leaderelection.go:253] successfully acquired lease kube-system/cert-manager-cainjector-leader-election | ||||
| I0703 03:32:10.739941       1 recorder.go:52] cert-manager/controller-runtime/manager/events "msg"="Normal"  "message"="cert-manager-cainjector-7cdbb9c945-g6bt4_88e4bc70-eded-4343-a6fb-0ddd6434eb55 became leader" "object"={"kind":"ConfigMap","namespace":"kube-system","name":"cert-manager-cainjector-leader-election","uid":"942a021e-364c-461a-978c-f54a95723cdc","apiVersion":"v1","resourceVersion":"1576"} "reason"="LeaderElection" | ||||
| E0703 03:32:11.192128       1 start.go:119] cert-manager/ca-injector "msg"="manager goroutine exited" "error"=null | ||||
| I0703 03:32:12.339197       1 request.go:645] Throttling request took 1.047437675s, request: GET:https://10.96.0.1:443/apis/storage.k8s.io/v1beta1?timeout=32s | ||||
| E0703 03:32:13.143790       1 start.go:151] cert-manager/ca-injector "msg"="Error registering certificate based controllers. Retrying after 5 seconds." "error"="no matches for kind \"MutatingWebhookConfiguration\" in version \"admissionregistration.k8s.io/v1beta1\"" | ||||
| Error: error registering secret controller: no matches for kind "MutatingWebhookConfiguration" in version "admissionregistration.k8s.io/v1beta1" | ||||
| ``` | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| Your cluster is based on a new enough Kubernetes of version 1.22 or greater which does not support the legacy `admissionregistration.k8s.io/v1beta1` API anymore, and your `cert-manager` is not up-to-date hence it's still trying to use the leagcy Kubernetes API. | ||||
| 
 | ||||
| In many cases, it's not an option to downgrade Kubernetes. So, just upgrade `cert-manager` to a more recent version that does have have the support for the specific Kubernetes version you're using. | ||||
| 
 | ||||
| See <https://cert-manager.io/docs/installation/supported-releases/> for the list of available cert-manager versions. | ||||
| 
 | ||||
| ## Operations | ||||
| 
 | ||||
| Troubeshooting runbooks that relate to ARC operational problems | ||||
|  | @ -102,7 +156,7 @@ Sometimes either the runner kind (`kubectl get runners`) or it's underlying pod | |||
| 
 | ||||
| Remove the finaliser from the relevent runner kind or pod | ||||
| 
 | ||||
| ``` | ||||
| ```text | ||||
| # Get all kind runners and remove the finalizer | ||||
| $ kubectl get runners --no-headers | awk {'print $1'} | xargs kubectl patch runner --type merge -p '{"metadata":{"finalizers":null}}' | ||||
| 
 | ||||
|  | @ -117,7 +171,7 @@ are in a namespace not shared with anything else_ | |||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| ARC isn't involved in jobs actually getting allocated to a runner. ARC is responsible for orchestrating runners and the runner lifecycle. Why some people see large delays in job allocation is not clear however it has been https://github.com/actions-runner-controller/actions-runner-controller/issues/1387#issuecomment-1122593984 that this is caused from the self-update process somehow. | ||||
| ARC isn't involved in jobs actually getting allocated to a runner. ARC is responsible for orchestrating runners and the runner lifecycle. Why some people see large delays in job allocation is not clear however it has been confirmed https://github.com/actions/actions-runner-controller/issues/1387#issuecomment-1122593984 that this is caused from the self-update process somehow. | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
|  | @ -144,7 +198,7 @@ spec: | |||
| If you're running your action runners on a service mesh like Istio, you might | ||||
| have problems with runner configuration accompanied by logs like: | ||||
| 
 | ||||
| ``` | ||||
| ```text | ||||
| .... | ||||
| runner Starting Runner listener with startup type: service | ||||
| runner Started listener process | ||||
|  | @ -159,11 +213,11 @@ configuration script tries to communicate with the network. | |||
| 
 | ||||
| More broadly, there are many other circumstances where the runner pod coming up first can cause issues. | ||||
| 
 | ||||
| **Solution**<br /> | ||||
| **Solution** | ||||
| 
 | ||||
| > Added originally to help users with older istio instances. | ||||
| > Newer Istio instances can use Istio's `holdApplicationUntilProxyStarts` attribute ([istio/istio#11130](https://github.com/istio/istio/issues/11130)) to avoid having to delay starting up the runner. | ||||
| > Please read the discussion in [#592](https://github.com/actions-runner-controller/actions-runner-controller/pull/592) for more information. | ||||
| > Please read the discussion in [#592](https://github.com/actions/actions-runner-controller/pull/592) for more information. | ||||
| 
 | ||||
| You can add a delay to the runner's entrypoint script by setting the `STARTUP_DELAY_IN_SECONDS` environment variable for the runner pod. This will cause the script to sleep X seconds, this works with any runner kind. | ||||
| 
 | ||||
|  | @ -181,7 +235,7 @@ spec: | |||
|           value: "5" | ||||
| ``` | ||||
| 
 | ||||
| ## Outgoing network action hangs indefinitely | ||||
| ### Outgoing network action hangs indefinitely | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
|  | @ -206,10 +260,30 @@ spec: | |||
|       env: [] | ||||
| ``` | ||||
| 
 | ||||
| There may be more places you need to tweak for MTU. | ||||
| Please consult issues like #651 for more information. | ||||
| If the issue still persists, you can set the `ARC_DOCKER_MTU_PROPAGATION` to propagate the host MTU to networks created | ||||
| by the GitHub Runner. For instance: | ||||
| 
 | ||||
| ## Unable to scale to zero with TotalNumberOfQueuedAndInProgressWorkflowRuns | ||||
| ```yaml | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: RunnerDeployment | ||||
| metadata: | ||||
|   name: github-runner | ||||
|   namespace: github-system | ||||
| spec: | ||||
|   replicas: 6 | ||||
|   template: | ||||
|     spec: | ||||
|       dockerMTU: 1400 | ||||
|       repository: $username/$repo | ||||
|       env: | ||||
|         - name: ARC_DOCKER_MTU_PROPAGATION | ||||
|           value: "true" | ||||
| ``` | ||||
| 
 | ||||
| You can read the discussion regarding this issue in | ||||
| [#1406](https://github.com/actions/actions-runner-controller/issues/1046). | ||||
| 
 | ||||
| ### Unable to scale to zero with TotalNumberOfQueuedAndInProgressWorkflowRuns | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
|  | @ -217,6 +291,40 @@ HRA doesn't scale the RunnerDeployment to zero, even though you did configure HR | |||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| You very likely have some dangling workflow jobs stuck in `queued` or `in_progress` as seen in [#1057](https://github.com/actions-runner-controller/actions-runner-controller/issues/1057#issuecomment-1133439061). | ||||
| You very likely have some dangling workflow jobs stuck in `queued` or `in_progress` as seen in [#1057](https://github.com/actions/actions-runner-controller/issues/1057#issuecomment-1133439061). | ||||
| 
 | ||||
| Manually call [the "list workflow runs" API](https://docs.github.com/en/rest/actions/workflow-runs#list-workflow-runs-for-a-repository), and [remove the dangling workflow job(s)](https://docs.github.com/en/rest/actions/workflow-runs#delete-a-workflow-run). | ||||
| 
 | ||||
| ### Slow / failure to boot dind sidecar (default runner) | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| If you noticed that it takes several minutes for sidecar dind container to be created or it exits with with error just after being created it might indicate that you are experiencing disk performance issue. You might see message `failed to reserve container name` when scaling up multiple runners at once. When you ssh on kubernetes node that problematic pods were scheduled on you can use tools like `atop`, `htop` or `iotop` to check IO usage and cpu time percentage used on iowait. If you see that disk usage is high (80-100%) and iowaits are taking a significant chunk of you cpu time (normally it should not be higher than 10%) it means that performance is being bottlenecked by slow disk. | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| The solution is to switch to using faster storage, if you are experiencing this issue you are probably using HDD storage. Switching to SSD storage fixed the problem in my case. Most cloud providers have a list of storage options to use just pick something faster that your current disk, for on prem clusters you will need to invest in some SSDs. | ||||
| 
 | ||||
| ### Dockerd no space left on device | ||||
| 
 | ||||
| **Problem** | ||||
| 
 | ||||
| If you are running many containers on your runner you might encounter an issue where docker daemon is unable to start new containers and you see error `no space left on device`.   | ||||
| 
 | ||||
| **Solution** | ||||
| 
 | ||||
| Add a `dockerVarRunVolumeSizeLimit` key in your runner's spec with a higher size limit (the default is 1M) For instance: | ||||
| 
 | ||||
| ```yaml | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: RunnerDeployment | ||||
| metadata: | ||||
|   name: github-runner | ||||
|   namespace: github-system | ||||
| spec: | ||||
|   replicas: 6 | ||||
|   template: | ||||
|     spec: | ||||
|       dockerVarRunVolumeSizeLimit: 50M | ||||
|       env: [] | ||||
| ``` | ||||
|  | @ -0,0 +1,100 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| # See https://developers.cloudflare.com/cloudflare-one/tutorials/many-cfd-one-tunnel/ | ||||
| 
 | ||||
| kubectl create ns tunnel || : | ||||
| 
 | ||||
| kubectl -n tunnel delete secret tunnel-credentials || : | ||||
| 
 | ||||
| kubectl -n tunnel create secret generic tunnel-credentials \ | ||||
|   --from-file=credentials.json=$HOME/.cloudflared/${TUNNEL_ID}.json || : | ||||
| 
 | ||||
| cat <<MANIFEST | kubectl -n tunnel ${OP} -f - | ||||
| --- | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: cloudflared | ||||
| spec: | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       app: cloudflared | ||||
|   replicas: 2 # You could also consider elastic scaling for this deployment | ||||
|   template: | ||||
|     metadata: | ||||
|       labels: | ||||
|         app: cloudflared | ||||
|     spec: | ||||
|       containers: | ||||
|       - name: cloudflared | ||||
|         image: cloudflare/cloudflared:latest | ||||
|         args: | ||||
|         - tunnel | ||||
|         # Points cloudflared to the config file, which configures what | ||||
|         # cloudflared will actually do. This file is created by a ConfigMap | ||||
|         # below. | ||||
|         - --config | ||||
|         - /etc/cloudflared/config/config.yaml | ||||
|         - run | ||||
|         livenessProbe: | ||||
|           httpGet: | ||||
|             # Cloudflared has a /ready endpoint which returns 200 if and only if | ||||
|             # it has an active connection to the edge. | ||||
|             path: /ready | ||||
|             port: 2000 | ||||
|           failureThreshold: 1 | ||||
|           initialDelaySeconds: 10 | ||||
|           periodSeconds: 10 | ||||
|         volumeMounts: | ||||
|         - name: config | ||||
|           mountPath: /etc/cloudflared/config | ||||
|           readOnly: true | ||||
|         # Each tunnel has an associated "credentials file" which authorizes machines | ||||
|         # to run the tunnel. cloudflared will read this file from its local filesystem, | ||||
|         # and it'll be stored in a k8s secret. | ||||
|         - name: creds | ||||
|           mountPath: /etc/cloudflared/creds | ||||
|           readOnly: true | ||||
|       volumes: | ||||
|       - name: creds | ||||
|         secret: | ||||
|           secretName: tunnel-credentials | ||||
|       # Create a config.yaml file from the ConfigMap below. | ||||
|       - name: config | ||||
|         configMap: | ||||
|           name: cloudflared | ||||
|           items: | ||||
|           - key: config.yaml | ||||
|             path: config.yaml | ||||
| --- | ||||
| # This ConfigMap is just a way to define the cloudflared config.yaml file in k8s. | ||||
| # It's useful to define it in k8s, rather than as a stand-alone .yaml file, because | ||||
| # this lets you use various k8s templating solutions (e.g. Helm charts) to | ||||
| # parameterize your config, instead of just using string literals. | ||||
| apiVersion: v1 | ||||
| kind: ConfigMap | ||||
| metadata: | ||||
|   name: cloudflared | ||||
| data: | ||||
|   config.yaml: | | ||||
|     # Name of the tunnel you want to run | ||||
|     tunnel: ${TUNNEL_NAME} | ||||
|     credentials-file: /etc/cloudflared/creds/credentials.json | ||||
|     # Serves the metrics server under /metrics and the readiness server under /ready | ||||
|     metrics: 0.0.0.0:2000 | ||||
|     # Autoupdates applied in a k8s pod will be lost when the pod is removed or restarted, so | ||||
|     # autoupdate doesn't make sense in Kubernetes. However, outside of Kubernetes, we strongly | ||||
|     # recommend using autoupdate. | ||||
|     no-autoupdate: true | ||||
|     ingress: | ||||
|     # The first rule proxies traffic to the httpbin sample Service defined in app.yaml | ||||
|     - hostname: ${TUNNEL_HOSTNAME} | ||||
|       service: http://actions-runner-controller-actions-metrics-server.actions-runner-system:80 | ||||
|       path: /metrics$ | ||||
|     - hostname: ${TUNNEL_HOSTNAME} | ||||
|       service: http://actions-runner-controller-github-webhook-server.actions-runner-system:80 | ||||
|     # This rule matches any traffic which didn't match a previous rule, and responds with HTTP 404. | ||||
|     - service: http_status:404 | ||||
| MANIFEST | ||||
| 
 | ||||
| kubectl -n tunnel delete po -l app=cloudflared || : | ||||
|  | @ -35,14 +35,63 @@ else | |||
|   echo 'Skipped deploying secret "github-webhook-server". Set WEBHOOK_GITHUB_TOKEN to deploy.' 1>&2 | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${WEBHOOK_GITHUB_TOKEN}" ] && [ -z "${CREATE_SECRETS_USING_HELM}" ]; then | ||||
|   kubectl -n actions-runner-system delete secret \ | ||||
|       actions-metrics-server || : | ||||
|   kubectl -n actions-runner-system create secret generic \ | ||||
|       actions-metrics-server \ | ||||
|       --from-literal=github_token=${WEBHOOK_GITHUB_TOKEN:?WEBHOOK_GITHUB_TOKEN must not be empty} | ||||
| else | ||||
|   echo 'Skipped deploying secret "actions-metrics-server". Set WEBHOOK_GITHUB_TOKEN to deploy.' 1>&2 | ||||
| fi | ||||
| 
 | ||||
| tool=${ACCEPTANCE_TEST_DEPLOYMENT_TOOL} | ||||
| 
 | ||||
| TEST_ID=${TEST_ID:-default} | ||||
| 
 | ||||
| if [ "${tool}" == "helm" ]; then | ||||
|   set -v | ||||
| 
 | ||||
|   CHART=${CHART:-charts/actions-runner-controller} | ||||
| 
 | ||||
|   flags=() | ||||
|   if [ "${IMAGE_PULL_SECRET}" != "" ]; then | ||||
|     flags+=( --set imagePullSecrets[0].name=${IMAGE_PULL_SECRET}) | ||||
|     flags+=( --set image.actionsRunnerImagePullSecrets[0].name=${IMAGE_PULL_SECRET}) | ||||
|     flags+=( --set githubWebhookServer.imagePullSecrets[0].name=${IMAGE_PULL_SECRET}) | ||||
|     flags+=( --set actionsMetricsServer.imagePullSecrets[0].name=${IMAGE_PULL_SECRET}) | ||||
|   fi | ||||
|   if [ "${WATCH_NAMESPACE}" != "" ]; then | ||||
|     flags+=( --set watchNamespace=${WATCH_NAMESPACE} --set singleNamespace=true) | ||||
|   fi | ||||
|   if [ "${CHART_VERSION}" != "" ]; then | ||||
|     flags+=( --version ${CHART_VERSION}) | ||||
|   fi | ||||
|   if [ "${LOG_FORMAT}" != "" ]; then | ||||
|     flags+=( --set logFormat=${LOG_FORMAT}) | ||||
|     flags+=( --set githubWebhookServer.logFormat=${LOG_FORMAT}) | ||||
|     flags+=( --set actionsMetricsServer.logFormat=${LOG_FORMAT}) | ||||
|   fi | ||||
|   if [ "${ADMISSION_WEBHOOKS_TIMEOUT}" != "" ]; then | ||||
|     flags+=( --set admissionWebHooks.timeoutSeconds=${ADMISSION_WEBHOOKS_TIMEOUT}) | ||||
|   fi | ||||
|   if [ -n "${CREATE_SECRETS_USING_HELM}" ]; then | ||||
|     if [ -z "${WEBHOOK_GITHUB_TOKEN}" ]; then | ||||
|       echo 'Failed deploying secret "actions-metrics-server" using helm. Set WEBHOOK_GITHUB_TOKEN to deploy.' 1>&2 | ||||
|       exit 1 | ||||
|     fi | ||||
|     flags+=( --set actionsMetricsServer.secret.create=true) | ||||
|     flags+=( --set actionsMetricsServer.secret.github_token=${WEBHOOK_GITHUB_TOKEN}) | ||||
|   fi | ||||
|   if [ -n "${GITHUB_WEBHOOK_SERVER_ENV_NAME}" ] && [ -n "${GITHUB_WEBHOOK_SERVER_ENV_VALUE}" ]; then | ||||
|     flags+=( --set githubWebhookServer.env[0].name=${GITHUB_WEBHOOK_SERVER_ENV_NAME}) | ||||
|     flags+=( --set githubWebhookServer.env[0].value=${GITHUB_WEBHOOK_SERVER_ENV_VALUE}) | ||||
|   fi | ||||
| 
 | ||||
|   set -vx | ||||
| 
 | ||||
|   helm upgrade --install actions-runner-controller \ | ||||
|     charts/actions-runner-controller \ | ||||
|     ${CHART} \ | ||||
|     -n actions-runner-system \ | ||||
|     --create-namespace \ | ||||
|     --set syncPeriod=${SYNC_PERIOD} \ | ||||
|  | @ -51,6 +100,9 @@ if [ "${tool}" == "helm" ]; then | |||
|     --set image.tag=${VERSION} \ | ||||
|     --set podAnnotations.test-id=${TEST_ID} \ | ||||
|     --set githubWebhookServer.podAnnotations.test-id=${TEST_ID} \ | ||||
|     --set actionsMetricsServer.podAnnotations.test-id=${TEST_ID} \ | ||||
|     ${flags[@]} --set image.imagePullPolicy=${IMAGE_PULL_POLICY} \ | ||||
|     --set image.dindSidecarRepositoryAndTag=${DIND_SIDECAR_REPOSITORY_AND_TAG} \ | ||||
|     -f ${VALUES_FILE} | ||||
|   set +v | ||||
|   # To prevent `CustomResourceDefinition.apiextensions.k8s.io "runners.actions.summerwind.dev" is invalid: metadata.annotations: Too long: must have at most 262144 bytes` | ||||
|  | @ -76,56 +128,3 @@ kubectl -n actions-runner-system wait deploy/actions-runner-controller --for con | |||
| 
 | ||||
| # Adhocly wait for some time until actions-runner-controller's admission webhook gets ready | ||||
| sleep 20 | ||||
| 
 | ||||
| RUNNER_LABEL=${RUNNER_LABEL:-self-hosted} | ||||
| 
 | ||||
| if [ -n "${TEST_REPO}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_ORG= RUNNER_MIN_REPLICAS=${REPO_RUNNER_MIN_REPLICAS} NAME=repo-runnerset envsubst | kubectl apply -f - | ||||
|   else | ||||
|     echo 'Deploying runnerdeployment and hra. Set USE_RUNNERSET if you want to deploy runnerset instead.' | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_ORG= RUNNER_MIN_REPLICAS=${REPO_RUNNER_MIN_REPLICAS} NAME=repo-runnerdeploy envsubst | kubectl apply -f - | ||||
|   fi | ||||
| else | ||||
|   echo 'Skipped deploying runnerdeployment and hra. Set TEST_REPO to "yourorg/yourrepo" to deploy.' | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${TEST_ORG}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} NAME=org-runnerset envsubst | kubectl apply -f - | ||||
|   else | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} NAME=org-runnerdeploy envsubst | kubectl apply -f - | ||||
|   fi | ||||
| 
 | ||||
|   if [ -n "${TEST_ORG_GROUP}" ]; then | ||||
|     if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|       cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ORG_GROUP} NAME=orggroup-runnerset envsubst | kubectl apply -f - | ||||
|     else | ||||
|       cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ORG_GROUP} NAME=orggroup-runnerdeploy envsubst | kubectl apply -f - | ||||
|     fi | ||||
|   else | ||||
|     echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ORG_GROUP to deploy.' | ||||
|   fi | ||||
| else | ||||
|   echo 'Skipped deploying organizational runnerdeployment. Set TEST_ORG to deploy.' | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${TEST_ENTERPRISE}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} NAME=enterprise-runnerset envsubst | kubectl apply -f - | ||||
|   else | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} NAME=enterprise-runnerdeploy envsubst | kubectl apply -f - | ||||
|   fi | ||||
| 
 | ||||
|   if [ -n "${TEST_ENTERPRISE_GROUP}" ]; then | ||||
|     if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|       cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ENTERPRISE_GROUP} NAME=enterprisegroup-runnerset envsubst | kubectl apply -f - | ||||
|     else | ||||
|       cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ENTERPRISE_GROUP} NAME=enterprisegroup-runnerdeploy envsubst | kubectl apply -f - | ||||
|     fi | ||||
|   else | ||||
|     echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ENTERPRISE_GROUP to deploy.' | ||||
|   fi | ||||
| else | ||||
|   echo 'Skipped deploying enterprise runnerdeployment. Set TEST_ENTERPRISE to deploy.' | ||||
| fi | ||||
|  |  | |||
|  | @ -0,0 +1,64 @@ | |||
| #!/usr/bin/env bash | ||||
| 
 | ||||
| set -e | ||||
| 
 | ||||
| OP=${OP:-apply} | ||||
| 
 | ||||
| RUNNER_LABEL=${RUNNER_LABEL:-self-hosted} | ||||
| 
 | ||||
| # See https://github.com/actions/actions-runner-controller/issues/2123 | ||||
| kubectl delete secret generic docker-config || : | ||||
| kubectl create secret generic docker-config --from-file .dockerconfigjson=<(jq -M 'del(.aliases)' $HOME/.docker/config.json) --type=kubernetes.io/dockerconfigjson || : | ||||
| 
 | ||||
| cat acceptance/testdata/kubernetes_container_mode.envsubst.yaml  | NAMESPACE=${RUNNER_NAMESPACE} envsubst  | kubectl apply -f - | ||||
| 
 | ||||
| if [ -n "${TEST_REPO}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_ORG= RUNNER_MIN_REPLICAS=${REPO_RUNNER_MIN_REPLICAS} NAME=repo-runnerset envsubst | kubectl ${OP} -f - | ||||
|   else | ||||
|     echo "Running ${OP} runnerdeployment and hra. Set USE_RUNNERSET if you want to deploy runnerset instead." | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_ORG= RUNNER_MIN_REPLICAS=${REPO_RUNNER_MIN_REPLICAS} NAME=repo-runnerdeploy envsubst | kubectl ${OP} -f - | ||||
|   fi | ||||
| else | ||||
|   echo "Skipped ${OP} for runnerdeployment and hra. Set TEST_REPO to "yourorg/yourrepo" to deploy." | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${TEST_ORG}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} NAME=org-runnerset envsubst | kubectl ${OP} -f - | ||||
|   else | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} NAME=org-runnerdeploy envsubst | kubectl ${OP} -f - | ||||
|   fi | ||||
| 
 | ||||
|   if [ -n "${TEST_ORG_GROUP}" ]; then | ||||
|     if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|       cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ORG_GROUP} NAME=orggroup-runnerset envsubst | kubectl ${OP} -f - | ||||
|     else | ||||
|       cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ENTERPRISE= TEST_REPO= RUNNER_MIN_REPLICAS=${ORG_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ORG_GROUP} NAME=orggroup-runnerdeploy envsubst | kubectl ${OP} -f - | ||||
|     fi | ||||
|   else | ||||
|     echo "Skipped ${OP} on enterprise runnerdeployment. Set TEST_ORG_GROUP to ${OP}." | ||||
|   fi | ||||
| else | ||||
|   echo "Skipped ${OP} on organizational runnerdeployment. Set TEST_ORG to ${OP}." | ||||
| fi | ||||
| 
 | ||||
| if [ -n "${TEST_ENTERPRISE}" ]; then | ||||
|   if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|     cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} NAME=enterprise-runnerset envsubst | kubectl ${OP} -f - | ||||
|   else | ||||
|     cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} NAME=enterprise-runnerdeploy envsubst | kubectl ${OP} -f - | ||||
|   fi | ||||
| 
 | ||||
|   if [ -n "${TEST_ENTERPRISE_GROUP}" ]; then | ||||
|     if [ "${USE_RUNNERSET}" != "false" ]; then | ||||
|       cat acceptance/testdata/runnerset.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ENTERPRISE_GROUP} NAME=enterprisegroup-runnerset envsubst | kubectl ${OP} -f - | ||||
|     else | ||||
|       cat acceptance/testdata/runnerdeploy.envsubst.yaml | TEST_ORG= TEST_REPO= RUNNER_MIN_REPLICAS=${ENTERPRISE_RUNNER_MIN_REPLICAS} TEST_GROUP=${TEST_ENTERPRISE_GROUP} NAME=enterprisegroup-runnerdeploy envsubst | kubectl ${OP} -f - | ||||
|     fi | ||||
|   else | ||||
|     echo "Skipped ${OP} on enterprise runnerdeployment. Set TEST_ENTERPRISE_GROUP to ${OP}." | ||||
|   fi | ||||
| else | ||||
|   echo "Skipped ${OP} on enterprise runnerdeployment. Set TEST_ENTERPRISE to ${OP}." | ||||
| fi | ||||
|  | @ -10,16 +10,17 @@ env: | |||
| 
 | ||||
| jobs: | ||||
|   assume-role-in-runner-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     steps: | ||||
|       - name: Test aws-actions/configure-aws-credentials Action | ||||
|         uses: aws-actions/configure-aws-credentials@v1 | ||||
|         # https://github.com/aws-actions/configure-aws-credentials/releases/tag/v4.1.0 | ||||
|         uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 | ||||
|         with: | ||||
|           aws-region: ${{ env.AWS_REGION }} | ||||
|           role-to-assume: ${{ env.ASSUME_ROLE_ARN }} | ||||
|           role-duration-seconds: 900 | ||||
|   assume-role-in-container-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     container: | ||||
|       image: amazon/aws-cli | ||||
|       env: | ||||
|  | @ -29,7 +30,8 @@ jobs: | |||
|         - /var/run/secrets/eks.amazonaws.com/serviceaccount/token:/var/run/secrets/eks.amazonaws.com/serviceaccount/token | ||||
|     steps: | ||||
|       - name: Test aws-actions/configure-aws-credentials Action in container | ||||
|         uses: aws-actions/configure-aws-credentials@v1 | ||||
|         # https://github.com/aws-actions/configure-aws-credentials/releases/tag/v4.1.0 | ||||
|         uses: aws-actions/configure-aws-credentials@ececac1a45f3b08a01d2dd070d28d111c5fe6722 | ||||
|         with: | ||||
|           aws-region: ${{ env.AWS_REGION }} | ||||
|           role-to-assume: ${{ env.ASSUME_ROLE_ARN }} | ||||
|  |  | |||
|  | @ -8,7 +8,7 @@ env: | |||
| 
 | ||||
| jobs: | ||||
|   run-step-in-container-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     container: | ||||
|       image: alpine | ||||
|     steps: | ||||
|  | @ -21,7 +21,7 @@ jobs: | |||
|               exit 1 | ||||
|           fi | ||||
|   setup-python-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     steps: | ||||
|       - name: Print native Python environment | ||||
|         run: | | ||||
|  | @ -41,11 +41,11 @@ jobs: | |||
|             echo "Python version detected : $(python --version 2>&1)" | ||||
|           fi | ||||
|   setup-node-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     steps: | ||||
|       - uses: actions/setup-node@v2 | ||||
|         with: | ||||
|           node-version: '12' | ||||
|           node-version: "12" | ||||
|       - name: Test actions/setup-node works | ||||
|         run: | | ||||
|           VERSION=$(node --version | cut -c 2- | cut -d '.' -f1) | ||||
|  | @ -57,9 +57,10 @@ jobs: | |||
|             echo "Node version detected : $(node --version 2>&1)" | ||||
|           fi | ||||
|   setup-ruby-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     steps: | ||||
|       - uses: ruby/setup-ruby@v1 | ||||
|       # https://github.com/ruby/setup-ruby/releases/tag/v1.227.0 | ||||
|       - uses: ruby/setup-ruby@1a615958ad9d422dd932dc1d5823942ee002799f | ||||
|         with: | ||||
|           ruby-version: 3.0 | ||||
|           bundler-cache: true | ||||
|  | @ -74,7 +75,7 @@ jobs: | |||
|               echo "Ruby version detected : $(ruby --version 2>&1)" | ||||
|           fi | ||||
|   python-shell-test: | ||||
|     runs-on: ['self-hosted', 'Linux'] | ||||
|     runs-on: ["self-hosted", "Linux"] | ||||
|     steps: | ||||
|       - name: Test Python shell works | ||||
|         run: | | ||||
|  |  | |||
|  | @ -0,0 +1,86 @@ | |||
| # USAGE: | ||||
| #   cat acceptance/testdata/kubernetes_container_mode.envsubst.yaml  | NAMESPACE=default envsubst  | kubectl apply -f - | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRole | ||||
| metadata: | ||||
|   name: k8s-mode-runner | ||||
| rules: | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods/exec"] | ||||
|   verbs: ["get", "create"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["pods/log"] | ||||
|   verbs: ["get", "list", "watch",] | ||||
| - apiGroups: ["batch"] | ||||
|   resources: ["jobs"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| - apiGroups: [""] | ||||
|   resources: ["secrets"] | ||||
|   verbs: ["get", "list", "create", "delete"] | ||||
| # Needed to report test success by crating a cm from within workflow job step | ||||
| - apiGroups: [""] | ||||
|   resources: ["configmaps"] | ||||
|   verbs: ["create", "delete"] | ||||
| --- | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRole | ||||
| metadata: | ||||
|   name: runner-status-updater | ||||
| rules: | ||||
| - apiGroups: ["actions.summerwind.dev"] | ||||
|   resources: ["runners/status"] | ||||
|   verbs: ["get", "update", "patch"] | ||||
| --- | ||||
| apiVersion: v1 | ||||
| kind: ServiceAccount | ||||
| metadata: | ||||
|   name: ${RUNNER_SERVICE_ACCOUNT_NAME} | ||||
|   namespace: ${NAMESPACE} | ||||
| --- | ||||
| # To verify it's working, try: | ||||
| #   kubectl auth can-i --as system:serviceaccount:default:runner get pod | ||||
| # If incomplete, workflows and jobs would fail with an error message like: | ||||
| #   Error: Error: The Service account needs the following permissions [{"group":"","verbs":["get","list","create","delete"],"resource":"pods","subresource":""},{"group":"","verbs":["get","create"],"resource":"pods","subresource":"exec"},{"group":"","verbs":["get","list","watch"],"resource":"pods","subresource":"log"},{"group":"batch","verbs":["get","list","create","delete"],"resource":"jobs","subresource":""},{"group":"","verbs":["create","delete","get","list"],"resource":"secrets","subresource":""}] on the pod resource in the 'default' namespace. Please contact your self hosted runner administrator. | ||||
| #   Error: Process completed with exit code 1. | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| # This role binding allows "jane" to read pods in the "default" namespace. | ||||
| # You need to already have a Role named "pod-reader" in that namespace. | ||||
| kind: RoleBinding | ||||
| metadata: | ||||
|   name: runner-k8s-mode-runner | ||||
|   namespace: ${NAMESPACE} | ||||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: ${RUNNER_SERVICE_ACCOUNT_NAME} | ||||
|   namespace: ${NAMESPACE} | ||||
| roleRef: | ||||
|   kind: ClusterRole | ||||
|   name: k8s-mode-runner | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
| --- | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: RoleBinding | ||||
| metadata: | ||||
|   name: runner-runner-stat-supdater | ||||
|   namespace: ${NAMESPACE} | ||||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: ${RUNNER_SERVICE_ACCOUNT_NAME} | ||||
|   namespace: ${NAMESPACE} | ||||
| roleRef: | ||||
|   kind: ClusterRole | ||||
|   name: runner-status-updater | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
| --- | ||||
| apiVersion: storage.k8s.io/v1 | ||||
| kind: StorageClass | ||||
| metadata: | ||||
|   name: org-runnerdeploy-runner-work-dir | ||||
|   labels: | ||||
|     content: org-runnerdeploy-runner-work-dir | ||||
| provisioner: rancher.io/local-path | ||||
| reclaimPolicy: Delete | ||||
| volumeBindingMode: WaitForFirstConsumer | ||||
|  | @ -1,3 +1,23 @@ | |||
| apiVersion: storage.k8s.io/v1 | ||||
| kind: StorageClass | ||||
| metadata: | ||||
|   name: ${NAME}-runner-work-dir | ||||
|   labels: | ||||
|     content: ${NAME}-runner-work-dir | ||||
| provisioner: rancher.io/local-path | ||||
| reclaimPolicy: Delete | ||||
| volumeBindingMode: WaitForFirstConsumer | ||||
| --- | ||||
| apiVersion: storage.k8s.io/v1 | ||||
| kind: StorageClass | ||||
| metadata: | ||||
|   name: ${NAME}-rootless-dind-work-dir | ||||
|   labels: | ||||
|     content: ${NAME}-rootless-dind-work-dir | ||||
| provisioner: rancher.io/local-path | ||||
| reclaimPolicy: Delete | ||||
| volumeBindingMode: WaitForFirstConsumer | ||||
| --- | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: RunnerDeployment | ||||
| metadata: | ||||
|  | @ -39,10 +59,95 @@ spec: | |||
|       labels: | ||||
|       - "${RUNNER_LABEL}" | ||||
| 
 | ||||
|       serviceAccountName: ${RUNNER_SERVICE_ACCOUNT_NAME} | ||||
|       terminationGracePeriodSeconds: ${RUNNER_TERMINATION_GRACE_PERIOD_SECONDS} | ||||
| 
 | ||||
|       env: | ||||
|       - name: RUNNER_GRACEFUL_STOP_TIMEOUT | ||||
|         value: "${RUNNER_GRACEFUL_STOP_TIMEOUT}" | ||||
|       - name: ROLLING_UPDATE_PHASE | ||||
|         value: "${ROLLING_UPDATE_PHASE}" | ||||
|       - name: ARC_DOCKER_MTU_PROPAGATION | ||||
|         value: "true" | ||||
|       # https://github.com/docker/docs/issues/8663 | ||||
|       - name: DOCKER_DEFAULT_ADDRESS_POOL_BASE | ||||
|         value: "172.17.0.0/12" | ||||
|       - name: DOCKER_DEFAULT_ADDRESS_POOL_SIZE | ||||
|         value: "24" | ||||
|       - name: WAIT_FOR_DOCKER_SECONDS | ||||
|         value: "3" | ||||
| 
 | ||||
|       dockerMTU: 1400 | ||||
|       dockerEnv: | ||||
|       - name: RUNNER_GRACEFUL_STOP_TIMEOUT | ||||
|         value: "${RUNNER_GRACEFUL_STOP_TIMEOUT}" | ||||
| 
 | ||||
|       # Fix the following no space left errors with rootless-dind runners that can happen while running buildx build: | ||||
|       #   ------ | ||||
|       #   > [4/5] RUN go mod download: | ||||
|       #   ------ | ||||
|       #   ERROR: failed to solve: failed to prepare yxsw8lv9hqnuafzlfta244l0z: mkdir /home/runner/.local/share/docker/vfs/dir/yxsw8lv9hqnuafzlfta244l0z/usr/local/go/src/cmd/compile/internal/types2/testdata: no space left on device | ||||
|       #   Error: Process completed with exit code 1. | ||||
|       # | ||||
|       volumeMounts: | ||||
|       - name: rootless-dind-work-dir | ||||
|         # Omit the /share/docker part of the /home/runner/.local/share/docker as | ||||
|         # that part is created by dockerd. | ||||
|         mountPath: /home/runner/.local | ||||
|         readOnly: false | ||||
|       # See https://github.com/actions/actions-runner-controller/issues/2123 | ||||
|       # Be sure to omit the "aliases" field from the config.json. | ||||
|       # Otherwise you may encounter nasty errors like: | ||||
|       #   $ docker build | ||||
|       #   docker: 'buildx' is not a docker command. | ||||
|       #   See 'docker --help' | ||||
|       # due to the incompatibility between your host docker config.json and the runner environment. | ||||
|       # That is, your host dockcer config.json might contain this: | ||||
|       #   "aliases": { | ||||
|       #     "builder": "buildx" | ||||
|       #   } | ||||
|       # And this results in the above error when the runner does not have buildx installed yet. | ||||
|       - name: docker-config | ||||
|         mountPath: /home/runner/.docker/config.json | ||||
|         subPath: config.json | ||||
|         readOnly: true | ||||
|       - name: docker-config-root | ||||
|         mountPath: /home/runner/.docker | ||||
|       volumes: | ||||
|       - name: rootless-dind-work-dir | ||||
|         ephemeral: | ||||
|           volumeClaimTemplate: | ||||
|             spec: | ||||
|               accessModes: [ "ReadWriteOnce" ] | ||||
|               storageClassName: "${NAME}-rootless-dind-work-dir" | ||||
|               resources: | ||||
|                 requests: | ||||
|                   storage: 3Gi | ||||
|       - name: docker-config | ||||
|         # Refer to .dockerconfigjson/.docker/config.json | ||||
|         secret: | ||||
|           secretName: docker-config | ||||
|           items: | ||||
|           - key: .dockerconfigjson | ||||
|             path: config.json | ||||
|       - name: docker-config-root | ||||
|         emptyDir: {} | ||||
| 
 | ||||
|       # | ||||
|       # Non-standard working directory | ||||
|       # | ||||
|       # workDir: "/" | ||||
| 
 | ||||
|       # # Uncomment the below to enable the kubernetes container mode | ||||
|       # # See https://github.com/actions/actions-runner-controller#runner-with-k8s-jobs | ||||
|       containerMode: ${RUNNER_CONTAINER_MODE} | ||||
|       workVolumeClaimTemplate: | ||||
|         accessModes: | ||||
|         - ReadWriteOnce | ||||
|         storageClassName: "${NAME}-runner-work-dir" | ||||
|         resources: | ||||
|           requests: | ||||
|             storage: 10Gi | ||||
| --- | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: HorizontalRunnerAutoscaler | ||||
|  |  | |||
|  | @ -54,6 +54,16 @@ provisioner: rancher.io/local-path | |||
| reclaimPolicy: Retain | ||||
| volumeBindingMode: WaitForFirstConsumer | ||||
| --- | ||||
| apiVersion: storage.k8s.io/v1 | ||||
| kind: StorageClass | ||||
| metadata: | ||||
|   name: ${NAME}-rootless-dind-work-dir | ||||
|   labels: | ||||
|     content: ${NAME}-rootless-dind-work-dir | ||||
| provisioner: rancher.io/local-path | ||||
| reclaimPolicy: Delete | ||||
| volumeBindingMode: WaitForFirstConsumer | ||||
| --- | ||||
| apiVersion: actions.summerwind.dev/v1alpha1 | ||||
| kind: RunnerSet | ||||
| metadata: | ||||
|  | @ -112,18 +122,33 @@ spec: | |||
|       labels: | ||||
|         app: ${NAME} | ||||
|     spec: | ||||
|       serviceAccountName: ${RUNNER_SERVICE_ACCOUNT_NAME} | ||||
|       terminationGracePeriodSeconds: ${RUNNER_TERMINATION_GRACE_PERIOD_SECONDS} | ||||
|       containers: | ||||
|       # # Uncomment only when non-dind-runner / you're using docker sidecar | ||||
|       # - name: docker | ||||
|       #   # Image is required for the dind sidecar definition within RunnerSet spec | ||||
|       #   image: "docker:dind" | ||||
|       #   env: | ||||
|       #   - name: RUNNER_GRACEFUL_STOP_TIMEOUT | ||||
|       #     value: "${RUNNER_GRACEFUL_STOP_TIMEOUT}" | ||||
|       - name: runner | ||||
|         imagePullPolicy: IfNotPresent | ||||
|         env: | ||||
|         - name: RUNNER_GRACEFUL_STOP_TIMEOUT | ||||
|           value: "${RUNNER_GRACEFUL_STOP_TIMEOUT}" | ||||
|         - name: RUNNER_FEATURE_FLAG_EPHEMERAL | ||||
|           value: "${RUNNER_FEATURE_FLAG_EPHEMERAL}" | ||||
|         - name: GOMODCACHE | ||||
|           value: "/home/runner/.cache/go-mod" | ||||
|         - name: ROLLING_UPDATE_PHASE | ||||
|           value: "${ROLLING_UPDATE_PHASE}" | ||||
|         # PV-backed runner work dir | ||||
|         volumeMounts: | ||||
|         - name: work | ||||
|           mountPath: /runner/_work | ||||
|         # Comment out the ephemeral work volume if you're going to test the kubernetes container mode | ||||
|         # The volume and mount with the same names will be created by workVolumeClaimTemplate and the kubernetes container mode support. | ||||
|         # - name: work | ||||
|         #   mountPath: /runner/_work | ||||
|         # Cache docker image layers, in case dockerdWithinRunnerContainer=true | ||||
|         - name: var-lib-docker | ||||
|           mountPath: /var/lib/docker | ||||
|  | @ -150,30 +175,57 @@ spec: | |||
|           # https://github.com/actions/setup-go/blob/56a61c9834b4a4950dbbf4740af0b8a98c73b768/src/installer.ts#L144 | ||||
|           mountPath: "/opt/hostedtoolcache" | ||||
|       # Valid only when dockerdWithinRunnerContainer=false | ||||
|       - name: docker | ||||
|         # PV-backed runner work dir | ||||
|         volumeMounts: | ||||
|         - name: work | ||||
|           mountPath: /runner/_work | ||||
|         # Cache docker image layers, in case dockerdWithinRunnerContainer=false | ||||
|         - name: var-lib-docker | ||||
|           mountPath: /var/lib/docker | ||||
|         # image: mumoshu/actions-runner-dind:dev | ||||
|       # - name: docker | ||||
|       #   # PV-backed runner work dir | ||||
|       #   volumeMounts: | ||||
|       #   - name: work | ||||
|       #     mountPath: /runner/_work | ||||
|       #   # Cache docker image layers, in case dockerdWithinRunnerContainer=false | ||||
|       #   - name: var-lib-docker | ||||
|       #     mountPath: /var/lib/docker | ||||
|       #   # image: mumoshu/actions-runner-dind:dev | ||||
| 
 | ||||
|         # For buildx cache | ||||
|         - name: cache | ||||
|           mountPath: "/home/runner/.cache" | ||||
|       #   # For buildx cache | ||||
|       #   - name: cache | ||||
|       #     mountPath: "/home/runner/.cache" | ||||
| 
 | ||||
|         # For fixing no space left error on rootless dind runner | ||||
|         - name: rootless-dind-work-dir | ||||
|           # Omit the /share/docker part of the /home/runner/.local/share/docker as | ||||
|           # that part is created by dockerd. | ||||
|           mountPath: /home/runner/.local | ||||
|           readOnly: false | ||||
| 
 | ||||
|       # Comment out the ephemeral work volume if you're going to test the kubernetes container mode | ||||
|       # volumes: | ||||
|       # - name: work | ||||
|       #   ephemeral: | ||||
|       #     volumeClaimTemplate: | ||||
|       #       spec: | ||||
|       #         accessModes: | ||||
|       #         - ReadWriteOnce | ||||
|       #         storageClassName: "${NAME}-runner-work-dir" | ||||
|       #         resources: | ||||
|       #           requests: | ||||
|       #             storage: 10Gi | ||||
| 
 | ||||
|       # Fix the following no space left errors with rootless-dind runners that can happen while running buildx build: | ||||
|       #   ------ | ||||
|       #   > [4/5] RUN go mod download: | ||||
|       #   ------ | ||||
|       #   ERROR: failed to solve: failed to prepare yxsw8lv9hqnuafzlfta244l0z: mkdir /home/runner/.local/share/docker/vfs/dir/yxsw8lv9hqnuafzlfta244l0z/usr/local/go/src/cmd/compile/internal/types2/testdata: no space left on device | ||||
|       #   Error: Process completed with exit code 1. | ||||
|       # | ||||
|       volumes: | ||||
|       - name: work | ||||
|       - name: rootless-dind-work-dir | ||||
|         ephemeral: | ||||
|           volumeClaimTemplate: | ||||
|             spec: | ||||
|               accessModes: | ||||
|               - ReadWriteOnce | ||||
|               storageClassName: "${NAME}-runner-work-dir" | ||||
|               accessModes: [ "ReadWriteOnce" ] | ||||
|               storageClassName: "${NAME}-rootless-dind-work-dir" | ||||
|               resources: | ||||
|                 requests: | ||||
|                   storage: 10Gi | ||||
|                   storage: 3Gi | ||||
|   volumeClaimTemplates: | ||||
|   - metadata: | ||||
|       name: vol1 | ||||
|  | @ -251,3 +303,10 @@ spec: | |||
|   minReplicas: ${RUNNER_MIN_REPLICAS} | ||||
|   maxReplicas: 10 | ||||
|   scaleDownDelaySecondsAfterScaleOut: ${RUNNER_SCALE_DOWN_DELAY_SECONDS_AFTER_SCALE_OUT} | ||||
|   # Comment out the whole metrics if you'd like to solely test webhook-based scaling | ||||
|   metrics: | ||||
|   - type: PercentageRunnersBusy | ||||
|     scaleUpThreshold: '0.75' | ||||
|     scaleDownThreshold: '0.25' | ||||
|     scaleUpFactor: '2' | ||||
|     scaleDownFactor: '0.5' | ||||
|  |  | |||
|  | @ -1,6 +1,18 @@ | |||
| # Set actions-runner-controller settings for testing | ||||
| logLevel: "-4" | ||||
| imagePullSecrets: [] | ||||
| image: | ||||
|   # This needs to be an empty array rather than a single-item array with empty name. | ||||
|   # Otherwise you end up with the following error on helm-upgrade: | ||||
|   #   Error: UPGRADE FAILED: failed to create patch: map: map[] does not contain declared merge key: name && failed to create patch: map: map[] does not contain declared merge key: name | ||||
|   actionsRunnerImagePullSecrets: [] | ||||
| runner: | ||||
|   statusUpdateHook: | ||||
|     enabled: true | ||||
| rbac: | ||||
|   allowGrantingKubernetesContainerModePermissions: true | ||||
| githubWebhookServer: | ||||
|   imagePullSecrets: [] | ||||
|   logLevel: "-4" | ||||
|   enabled: true | ||||
|   labels: {} | ||||
|  | @ -21,3 +33,23 @@ githubWebhookServer: | |||
|         protocol: TCP | ||||
|         name: http | ||||
|         nodePort: 31000 | ||||
| actionsMetricsServer: | ||||
|   imagePullSecrets: [] | ||||
|   logLevel: "-4" | ||||
|   enabled: true | ||||
|   labels: {} | ||||
|   replicaCount: 1 | ||||
|   secret: | ||||
|     enabled: true | ||||
|     # create: true | ||||
|     name: "actions-metrics-server" | ||||
|     ### GitHub Webhook Configuration | ||||
|     #github_webhook_secret_token: "" | ||||
|   service: | ||||
|     type: NodePort | ||||
|     ports: | ||||
|       - port: 80 | ||||
|         targetPort: http | ||||
|         protocol: TCP | ||||
|         name: http | ||||
|         nodePort: 31001 | ||||
|  |  | |||
|  | @ -0,0 +1,89 @@ | |||
| package appconfig | ||||
| 
 | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 
 | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| ) | ||||
| 
 | ||||
| type AppConfig struct { | ||||
| 	AppID             string `json:"github_app_id"` | ||||
| 	AppInstallationID int64  `json:"github_app_installation_id"` | ||||
| 	AppPrivateKey     string `json:"github_app_private_key"` | ||||
| 
 | ||||
| 	Token string `json:"github_token"` | ||||
| } | ||||
| 
 | ||||
| func (c *AppConfig) tidy() *AppConfig { | ||||
| 	if len(c.Token) > 0 { | ||||
| 		return &AppConfig{ | ||||
| 			Token: c.Token, | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	return &AppConfig{ | ||||
| 		AppID:             c.AppID, | ||||
| 		AppInstallationID: c.AppInstallationID, | ||||
| 		AppPrivateKey:     c.AppPrivateKey, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (c *AppConfig) Validate() error { | ||||
| 	if c == nil { | ||||
| 		return fmt.Errorf("missing app config") | ||||
| 	} | ||||
| 	hasToken := len(c.Token) > 0 | ||||
| 	hasGitHubAppAuth := c.hasGitHubAppAuth() | ||||
| 	if hasToken && hasGitHubAppAuth { | ||||
| 		return fmt.Errorf("both PAT and GitHub App credentials provided. should only provide one") | ||||
| 	} | ||||
| 	if !hasToken && !hasGitHubAppAuth { | ||||
| 		return fmt.Errorf("no credentials provided: either a PAT or GitHub App credentials should be provided") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (c *AppConfig) hasGitHubAppAuth() bool { | ||||
| 	return len(c.AppID) > 0 && c.AppInstallationID > 0 && len(c.AppPrivateKey) > 0 | ||||
| } | ||||
| 
 | ||||
| func FromSecret(secret *corev1.Secret) (*AppConfig, error) { | ||||
| 	var appInstallationID int64 | ||||
| 	if v := string(secret.Data["github_app_installation_id"]); v != "" { | ||||
| 		val, err := strconv.ParseInt(v, 10, 64) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		appInstallationID = val | ||||
| 	} | ||||
| 
 | ||||
| 	cfg := &AppConfig{ | ||||
| 		Token:             string(secret.Data["github_token"]), | ||||
| 		AppID:             string(secret.Data["github_app_id"]), | ||||
| 		AppInstallationID: appInstallationID, | ||||
| 		AppPrivateKey:     string(secret.Data["github_app_private_key"]), | ||||
| 	} | ||||
| 
 | ||||
| 	if err := cfg.Validate(); err != nil { | ||||
| 		return nil, fmt.Errorf("failed to validate config: %v", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return cfg.tidy(), nil | ||||
| } | ||||
| 
 | ||||
| func FromJSONString(v string) (*AppConfig, error) { | ||||
| 	var appConfig AppConfig | ||||
| 	if err := json.NewDecoder(bytes.NewBufferString(v)).Decode(&appConfig); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	if err := appConfig.Validate(); err != nil { | ||||
| 		return nil, fmt.Errorf("failed to validate app config decoded from string: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	return appConfig.tidy(), nil | ||||
| } | ||||
|  | @ -0,0 +1,152 @@ | |||
| package appconfig | ||||
| 
 | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| ) | ||||
| 
 | ||||
| func TestAppConfigValidate_invalid(t *testing.T) { | ||||
| 	tt := map[string]*AppConfig{ | ||||
| 		"empty": {}, | ||||
| 		"token and app config": { | ||||
| 			AppID:             "1", | ||||
| 			AppInstallationID: 2, | ||||
| 			AppPrivateKey:     "private key", | ||||
| 			Token:             "token", | ||||
| 		}, | ||||
| 		"app id not set": { | ||||
| 			AppInstallationID: 2, | ||||
| 			AppPrivateKey:     "private key", | ||||
| 		}, | ||||
| 		"app installation id not set": { | ||||
| 			AppID:         "2", | ||||
| 			AppPrivateKey: "private key", | ||||
| 		}, | ||||
| 		"private key empty": { | ||||
| 			AppID:             "2", | ||||
| 			AppInstallationID: 1, | ||||
| 			AppPrivateKey:     "", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, cfg := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			err := cfg.Validate() | ||||
| 			require.Error(t, err) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAppConfigValidate_valid(t *testing.T) { | ||||
| 	tt := map[string]*AppConfig{ | ||||
| 		"token": { | ||||
| 			Token: "token", | ||||
| 		}, | ||||
| 		"app ID": { | ||||
| 			AppID:             "1", | ||||
| 			AppInstallationID: 2, | ||||
| 			AppPrivateKey:     "private key", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, cfg := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			err := cfg.Validate() | ||||
| 			require.NoError(t, err) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAppConfigFromSecret_invalid(t *testing.T) { | ||||
| 	tt := map[string]map[string]string{ | ||||
| 		"empty": {}, | ||||
| 		"token and app provided": { | ||||
| 			"github_token":              "token", | ||||
| 			"github_app_id":             "2", | ||||
| 			"githu_app_installation_id": "3", | ||||
| 			"github_app_private_key":    "private key", | ||||
| 		}, | ||||
| 		"invalid app id": { | ||||
| 			"github_app_id":             "abc", | ||||
| 			"githu_app_installation_id": "3", | ||||
| 			"github_app_private_key":    "private key", | ||||
| 		}, | ||||
| 		"invalid app installation_id": { | ||||
| 			"github_app_id":             "1", | ||||
| 			"githu_app_installation_id": "abc", | ||||
| 			"github_app_private_key":    "private key", | ||||
| 		}, | ||||
| 		"empty private key": { | ||||
| 			"github_app_id":             "1", | ||||
| 			"githu_app_installation_id": "2", | ||||
| 			"github_app_private_key":    "", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, data := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			secret := &corev1.Secret{ | ||||
| 				StringData: data, | ||||
| 			} | ||||
| 
 | ||||
| 			appConfig, err := FromSecret(secret) | ||||
| 			assert.Error(t, err) | ||||
| 			assert.Nil(t, appConfig) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAppConfigFromSecret_valid(t *testing.T) { | ||||
| 	tt := map[string]map[string]string{ | ||||
| 		"with token": { | ||||
| 			"github_token": "token", | ||||
| 		}, | ||||
| 		"app config": { | ||||
| 			"github_app_id":             "2", | ||||
| 			"githu_app_installation_id": "3", | ||||
| 			"github_app_private_key":    "private key", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, data := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			secret := &corev1.Secret{ | ||||
| 				StringData: data, | ||||
| 			} | ||||
| 
 | ||||
| 			appConfig, err := FromSecret(secret) | ||||
| 			assert.Error(t, err) | ||||
| 			assert.Nil(t, appConfig) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func TestAppConfigFromString_valid(t *testing.T) { | ||||
| 	tt := map[string]*AppConfig{ | ||||
| 		"token": { | ||||
| 			Token: "token", | ||||
| 		}, | ||||
| 		"app ID": { | ||||
| 			AppID:             "1", | ||||
| 			AppInstallationID: 2, | ||||
| 			AppPrivateKey:     "private key", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, cfg := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			bytes, err := json.Marshal(cfg) | ||||
| 			require.NoError(t, err) | ||||
| 
 | ||||
| 			got, err := FromJSONString(string(bytes)) | ||||
| 			require.NoError(t, err) | ||||
| 
 | ||||
| 			want := cfg.tidy() | ||||
| 			assert.Equal(t, want, got) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,102 @@ | |||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| // AutoscalingListenerSpec defines the desired state of AutoscalingListener
 | ||||
| type AutoscalingListenerSpec struct { | ||||
| 	// Required
 | ||||
| 	GitHubConfigUrl string `json:"githubConfigUrl,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	GitHubConfigSecret string `json:"githubConfigSecret,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	RunnerScaleSetId int `json:"runnerScaleSetId,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	AutoscalingRunnerSetNamespace string `json:"autoscalingRunnerSetNamespace,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	AutoscalingRunnerSetName string `json:"autoscalingRunnerSetName,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	EphemeralRunnerSetName string `json:"ephemeralRunnerSetName,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	// +kubebuilder:validation:Minimum:=0
 | ||||
| 	MaxRunners int `json:"maxRunners,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	// +kubebuilder:validation:Minimum:=0
 | ||||
| 	MinRunners int `json:"minRunners,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	Image string `json:"image,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	ImagePullSecrets []corev1.LocalObjectReference `json:"imagePullSecrets,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Metrics *MetricsConfig `json:"metrics,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Template *corev1.PodTemplateSpec `json:"template,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // AutoscalingListenerStatus defines the observed state of AutoscalingListener
 | ||||
| type AutoscalingListenerStatus struct{} | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.githubConfigUrl",name=GitHub Configure URL,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.autoscalingRunnerSetNamespace",name=AutoscalingRunnerSet Namespace,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.autoscalingRunnerSetName",name=AutoscalingRunnerSet Name,type=string
 | ||||
| 
 | ||||
| // AutoscalingListener is the Schema for the autoscalinglisteners API
 | ||||
| type AutoscalingListener struct { | ||||
| 	metav1.TypeMeta   `json:",inline"` | ||||
| 	metav1.ObjectMeta `json:"metadata,omitempty"` | ||||
| 
 | ||||
| 	Spec   AutoscalingListenerSpec   `json:"spec,omitempty"` | ||||
| 	Status AutoscalingListenerStatus `json:"status,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // AutoscalingListenerList contains a list of AutoscalingListener
 | ||||
| type AutoscalingListenerList struct { | ||||
| 	metav1.TypeMeta `json:",inline"` | ||||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 	Items           []AutoscalingListener `json:"items"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&AutoscalingListener{}, &AutoscalingListenerList{}) | ||||
| } | ||||
|  | @ -0,0 +1,372 @@ | |||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/x509" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"strings" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/hash" | ||||
| 	"github.com/actions/actions-runner-controller/vault" | ||||
| 	"golang.org/x/net/http/httpproxy" | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| // NOTE: json tags are required.  Any new fields you add must have json tags for the fields to be serialized.
 | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.minRunners",name=Minimum Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.maxRunners",name=Maximum Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.currentRunners",name=Current Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.state",name=State,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.pendingEphemeralRunners",name=Pending Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.runningEphemeralRunners",name=Running Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.finishedEphemeralRunners",name=Finished Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.deletingEphemeralRunners",name=Deleting Runners,type=integer
 | ||||
| 
 | ||||
| // AutoscalingRunnerSet is the Schema for the autoscalingrunnersets API
 | ||||
| type AutoscalingRunnerSet struct { | ||||
| 	metav1.TypeMeta   `json:",inline"` | ||||
| 	metav1.ObjectMeta `json:"metadata,omitempty"` | ||||
| 
 | ||||
| 	Spec   AutoscalingRunnerSetSpec   `json:"spec,omitempty"` | ||||
| 	Status AutoscalingRunnerSetStatus `json:"status,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // AutoscalingRunnerSetSpec defines the desired state of AutoscalingRunnerSet
 | ||||
| type AutoscalingRunnerSetSpec struct { | ||||
| 	// Required
 | ||||
| 	GitHubConfigUrl string `json:"githubConfigUrl,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	GitHubConfigSecret string `json:"githubConfigSecret,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	RunnerGroup string `json:"runnerGroup,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	RunnerScaleSetName string `json:"runnerScaleSetName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	// Required
 | ||||
| 	Template corev1.PodTemplateSpec `json:"template,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	ListenerMetrics *MetricsConfig `json:"listenerMetrics,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	ListenerTemplate *corev1.PodTemplateSpec `json:"listenerTemplate,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	// +kubebuilder:validation:Minimum:=0
 | ||||
| 	MaxRunners *int `json:"maxRunners,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	// +kubebuilder:validation:Minimum:=0
 | ||||
| 	MinRunners *int `json:"minRunners,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type TLSConfig struct { | ||||
| 	// Required
 | ||||
| 	CertificateFrom *TLSCertificateSource `json:"certificateFrom,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (c *TLSConfig) ToCertPool(keyFetcher func(name, key string) ([]byte, error)) (*x509.CertPool, error) { | ||||
| 	if c.CertificateFrom == nil { | ||||
| 		return nil, fmt.Errorf("certificateFrom not specified") | ||||
| 	} | ||||
| 
 | ||||
| 	if c.CertificateFrom.ConfigMapKeyRef == nil { | ||||
| 		return nil, fmt.Errorf("configMapKeyRef not specified") | ||||
| 	} | ||||
| 
 | ||||
| 	cert, err := keyFetcher(c.CertificateFrom.ConfigMapKeyRef.Name, c.CertificateFrom.ConfigMapKeyRef.Key) | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf( | ||||
| 			"failed to fetch key %q in configmap %q: %w", | ||||
| 			c.CertificateFrom.ConfigMapKeyRef.Key, | ||||
| 			c.CertificateFrom.ConfigMapKeyRef.Name, | ||||
| 			err, | ||||
| 		) | ||||
| 	} | ||||
| 
 | ||||
| 	systemPool, err := x509.SystemCertPool() | ||||
| 	if err != nil { | ||||
| 		return nil, fmt.Errorf("failed to get system cert pool: %w", err) | ||||
| 	} | ||||
| 
 | ||||
| 	pool := systemPool.Clone() | ||||
| 	if !pool.AppendCertsFromPEM(cert) { | ||||
| 		return nil, fmt.Errorf("failed to parse certificate") | ||||
| 	} | ||||
| 
 | ||||
| 	return pool, nil | ||||
| } | ||||
| 
 | ||||
| type TLSCertificateSource struct { | ||||
| 	// Required
 | ||||
| 	ConfigMapKeyRef *corev1.ConfigMapKeySelector `json:"configMapKeyRef,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type ProxyConfig struct { | ||||
| 	// +optional
 | ||||
| 	HTTP *ProxyServerConfig `json:"http,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	HTTPS *ProxyServerConfig `json:"https,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	NoProxy []string `json:"noProxy,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (c *ProxyConfig) ToHTTPProxyConfig(secretFetcher func(string) (*corev1.Secret, error)) (*httpproxy.Config, error) { | ||||
| 	config := &httpproxy.Config{ | ||||
| 		NoProxy: strings.Join(c.NoProxy, ","), | ||||
| 	} | ||||
| 
 | ||||
| 	if c.HTTP != nil { | ||||
| 		u, err := url.Parse(c.HTTP.Url) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to parse proxy http url %q: %w", c.HTTP.Url, err) | ||||
| 		} | ||||
| 
 | ||||
| 		if c.HTTP.CredentialSecretRef != "" { | ||||
| 			secret, err := secretFetcher(c.HTTP.CredentialSecretRef) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf( | ||||
| 					"failed to get secret %s for http proxy: %w", | ||||
| 					c.HTTP.CredentialSecretRef, | ||||
| 					err, | ||||
| 				) | ||||
| 			} | ||||
| 
 | ||||
| 			u.User = url.UserPassword( | ||||
| 				string(secret.Data["username"]), | ||||
| 				string(secret.Data["password"]), | ||||
| 			) | ||||
| 		} | ||||
| 
 | ||||
| 		config.HTTPProxy = u.String() | ||||
| 	} | ||||
| 
 | ||||
| 	if c.HTTPS != nil { | ||||
| 		u, err := url.Parse(c.HTTPS.Url) | ||||
| 		if err != nil { | ||||
| 			return nil, fmt.Errorf("failed to parse proxy https url %q: %w", c.HTTPS.Url, err) | ||||
| 		} | ||||
| 
 | ||||
| 		if c.HTTPS.CredentialSecretRef != "" { | ||||
| 			secret, err := secretFetcher(c.HTTPS.CredentialSecretRef) | ||||
| 			if err != nil { | ||||
| 				return nil, fmt.Errorf( | ||||
| 					"failed to get secret %s for https proxy: %w", | ||||
| 					c.HTTPS.CredentialSecretRef, | ||||
| 					err, | ||||
| 				) | ||||
| 			} | ||||
| 
 | ||||
| 			u.User = url.UserPassword( | ||||
| 				string(secret.Data["username"]), | ||||
| 				string(secret.Data["password"]), | ||||
| 			) | ||||
| 		} | ||||
| 
 | ||||
| 		config.HTTPSProxy = u.String() | ||||
| 	} | ||||
| 
 | ||||
| 	return config, nil | ||||
| } | ||||
| 
 | ||||
| func (c *ProxyConfig) ToSecretData(secretFetcher func(string) (*corev1.Secret, error)) (map[string][]byte, error) { | ||||
| 	config, err := c.ToHTTPProxyConfig(secretFetcher) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	data := map[string][]byte{} | ||||
| 	data["http_proxy"] = []byte(config.HTTPProxy) | ||||
| 	data["https_proxy"] = []byte(config.HTTPSProxy) | ||||
| 	data["no_proxy"] = []byte(config.NoProxy) | ||||
| 
 | ||||
| 	return data, nil | ||||
| } | ||||
| 
 | ||||
| func (c *ProxyConfig) ProxyFunc(secretFetcher func(string) (*corev1.Secret, error)) (func(*http.Request) (*url.URL, error), error) { | ||||
| 	config, err := c.ToHTTPProxyConfig(secretFetcher) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	proxyFunc := func(req *http.Request) (*url.URL, error) { | ||||
| 		return config.ProxyFunc()(req.URL) | ||||
| 	} | ||||
| 
 | ||||
| 	return proxyFunc, nil | ||||
| } | ||||
| 
 | ||||
| type ProxyServerConfig struct { | ||||
| 	// Required
 | ||||
| 	Url string `json:"url,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	CredentialSecretRef string `json:"credentialSecretRef,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type VaultConfig struct { | ||||
| 	// +optional
 | ||||
| 	Type vault.VaultType `json:"type,omitempty"` | ||||
| 	// +optional
 | ||||
| 	AzureKeyVault *AzureKeyVaultConfig `json:"azureKeyVault,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type AzureKeyVaultConfig struct { | ||||
| 	// +required
 | ||||
| 	URL string `json:"url,omitempty"` | ||||
| 	// +required
 | ||||
| 	TenantID string `json:"tenantId,omitempty"` | ||||
| 	// +required
 | ||||
| 	ClientID string `json:"clientId,omitempty"` | ||||
| 	// +required
 | ||||
| 	CertificatePath string `json:"certificatePath,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // MetricsConfig holds configuration parameters for each metric type
 | ||||
| type MetricsConfig struct { | ||||
| 	// +optional
 | ||||
| 	Counters map[string]*CounterMetric `json:"counters,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Gauges map[string]*GaugeMetric `json:"gauges,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Histograms map[string]*HistogramMetric `json:"histograms,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // CounterMetric holds configuration of a single metric of type Counter
 | ||||
| type CounterMetric struct { | ||||
| 	Labels []string `json:"labels"` | ||||
| } | ||||
| 
 | ||||
| // GaugeMetric holds configuration of a single metric of type Gauge
 | ||||
| type GaugeMetric struct { | ||||
| 	Labels []string `json:"labels"` | ||||
| } | ||||
| 
 | ||||
| // HistogramMetric holds configuration of a single metric of type Histogram
 | ||||
| type HistogramMetric struct { | ||||
| 	Labels  []string  `json:"labels"` | ||||
| 	Buckets []float64 `json:"buckets,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // AutoscalingRunnerSetStatus defines the observed state of AutoscalingRunnerSet
 | ||||
| type AutoscalingRunnerSetStatus struct { | ||||
| 	// +optional
 | ||||
| 	CurrentRunners int `json:"currentRunners"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	State string `json:"state"` | ||||
| 
 | ||||
| 	// EphemeralRunner counts separated by the stage ephemeral runners are in, taken from the EphemeralRunnerSet
 | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	PendingEphemeralRunners int `json:"pendingEphemeralRunners"` | ||||
| 	// +optional
 | ||||
| 	RunningEphemeralRunners int `json:"runningEphemeralRunners"` | ||||
| 	// +optional
 | ||||
| 	FailedEphemeralRunners int `json:"failedEphemeralRunners"` | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) ListenerSpecHash() string { | ||||
| 	arsSpec := ars.Spec.DeepCopy() | ||||
| 	spec := arsSpec | ||||
| 	return hash.ComputeTemplateHash(&spec) | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) GitHubConfigSecret() string { | ||||
| 	return ars.Spec.GitHubConfigSecret | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) GitHubConfigUrl() string { | ||||
| 	return ars.Spec.GitHubConfigUrl | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) GitHubProxy() *ProxyConfig { | ||||
| 	return ars.Spec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) GitHubServerTLS() *TLSConfig { | ||||
| 	return ars.Spec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) VaultConfig() *VaultConfig { | ||||
| 	return ars.Spec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) VaultProxy() *ProxyConfig { | ||||
| 	if ars.Spec.VaultConfig != nil { | ||||
| 		return ars.Spec.VaultConfig.Proxy | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (ars *AutoscalingRunnerSet) RunnerSetSpecHash() string { | ||||
| 	type runnerSetSpec struct { | ||||
| 		GitHubConfigUrl    string | ||||
| 		GitHubConfigSecret string | ||||
| 		RunnerGroup        string | ||||
| 		RunnerScaleSetName string | ||||
| 		Proxy              *ProxyConfig | ||||
| 		GitHubServerTLS    *TLSConfig | ||||
| 		Template           corev1.PodTemplateSpec | ||||
| 	} | ||||
| 	spec := &runnerSetSpec{ | ||||
| 		GitHubConfigUrl:    ars.Spec.GitHubConfigUrl, | ||||
| 		GitHubConfigSecret: ars.Spec.GitHubConfigSecret, | ||||
| 		RunnerGroup:        ars.Spec.RunnerGroup, | ||||
| 		RunnerScaleSetName: ars.Spec.RunnerScaleSetName, | ||||
| 		Proxy:              ars.Spec.Proxy, | ||||
| 		GitHubServerTLS:    ars.Spec.GitHubServerTLS, | ||||
| 		Template:           ars.Spec.Template, | ||||
| 	} | ||||
| 	return hash.ComputeTemplateHash(&spec) | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| 
 | ||||
| // AutoscalingRunnerSetList contains a list of AutoscalingRunnerSet
 | ||||
| type AutoscalingRunnerSetList struct { | ||||
| 	metav1.TypeMeta `json:",inline"` | ||||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 	Items           []AutoscalingRunnerSet `json:"items"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&AutoscalingRunnerSet{}, &AutoscalingRunnerSetList{}) | ||||
| } | ||||
|  | @ -0,0 +1,201 @@ | |||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| // EphemeralRunnerContainerName is the name of the runner container.
 | ||||
| // It represents the name of the container running the self-hosted runner image.
 | ||||
| const EphemeralRunnerContainerName = "runner" | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.githubConfigUrl",name="GitHub Config URL",type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.runnerId",name=RunnerId,type=number
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.phase",name=Status,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.jobRepositoryName",name=JobRepository,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.jobWorkflowRef",name=JobWorkflowRef,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.workflowRunId",name=WorkflowRunId,type=number
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.jobDisplayName",name=JobDisplayName,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.jobId",name=JobId,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.message",name=Message,type=string
 | ||||
| // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
 | ||||
| 
 | ||||
| // EphemeralRunner is the Schema for the ephemeralrunners API
 | ||||
| type EphemeralRunner struct { | ||||
| 	metav1.TypeMeta   `json:",inline"` | ||||
| 	metav1.ObjectMeta `json:"metadata,omitempty"` | ||||
| 
 | ||||
| 	Spec   EphemeralRunnerSpec   `json:"spec,omitempty"` | ||||
| 	Status EphemeralRunnerStatus `json:"status,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) IsDone() bool { | ||||
| 	return er.Status.Phase == corev1.PodSucceeded || er.Status.Phase == corev1.PodFailed | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) HasJob() bool { | ||||
| 	return len(er.Status.JobID) > 0 | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) HasContainerHookConfigured() bool { | ||||
| 	for i := range er.Spec.Spec.Containers { | ||||
| 		if er.Spec.Spec.Containers[i].Name != EphemeralRunnerContainerName { | ||||
| 			continue | ||||
| 		} | ||||
| 
 | ||||
| 		for _, env := range er.Spec.Spec.Containers[i].Env { | ||||
| 			if env.Name == "ACTIONS_RUNNER_CONTAINER_HOOKS" { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 
 | ||||
| 		return false | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) GitHubConfigSecret() string { | ||||
| 	return er.Spec.GitHubConfigSecret | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) GitHubConfigUrl() string { | ||||
| 	return er.Spec.GitHubConfigUrl | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) GitHubProxy() *ProxyConfig { | ||||
| 	return er.Spec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) GitHubServerTLS() *TLSConfig { | ||||
| 	return er.Spec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) VaultConfig() *VaultConfig { | ||||
| 	return er.Spec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| func (er *EphemeralRunner) VaultProxy() *ProxyConfig { | ||||
| 	if er.Spec.VaultConfig != nil { | ||||
| 		return er.Spec.VaultConfig.Proxy | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerSpec defines the desired state of EphemeralRunner
 | ||||
| type EphemeralRunnerSpec struct { | ||||
| 	// +required
 | ||||
| 	GitHubConfigUrl string `json:"githubConfigUrl,omitempty"` | ||||
| 
 | ||||
| 	// +required
 | ||||
| 	GitHubConfigSecret string `json:"githubConfigSecret,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubServerTLS *TLSConfig `json:"githubServerTLS,omitempty"` | ||||
| 
 | ||||
| 	// +required
 | ||||
| 	RunnerScaleSetId int `json:"runnerScaleSetId,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Proxy *ProxyConfig `json:"proxy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	ProxySecretRef string `json:"proxySecretRef,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	VaultConfig *VaultConfig `json:"vaultConfig,omitempty"` | ||||
| 
 | ||||
| 	corev1.PodTemplateSpec `json:",inline"` | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerStatus defines the observed state of EphemeralRunner
 | ||||
| type EphemeralRunnerStatus struct { | ||||
| 	// Turns true only if the runner is online.
 | ||||
| 	// +optional
 | ||||
| 	Ready bool `json:"ready"` | ||||
| 	// Phase describes phases where EphemeralRunner can be in.
 | ||||
| 	// The underlying type is a PodPhase, but the meaning is more restrictive
 | ||||
| 	//
 | ||||
| 	// The PodFailed phase should be set only when EphemeralRunner fails to start
 | ||||
| 	// after multiple retries. That signals that this EphemeralRunner won't work,
 | ||||
| 	// and manual inspection is required
 | ||||
| 	//
 | ||||
| 	// The PodSucceded phase should be set only when confirmed that EphemeralRunner
 | ||||
| 	// actually executed the job and has been removed from the service.
 | ||||
| 	// +optional
 | ||||
| 	Phase corev1.PodPhase `json:"phase,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Reason string `json:"reason,omitempty"` | ||||
| 	// +optional
 | ||||
| 	Message string `json:"message,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	RunnerId int `json:"runnerId,omitempty"` | ||||
| 	// +optional
 | ||||
| 	RunnerName string `json:"runnerName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	Failures map[string]metav1.Time `json:"failures,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	JobRequestId int64 `json:"jobRequestId,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	JobID string `json:"jobId,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	JobRepositoryName string `json:"jobRepositoryName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	JobWorkflowRef string `json:"jobWorkflowRef,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	WorkflowRunId int64 `json:"workflowRunId,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	JobDisplayName string `json:"jobDisplayName,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (s *EphemeralRunnerStatus) LastFailure() metav1.Time { | ||||
| 	var maxTime metav1.Time | ||||
| 	if len(s.Failures) == 0 { | ||||
| 		return maxTime | ||||
| 	} | ||||
| 
 | ||||
| 	for _, ts := range s.Failures { | ||||
| 		if ts.After(maxTime.Time) { | ||||
| 			maxTime = ts | ||||
| 		} | ||||
| 	} | ||||
| 	return maxTime | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| 
 | ||||
| // EphemeralRunnerList contains a list of EphemeralRunner
 | ||||
| type EphemeralRunnerList struct { | ||||
| 	metav1.TypeMeta `json:",inline"` | ||||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 	Items           []EphemeralRunner `json:"items"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&EphemeralRunner{}, &EphemeralRunnerList{}) | ||||
| } | ||||
|  | @ -0,0 +1,100 @@ | |||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| ) | ||||
| 
 | ||||
| // EphemeralRunnerSetSpec defines the desired state of EphemeralRunnerSet
 | ||||
| type EphemeralRunnerSetSpec struct { | ||||
| 	// Replicas is the number of desired EphemeralRunner resources in the k8s namespace.
 | ||||
| 	Replicas int `json:"replicas,omitempty"` | ||||
| 	// PatchID is the unique identifier for the patch issued by the listener app
 | ||||
| 	PatchID int `json:"patchID"` | ||||
| 	// EphemeralRunnerSpec is the spec of the ephemeral runner
 | ||||
| 	EphemeralRunnerSpec EphemeralRunnerSpec `json:"ephemeralRunnerSpec,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerSetStatus defines the observed state of EphemeralRunnerSet
 | ||||
| type EphemeralRunnerSetStatus struct { | ||||
| 	// CurrentReplicas is the number of currently running EphemeralRunner resources being managed by this EphemeralRunnerSet.
 | ||||
| 	CurrentReplicas int `json:"currentReplicas"` | ||||
| 	// +optional
 | ||||
| 	PendingEphemeralRunners int `json:"pendingEphemeralRunners"` | ||||
| 	// +optional
 | ||||
| 	RunningEphemeralRunners int `json:"runningEphemeralRunners"` | ||||
| 	// +optional
 | ||||
| 	FailedEphemeralRunners int `json:"failedEphemeralRunners"` | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.replicas",name="DesiredReplicas",type="integer"
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.currentReplicas", name="CurrentReplicas",type="integer"
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.pendingEphemeralRunners",name=Pending Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.runningEphemeralRunners",name=Running Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.finishedEphemeralRunners",name=Finished Runners,type=integer
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.deletingEphemeralRunners",name=Deleting Runners,type=integer
 | ||||
| 
 | ||||
| // EphemeralRunnerSet is the Schema for the ephemeralrunnersets API
 | ||||
| type EphemeralRunnerSet struct { | ||||
| 	metav1.TypeMeta   `json:",inline"` | ||||
| 	metav1.ObjectMeta `json:"metadata,omitempty"` | ||||
| 
 | ||||
| 	Spec   EphemeralRunnerSetSpec   `json:"spec,omitempty"` | ||||
| 	Status EphemeralRunnerSetStatus `json:"status,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) GitHubConfigSecret() string { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.GitHubConfigSecret | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) GitHubConfigUrl() string { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.GitHubConfigUrl | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) GitHubProxy() *ProxyConfig { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.Proxy | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) GitHubServerTLS() *TLSConfig { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.GitHubServerTLS | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) VaultConfig() *VaultConfig { | ||||
| 	return ers.Spec.EphemeralRunnerSpec.VaultConfig | ||||
| } | ||||
| 
 | ||||
| func (ers *EphemeralRunnerSet) VaultProxy() *ProxyConfig { | ||||
| 	if ers.Spec.EphemeralRunnerSpec.VaultConfig != nil { | ||||
| 		return ers.Spec.EphemeralRunnerSpec.VaultConfig.Proxy | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // EphemeralRunnerSetList contains a list of EphemeralRunnerSet
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| type EphemeralRunnerSetList struct { | ||||
| 	metav1.TypeMeta `json:",inline"` | ||||
| 	metav1.ListMeta `json:"metadata,omitempty"` | ||||
| 	Items           []EphemeralRunnerSet `json:"items"` | ||||
| } | ||||
| 
 | ||||
| func init() { | ||||
| 	SchemeBuilder.Register(&EphemeralRunnerSet{}, &EphemeralRunnerSetList{}) | ||||
| } | ||||
|  | @ -0,0 +1,36 @@ | |||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| // Package v1 contains API Schema definitions for the batch v1 API group
 | ||||
| // +kubebuilder:object:generate=true
 | ||||
| // +groupName=actions.github.com
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"k8s.io/apimachinery/pkg/runtime/schema" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/scheme" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| 	// GroupVersion is group version used to register these objects
 | ||||
| 	GroupVersion = schema.GroupVersion{Group: "actions.github.com", Version: "v1alpha1"} | ||||
| 
 | ||||
| 	// SchemeBuilder is used to add go types to the GroupVersionKind scheme
 | ||||
| 	SchemeBuilder = &scheme.Builder{GroupVersion: GroupVersion} | ||||
| 
 | ||||
| 	// AddToScheme adds the types in this group-version to the given scheme.
 | ||||
| 	AddToScheme = SchemeBuilder.AddToScheme | ||||
| ) | ||||
|  | @ -0,0 +1,118 @@ | |||
| package v1alpha1_test | ||||
| 
 | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
| 
 | ||||
| func TestProxyConfig_ToSecret(t *testing.T) { | ||||
| 	config := &v1alpha1.ProxyConfig{ | ||||
| 		HTTP: &v1alpha1.ProxyServerConfig{ | ||||
| 			Url:                 "http://proxy.example.com:8080", | ||||
| 			CredentialSecretRef: "my-secret", | ||||
| 		}, | ||||
| 		HTTPS: &v1alpha1.ProxyServerConfig{ | ||||
| 			Url:                 "https://proxy.example.com:8080", | ||||
| 			CredentialSecretRef: "my-secret", | ||||
| 		}, | ||||
| 		NoProxy: []string{ | ||||
| 			"noproxy.example.com", | ||||
| 			"noproxy2.example.com", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	secretFetcher := func(string) (*corev1.Secret, error) { | ||||
| 		return &corev1.Secret{ | ||||
| 			Data: map[string][]byte{ | ||||
| 				"username": []byte("username"), | ||||
| 				"password": []byte("password"), | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	result, err := config.ToSecretData(secretFetcher) | ||||
| 	require.NoError(t, err) | ||||
| 	require.NotNil(t, result) | ||||
| 
 | ||||
| 	assert.Equal(t, "http://username:password@proxy.example.com:8080", string(result["http_proxy"])) | ||||
| 	assert.Equal(t, "https://username:password@proxy.example.com:8080", string(result["https_proxy"])) | ||||
| 	assert.Equal(t, "noproxy.example.com,noproxy2.example.com", string(result["no_proxy"])) | ||||
| } | ||||
| 
 | ||||
| func TestProxyConfig_ProxyFunc(t *testing.T) { | ||||
| 	config := &v1alpha1.ProxyConfig{ | ||||
| 		HTTP: &v1alpha1.ProxyServerConfig{ | ||||
| 			Url:                 "http://proxy.example.com:8080", | ||||
| 			CredentialSecretRef: "my-secret", | ||||
| 		}, | ||||
| 		HTTPS: &v1alpha1.ProxyServerConfig{ | ||||
| 			Url:                 "https://proxy.example.com:8080", | ||||
| 			CredentialSecretRef: "my-secret", | ||||
| 		}, | ||||
| 		NoProxy: []string{ | ||||
| 			"noproxy.example.com", | ||||
| 			"noproxy2.example.com", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	secretFetcher := func(string) (*corev1.Secret, error) { | ||||
| 		return &corev1.Secret{ | ||||
| 			Data: map[string][]byte{ | ||||
| 				"username": []byte("username"), | ||||
| 				"password": []byte("password"), | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
| 
 | ||||
| 	result, err := config.ProxyFunc(secretFetcher) | ||||
| 	require.NoError(t, err) | ||||
| 
 | ||||
| 	tests := []struct { | ||||
| 		name string | ||||
| 		in   string | ||||
| 		out  string | ||||
| 	}{ | ||||
| 		{ | ||||
| 			name: "http target", | ||||
| 			in:   "http://target.com", | ||||
| 			out:  "http://username:password@proxy.example.com:8080", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "https target", | ||||
| 			in:   "https://target.com", | ||||
| 			out:  "https://username:password@proxy.example.com:8080", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "no proxy", | ||||
| 			in:   "https://noproxy.example.com", | ||||
| 			out:  "", | ||||
| 		}, | ||||
| 		{ | ||||
| 			name: "no proxy 2", | ||||
| 			in:   "https://noproxy2.example.com", | ||||
| 			out:  "", | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for _, test := range tests { | ||||
| 		t.Run(test.name, func(t *testing.T) { | ||||
| 			req, err := http.NewRequest("GET", test.in, nil) | ||||
| 			require.NoError(t, err) | ||||
| 			u, err := result(req) | ||||
| 			require.NoError(t, err) | ||||
| 
 | ||||
| 			if test.out == "" { | ||||
| 				assert.Nil(t, u) | ||||
| 				return | ||||
| 			} | ||||
| 
 | ||||
| 			assert.Equal(t, test.out, u.String()) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,105 @@ | |||
| package v1alpha1_test | ||||
| 
 | ||||
| import ( | ||||
| 	"crypto/tls" | ||||
| 	"crypto/x509" | ||||
| 	"net/http" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" | ||||
| 	"github.com/actions/actions-runner-controller/github/actions/testserver" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| 	"github.com/stretchr/testify/require" | ||||
| 	v1 "k8s.io/api/core/v1" | ||||
| ) | ||||
| 
 | ||||
| func TestGitHubServerTLSConfig_ToCertPool(t *testing.T) { | ||||
| 	t.Run("returns an error if CertificateFrom not specified", func(t *testing.T) { | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: nil, | ||||
| 		} | ||||
| 
 | ||||
| 		pool, err := c.ToCertPool(nil) | ||||
| 		assert.Nil(t, pool) | ||||
| 
 | ||||
| 		require.Error(t, err) | ||||
| 		assert.Equal(t, err.Error(), "certificateFrom not specified") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("returns an error if CertificateFrom.ConfigMapKeyRef not specified", func(t *testing.T) { | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: &v1alpha1.TLSCertificateSource{}, | ||||
| 		} | ||||
| 
 | ||||
| 		pool, err := c.ToCertPool(nil) | ||||
| 		assert.Nil(t, pool) | ||||
| 
 | ||||
| 		require.Error(t, err) | ||||
| 		assert.Equal(t, err.Error(), "configMapKeyRef not specified") | ||||
| 	}) | ||||
| 
 | ||||
| 	t.Run("returns a valid cert pool with correct configuration", func(t *testing.T) { | ||||
| 		c := &v1alpha1.TLSConfig{ | ||||
| 			CertificateFrom: &v1alpha1.TLSCertificateSource{ | ||||
| 				ConfigMapKeyRef: &v1.ConfigMapKeySelector{ | ||||
| 					LocalObjectReference: v1.LocalObjectReference{ | ||||
| 						Name: "name", | ||||
| 					}, | ||||
| 					Key: "key", | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		certsFolder := filepath.Join( | ||||
| 			"../../../", | ||||
| 			"github", | ||||
| 			"actions", | ||||
| 			"testdata", | ||||
| 		) | ||||
| 
 | ||||
| 		fetcher := func(name, key string) ([]byte, error) { | ||||
| 			cert, err := os.ReadFile(filepath.Join(certsFolder, "rootCA.crt")) | ||||
| 			require.NoError(t, err) | ||||
| 
 | ||||
| 			pool := x509.NewCertPool() | ||||
| 			ok := pool.AppendCertsFromPEM(cert) | ||||
| 			assert.True(t, ok) | ||||
| 
 | ||||
| 			return cert, nil | ||||
| 		} | ||||
| 
 | ||||
| 		pool, err := c.ToCertPool(fetcher) | ||||
| 		require.NoError(t, err) | ||||
| 		require.NotNil(t, pool) | ||||
| 
 | ||||
| 		// can be used to communicate with a server
 | ||||
| 		serverSuccessfullyCalled := false | ||||
| 		server := testserver.NewUnstarted(t, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | ||||
| 			serverSuccessfullyCalled = true | ||||
| 			w.WriteHeader(http.StatusOK) | ||||
| 		})) | ||||
| 
 | ||||
| 		cert, err := tls.LoadX509KeyPair( | ||||
| 			filepath.Join(certsFolder, "server.crt"), | ||||
| 			filepath.Join(certsFolder, "server.key"), | ||||
| 		) | ||||
| 		require.NoError(t, err) | ||||
| 
 | ||||
| 		server.TLS = &tls.Config{Certificates: []tls.Certificate{cert}} | ||||
| 		server.StartTLS() | ||||
| 
 | ||||
| 		client := &http.Client{ | ||||
| 			Transport: &http.Transport{ | ||||
| 				TLSClientConfig: &tls.Config{ | ||||
| 					RootCAs: pool, | ||||
| 				}, | ||||
| 			}, | ||||
| 		} | ||||
| 
 | ||||
| 		_, err = client.Get(server.URL) | ||||
| 		assert.NoError(t, err) | ||||
| 		assert.True(t, serverSuccessfullyCalled) | ||||
| 	}) | ||||
| } | ||||
|  | @ -0,0 +1,72 @@ | |||
| package v1alpha1 | ||||
| 
 | ||||
| import "strings" | ||||
| 
 | ||||
| func IsVersionAllowed(resourceVersion, buildVersion string) bool { | ||||
| 	if buildVersion == "dev" || resourceVersion == buildVersion || strings.HasPrefix(buildVersion, "canary-") { | ||||
| 		return true | ||||
| 	} | ||||
| 
 | ||||
| 	rv, ok := parseSemver(resourceVersion) | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	bv, ok := parseSemver(buildVersion) | ||||
| 	if !ok { | ||||
| 		return false | ||||
| 	} | ||||
| 	return rv.major == bv.major && rv.minor == bv.minor | ||||
| } | ||||
| 
 | ||||
| type semver struct { | ||||
| 	major string | ||||
| 	minor string | ||||
| } | ||||
| 
 | ||||
| func parseSemver(v string) (p semver, ok bool) { | ||||
| 	if v == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	p.major, v, ok = parseInt(v) | ||||
| 	if !ok { | ||||
| 		return p, false | ||||
| 	} | ||||
| 	if v == "" { | ||||
| 		p.minor = "0" | ||||
| 		return p, true | ||||
| 	} | ||||
| 	if v[0] != '.' { | ||||
| 		return p, false | ||||
| 	} | ||||
| 	p.minor, v, ok = parseInt(v[1:]) | ||||
| 	if !ok { | ||||
| 		return p, false | ||||
| 	} | ||||
| 	if v == "" { | ||||
| 		return p, true | ||||
| 	} | ||||
| 	if v[0] != '.' { | ||||
| 		return p, false | ||||
| 	} | ||||
| 	if _, _, ok = parseInt(v[1:]); !ok { | ||||
| 		return p, false | ||||
| 	} | ||||
| 	return p, true | ||||
| } | ||||
| 
 | ||||
| func parseInt(v string) (t, rest string, ok bool) { | ||||
| 	if v == "" { | ||||
| 		return | ||||
| 	} | ||||
| 	if v[0] < '0' || '9' < v[0] { | ||||
| 		return | ||||
| 	} | ||||
| 	i := 1 | ||||
| 	for i < len(v) && '0' <= v[i] && v[i] <= '9' { | ||||
| 		i++ | ||||
| 	} | ||||
| 	if v[0] == '0' && i != 1 { | ||||
| 		return | ||||
| 	} | ||||
| 	return v[:i], v[i:], true | ||||
| } | ||||
|  | @ -0,0 +1,60 @@ | |||
| package v1alpha1_test | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| 
 | ||||
| 	"github.com/actions/actions-runner-controller/apis/actions.github.com/v1alpha1" | ||||
| 	"github.com/stretchr/testify/assert" | ||||
| ) | ||||
| 
 | ||||
| func TestIsVersionAllowed(t *testing.T) { | ||||
| 	t.Parallel() | ||||
| 	tt := map[string]struct { | ||||
| 		resourceVersion string | ||||
| 		buildVersion    string | ||||
| 		want            bool | ||||
| 	}{ | ||||
| 		"dev should always be allowed": { | ||||
| 			resourceVersion: "0.11.0", | ||||
| 			buildVersion:    "dev", | ||||
| 			want:            true, | ||||
| 		}, | ||||
| 		"resourceVersion is not semver": { | ||||
| 			resourceVersion: "dev", | ||||
| 			buildVersion:    "0.11.0", | ||||
| 			want:            false, | ||||
| 		}, | ||||
| 		"buildVersion is not semver": { | ||||
| 			resourceVersion: "0.11.0", | ||||
| 			buildVersion:    "NA", | ||||
| 			want:            false, | ||||
| 		}, | ||||
| 		"major version mismatch": { | ||||
| 			resourceVersion: "0.11.0", | ||||
| 			buildVersion:    "1.11.0", | ||||
| 			want:            false, | ||||
| 		}, | ||||
| 		"minor version mismatch": { | ||||
| 			resourceVersion: "0.11.0", | ||||
| 			buildVersion:    "0.10.0", | ||||
| 			want:            false, | ||||
| 		}, | ||||
| 		"patch version mismatch": { | ||||
| 			resourceVersion: "0.11.1", | ||||
| 			buildVersion:    "0.11.0", | ||||
| 			want:            true, | ||||
| 		}, | ||||
| 		"arbitrary version match": { | ||||
| 			resourceVersion: "abc", | ||||
| 			buildVersion:    "abc", | ||||
| 			want:            true, | ||||
| 		}, | ||||
| 	} | ||||
| 
 | ||||
| 	for name, tc := range tt { | ||||
| 		t.Run(name, func(t *testing.T) { | ||||
| 			got := v1alpha1.IsVersionAllowed(tc.resourceVersion, tc.buildVersion) | ||||
| 			assert.Equal(t, tc.want, got) | ||||
| 		}) | ||||
| 	} | ||||
| } | ||||
|  | @ -0,0 +1,726 @@ | |||
| //go:build !ignore_autogenerated
 | ||||
| 
 | ||||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
| 
 | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
| 
 | ||||
|     http://www.apache.org/licenses/LICENSE-2.0
 | ||||
| 
 | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
| 
 | ||||
| // Code generated by controller-gen. DO NOT EDIT.
 | ||||
| 
 | ||||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
| 	runtime "k8s.io/apimachinery/pkg/runtime" | ||||
| ) | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingListener) DeepCopyInto(out *AutoscalingListener) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) | ||||
| 	in.Spec.DeepCopyInto(&out.Spec) | ||||
| 	out.Status = in.Status | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListener.
 | ||||
| func (in *AutoscalingListener) DeepCopy() *AutoscalingListener { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingListener) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *AutoscalingListener) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingListenerList) DeepCopyInto(out *AutoscalingListenerList) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||
| 	if in.Items != nil { | ||||
| 		in, out := &in.Items, &out.Items | ||||
| 		*out = make([]AutoscalingListener, len(*in)) | ||||
| 		for i := range *in { | ||||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListenerList.
 | ||||
| func (in *AutoscalingListenerList) DeepCopy() *AutoscalingListenerList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingListenerList) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *AutoscalingListenerList) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingListenerSpec) DeepCopyInto(out *AutoscalingListenerSpec) { | ||||
| 	*out = *in | ||||
| 	if in.ImagePullSecrets != nil { | ||||
| 		in, out := &in.ImagePullSecrets, &out.ImagePullSecrets | ||||
| 		*out = make([]v1.LocalObjectReference, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	if in.Proxy != nil { | ||||
| 		in, out := &in.Proxy, &out.Proxy | ||||
| 		*out = new(ProxyConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.Metrics != nil { | ||||
| 		in, out := &in.Metrics, &out.Metrics | ||||
| 		*out = new(MetricsConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.Template != nil { | ||||
| 		in, out := &in.Template, &out.Template | ||||
| 		*out = new(v1.PodTemplateSpec) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListenerSpec.
 | ||||
| func (in *AutoscalingListenerSpec) DeepCopy() *AutoscalingListenerSpec { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingListenerSpec) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingListenerStatus) DeepCopyInto(out *AutoscalingListenerStatus) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingListenerStatus.
 | ||||
| func (in *AutoscalingListenerStatus) DeepCopy() *AutoscalingListenerStatus { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingListenerStatus) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingRunnerSet) DeepCopyInto(out *AutoscalingRunnerSet) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) | ||||
| 	in.Spec.DeepCopyInto(&out.Spec) | ||||
| 	out.Status = in.Status | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingRunnerSet.
 | ||||
| func (in *AutoscalingRunnerSet) DeepCopy() *AutoscalingRunnerSet { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingRunnerSet) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *AutoscalingRunnerSet) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingRunnerSetList) DeepCopyInto(out *AutoscalingRunnerSetList) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||
| 	if in.Items != nil { | ||||
| 		in, out := &in.Items, &out.Items | ||||
| 		*out = make([]AutoscalingRunnerSet, len(*in)) | ||||
| 		for i := range *in { | ||||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingRunnerSetList.
 | ||||
| func (in *AutoscalingRunnerSetList) DeepCopy() *AutoscalingRunnerSetList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingRunnerSetList) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *AutoscalingRunnerSetList) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingRunnerSetSpec) DeepCopyInto(out *AutoscalingRunnerSetSpec) { | ||||
| 	*out = *in | ||||
| 	if in.Proxy != nil { | ||||
| 		in, out := &in.Proxy, &out.Proxy | ||||
| 		*out = new(ProxyConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	in.Template.DeepCopyInto(&out.Template) | ||||
| 	if in.ListenerMetrics != nil { | ||||
| 		in, out := &in.ListenerMetrics, &out.ListenerMetrics | ||||
| 		*out = new(MetricsConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.ListenerTemplate != nil { | ||||
| 		in, out := &in.ListenerTemplate, &out.ListenerTemplate | ||||
| 		*out = new(v1.PodTemplateSpec) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.MaxRunners != nil { | ||||
| 		in, out := &in.MaxRunners, &out.MaxRunners | ||||
| 		*out = new(int) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.MinRunners != nil { | ||||
| 		in, out := &in.MinRunners, &out.MinRunners | ||||
| 		*out = new(int) | ||||
| 		**out = **in | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingRunnerSetSpec.
 | ||||
| func (in *AutoscalingRunnerSetSpec) DeepCopy() *AutoscalingRunnerSetSpec { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingRunnerSetSpec) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AutoscalingRunnerSetStatus) DeepCopyInto(out *AutoscalingRunnerSetStatus) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AutoscalingRunnerSetStatus.
 | ||||
| func (in *AutoscalingRunnerSetStatus) DeepCopy() *AutoscalingRunnerSetStatus { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AutoscalingRunnerSetStatus) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *AzureKeyVaultConfig) DeepCopyInto(out *AzureKeyVaultConfig) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AzureKeyVaultConfig.
 | ||||
| func (in *AzureKeyVaultConfig) DeepCopy() *AzureKeyVaultConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(AzureKeyVaultConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *CounterMetric) DeepCopyInto(out *CounterMetric) { | ||||
| 	*out = *in | ||||
| 	if in.Labels != nil { | ||||
| 		in, out := &in.Labels, &out.Labels | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new CounterMetric.
 | ||||
| func (in *CounterMetric) DeepCopy() *CounterMetric { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(CounterMetric) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunner) DeepCopyInto(out *EphemeralRunner) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) | ||||
| 	in.Spec.DeepCopyInto(&out.Spec) | ||||
| 	in.Status.DeepCopyInto(&out.Status) | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunner.
 | ||||
| func (in *EphemeralRunner) DeepCopy() *EphemeralRunner { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunner) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *EphemeralRunner) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerList) DeepCopyInto(out *EphemeralRunnerList) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||
| 	if in.Items != nil { | ||||
| 		in, out := &in.Items, &out.Items | ||||
| 		*out = make([]EphemeralRunner, len(*in)) | ||||
| 		for i := range *in { | ||||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerList.
 | ||||
| func (in *EphemeralRunnerList) DeepCopy() *EphemeralRunnerList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerList) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *EphemeralRunnerList) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerSet) DeepCopyInto(out *EphemeralRunnerSet) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ObjectMeta.DeepCopyInto(&out.ObjectMeta) | ||||
| 	in.Spec.DeepCopyInto(&out.Spec) | ||||
| 	out.Status = in.Status | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSet.
 | ||||
| func (in *EphemeralRunnerSet) DeepCopy() *EphemeralRunnerSet { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerSet) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *EphemeralRunnerSet) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerSetList) DeepCopyInto(out *EphemeralRunnerSetList) { | ||||
| 	*out = *in | ||||
| 	out.TypeMeta = in.TypeMeta | ||||
| 	in.ListMeta.DeepCopyInto(&out.ListMeta) | ||||
| 	if in.Items != nil { | ||||
| 		in, out := &in.Items, &out.Items | ||||
| 		*out = make([]EphemeralRunnerSet, len(*in)) | ||||
| 		for i := range *in { | ||||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSetList.
 | ||||
| func (in *EphemeralRunnerSetList) DeepCopy() *EphemeralRunnerSetList { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerSetList) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
 | ||||
| func (in *EphemeralRunnerSetList) DeepCopyObject() runtime.Object { | ||||
| 	if c := in.DeepCopy(); c != nil { | ||||
| 		return c | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerSetSpec) DeepCopyInto(out *EphemeralRunnerSetSpec) { | ||||
| 	*out = *in | ||||
| 	in.EphemeralRunnerSpec.DeepCopyInto(&out.EphemeralRunnerSpec) | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSetSpec.
 | ||||
| func (in *EphemeralRunnerSetSpec) DeepCopy() *EphemeralRunnerSetSpec { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerSetSpec) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerSetStatus) DeepCopyInto(out *EphemeralRunnerSetStatus) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSetStatus.
 | ||||
| func (in *EphemeralRunnerSetStatus) DeepCopy() *EphemeralRunnerSetStatus { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerSetStatus) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerSpec) DeepCopyInto(out *EphemeralRunnerSpec) { | ||||
| 	*out = *in | ||||
| 	if in.GitHubServerTLS != nil { | ||||
| 		in, out := &in.GitHubServerTLS, &out.GitHubServerTLS | ||||
| 		*out = new(TLSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.Proxy != nil { | ||||
| 		in, out := &in.Proxy, &out.Proxy | ||||
| 		*out = new(ProxyConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.VaultConfig != nil { | ||||
| 		in, out := &in.VaultConfig, &out.VaultConfig | ||||
| 		*out = new(VaultConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	in.PodTemplateSpec.DeepCopyInto(&out.PodTemplateSpec) | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerSpec.
 | ||||
| func (in *EphemeralRunnerSpec) DeepCopy() *EphemeralRunnerSpec { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerSpec) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *EphemeralRunnerStatus) DeepCopyInto(out *EphemeralRunnerStatus) { | ||||
| 	*out = *in | ||||
| 	if in.Failures != nil { | ||||
| 		in, out := &in.Failures, &out.Failures | ||||
| 		*out = make(map[string]metav1.Time, len(*in)) | ||||
| 		for key, val := range *in { | ||||
| 			(*out)[key] = *val.DeepCopy() | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new EphemeralRunnerStatus.
 | ||||
| func (in *EphemeralRunnerStatus) DeepCopy() *EphemeralRunnerStatus { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(EphemeralRunnerStatus) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *GaugeMetric) DeepCopyInto(out *GaugeMetric) { | ||||
| 	*out = *in | ||||
| 	if in.Labels != nil { | ||||
| 		in, out := &in.Labels, &out.Labels | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GaugeMetric.
 | ||||
| func (in *GaugeMetric) DeepCopy() *GaugeMetric { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(GaugeMetric) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *HistogramMetric) DeepCopyInto(out *HistogramMetric) { | ||||
| 	*out = *in | ||||
| 	if in.Labels != nil { | ||||
| 		in, out := &in.Labels, &out.Labels | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	if in.Buckets != nil { | ||||
| 		in, out := &in.Buckets, &out.Buckets | ||||
| 		*out = make([]float64, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HistogramMetric.
 | ||||
| func (in *HistogramMetric) DeepCopy() *HistogramMetric { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(HistogramMetric) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *MetricsConfig) DeepCopyInto(out *MetricsConfig) { | ||||
| 	*out = *in | ||||
| 	if in.Counters != nil { | ||||
| 		in, out := &in.Counters, &out.Counters | ||||
| 		*out = make(map[string]*CounterMetric, len(*in)) | ||||
| 		for key, val := range *in { | ||||
| 			var outVal *CounterMetric | ||||
| 			if val == nil { | ||||
| 				(*out)[key] = nil | ||||
| 			} else { | ||||
| 				inVal := (*in)[key] | ||||
| 				in, out := &inVal, &outVal | ||||
| 				*out = new(CounterMetric) | ||||
| 				(*in).DeepCopyInto(*out) | ||||
| 			} | ||||
| 			(*out)[key] = outVal | ||||
| 		} | ||||
| 	} | ||||
| 	if in.Gauges != nil { | ||||
| 		in, out := &in.Gauges, &out.Gauges | ||||
| 		*out = make(map[string]*GaugeMetric, len(*in)) | ||||
| 		for key, val := range *in { | ||||
| 			var outVal *GaugeMetric | ||||
| 			if val == nil { | ||||
| 				(*out)[key] = nil | ||||
| 			} else { | ||||
| 				inVal := (*in)[key] | ||||
| 				in, out := &inVal, &outVal | ||||
| 				*out = new(GaugeMetric) | ||||
| 				(*in).DeepCopyInto(*out) | ||||
| 			} | ||||
| 			(*out)[key] = outVal | ||||
| 		} | ||||
| 	} | ||||
| 	if in.Histograms != nil { | ||||
| 		in, out := &in.Histograms, &out.Histograms | ||||
| 		*out = make(map[string]*HistogramMetric, len(*in)) | ||||
| 		for key, val := range *in { | ||||
| 			var outVal *HistogramMetric | ||||
| 			if val == nil { | ||||
| 				(*out)[key] = nil | ||||
| 			} else { | ||||
| 				inVal := (*in)[key] | ||||
| 				in, out := &inVal, &outVal | ||||
| 				*out = new(HistogramMetric) | ||||
| 				(*in).DeepCopyInto(*out) | ||||
| 			} | ||||
| 			(*out)[key] = outVal | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new MetricsConfig.
 | ||||
| func (in *MetricsConfig) DeepCopy() *MetricsConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(MetricsConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *ProxyConfig) DeepCopyInto(out *ProxyConfig) { | ||||
| 	*out = *in | ||||
| 	if in.HTTP != nil { | ||||
| 		in, out := &in.HTTP, &out.HTTP | ||||
| 		*out = new(ProxyServerConfig) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.HTTPS != nil { | ||||
| 		in, out := &in.HTTPS, &out.HTTPS | ||||
| 		*out = new(ProxyServerConfig) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.NoProxy != nil { | ||||
| 		in, out := &in.NoProxy, &out.NoProxy | ||||
| 		*out = make([]string, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyConfig.
 | ||||
| func (in *ProxyConfig) DeepCopy() *ProxyConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(ProxyConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *ProxyServerConfig) DeepCopyInto(out *ProxyServerConfig) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ProxyServerConfig.
 | ||||
| func (in *ProxyServerConfig) DeepCopy() *ProxyServerConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(ProxyServerConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *TLSCertificateSource) DeepCopyInto(out *TLSCertificateSource) { | ||||
| 	*out = *in | ||||
| 	if in.ConfigMapKeyRef != nil { | ||||
| 		in, out := &in.ConfigMapKeyRef, &out.ConfigMapKeyRef | ||||
| 		*out = new(v1.ConfigMapKeySelector) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSCertificateSource.
 | ||||
| func (in *TLSCertificateSource) DeepCopy() *TLSCertificateSource { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(TLSCertificateSource) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *TLSConfig) DeepCopyInto(out *TLSConfig) { | ||||
| 	*out = *in | ||||
| 	if in.CertificateFrom != nil { | ||||
| 		in, out := &in.CertificateFrom, &out.CertificateFrom | ||||
| 		*out = new(TLSCertificateSource) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TLSConfig.
 | ||||
| func (in *TLSConfig) DeepCopy() *TLSConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(TLSConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *VaultConfig) DeepCopyInto(out *VaultConfig) { | ||||
| 	*out = *in | ||||
| 	if in.AzureKeyVault != nil { | ||||
| 		in, out := &in.AzureKeyVault, &out.AzureKeyVault | ||||
| 		*out = new(AzureKeyVaultConfig) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.Proxy != nil { | ||||
| 		in, out := &in.Proxy, &out.Proxy | ||||
| 		*out = new(ProxyConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new VaultConfig.
 | ||||
| func (in *VaultConfig) DeepCopy() *VaultConfig { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(VaultConfig) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
|  | @ -22,7 +22,7 @@ import ( | |||
| 
 | ||||
| // HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler
 | ||||
| type HorizontalRunnerAutoscalerSpec struct { | ||||
| 	// ScaleTargetRef sis the reference to scaled resource like RunnerDeployment
 | ||||
| 	// ScaleTargetRef is the reference to scaled resource like RunnerDeployment
 | ||||
| 	ScaleTargetRef ScaleTargetRef `json:"scaleTargetRef,omitempty"` | ||||
| 
 | ||||
| 	// MinReplicas is the minimum number of replicas the deployment is allowed to scale
 | ||||
|  | @ -60,6 +60,9 @@ type HorizontalRunnerAutoscalerSpec struct { | |||
| 	// The earlier a scheduled override is, the higher it is prioritized.
 | ||||
| 	// +optional
 | ||||
| 	ScheduledOverrides []ScheduledOverride `json:"scheduledOverrides,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	GitHubAPICredentialsFrom *GitHubAPICredentialsFrom `json:"githubAPICredentialsFrom,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type ScaleUpTrigger struct { | ||||
|  | @ -130,7 +133,7 @@ type ScaleTargetRef struct { | |||
| 
 | ||||
| type MetricSpec struct { | ||||
| 	// Type is the type of metric to be used for autoscaling.
 | ||||
| 	// The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns
 | ||||
| 	// It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy.
 | ||||
| 	Type string `json:"type,omitempty"` | ||||
| 
 | ||||
| 	// RepositoryNames is the list of repository names to be used for calculating the metric.
 | ||||
|  | @ -170,7 +173,7 @@ type MetricSpec struct { | |||
| } | ||||
| 
 | ||||
| // ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule.
 | ||||
| // A schedule can optionally be recurring, so that the correspoding override happens every day, week, month, or year.
 | ||||
| // A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year.
 | ||||
| type ScheduledOverride struct { | ||||
| 	// StartTime is the time at which the first override starts.
 | ||||
| 	StartTime metav1.Time `json:"startTime"` | ||||
|  | @ -18,8 +18,10 @@ package v1alpha1 | |||
| 
 | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	"k8s.io/apimachinery/pkg/api/resource" | ||||
| 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||
| 
 | ||||
| 	corev1 "k8s.io/api/core/v1" | ||||
| 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" | ||||
|  | @ -68,9 +70,24 @@ type RunnerConfig struct { | |||
| 	// +optional
 | ||||
| 	DockerRegistryMirror *string `json:"dockerRegistryMirror,omitempty"` | ||||
| 	// +optional
 | ||||
| 	DockerVarRunVolumeSizeLimit *resource.Quantity `json:"dockerVarRunVolumeSizeLimit,omitempty"` | ||||
| 	// +optional
 | ||||
| 	VolumeSizeLimit *resource.Quantity `json:"volumeSizeLimit,omitempty"` | ||||
| 	// +optional
 | ||||
| 	VolumeStorageMedium *string `json:"volumeStorageMedium,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	ContainerMode string `json:"containerMode,omitempty"` | ||||
| 
 | ||||
| 	GitHubAPICredentialsFrom *GitHubAPICredentialsFrom `json:"githubAPICredentialsFrom,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type GitHubAPICredentialsFrom struct { | ||||
| 	SecretRef SecretReference `json:"secretRef,omitempty"` | ||||
| } | ||||
| 
 | ||||
| type SecretReference struct { | ||||
| 	Name string `json:"name"` | ||||
| } | ||||
| 
 | ||||
| // RunnerPodSpec defines the desired pod spec fields of the runner pod
 | ||||
|  | @ -135,6 +152,9 @@ type RunnerPodSpec struct { | |||
| 	// +optional
 | ||||
| 	Tolerations []corev1.Toleration `json:"tolerations,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	PriorityClassName string `json:"priorityClassName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	TerminationGracePeriodSeconds *int64 `json:"terminationGracePeriodSeconds,omitempty"` | ||||
| 
 | ||||
|  | @ -152,12 +172,37 @@ type RunnerPodSpec struct { | |||
| 	// +optional
 | ||||
| 	RuntimeClassName *string `json:"runtimeClassName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	DnsPolicy corev1.DNSPolicy `json:"dnsPolicy,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	DnsConfig *corev1.PodDNSConfig `json:"dnsConfig,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	WorkVolumeClaimTemplate *WorkVolumeClaimTemplate `json:"workVolumeClaimTemplate,omitempty"` | ||||
| } | ||||
| 
 | ||||
| func (rs *RunnerSpec) Validate(rootPath *field.Path) field.ErrorList { | ||||
| 	var ( | ||||
| 		errList field.ErrorList | ||||
| 		err     error | ||||
| 	) | ||||
| 
 | ||||
| 	err = rs.validateRepository() | ||||
| 	if err != nil { | ||||
| 		errList = append(errList, field.Invalid(rootPath.Child("repository"), rs.Repository, err.Error())) | ||||
| 	} | ||||
| 
 | ||||
| 	err = rs.validateWorkVolumeClaimTemplate() | ||||
| 	if err != nil { | ||||
| 		errList = append(errList, field.Invalid(rootPath.Child("workVolumeClaimTemplate"), rs.WorkVolumeClaimTemplate, err.Error())) | ||||
| 	} | ||||
| 
 | ||||
| 	return errList | ||||
| } | ||||
| 
 | ||||
| // ValidateRepository validates repository field.
 | ||||
| func (rs *RunnerSpec) ValidateRepository() error { | ||||
| func (rs *RunnerSpec) validateRepository() error { | ||||
| 	// Enterprise, Organization and repository are both exclusive.
 | ||||
| 	foundCount := 0 | ||||
| 	if len(rs.Organization) > 0 { | ||||
|  | @ -170,15 +215,27 @@ func (rs *RunnerSpec) ValidateRepository() error { | |||
| 		foundCount += 1 | ||||
| 	} | ||||
| 	if foundCount == 0 { | ||||
| 		return errors.New("Spec needs enterprise, organization or repository") | ||||
| 		return errors.New("spec needs enterprise, organization or repository") | ||||
| 	} | ||||
| 	if foundCount > 1 { | ||||
| 		return errors.New("Spec cannot have many fields defined enterprise, organization and repository") | ||||
| 		return errors.New("spec cannot have many fields defined enterprise, organization and repository") | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (rs *RunnerSpec) validateWorkVolumeClaimTemplate() error { | ||||
| 	if rs.ContainerMode != "kubernetes" { | ||||
| 		return nil | ||||
| 	} | ||||
| 
 | ||||
| 	if rs.WorkVolumeClaimTemplate == nil { | ||||
| 		return errors.New("Spec.ContainerMode: kubernetes must have workVolumeClaimTemplate field specified") | ||||
| 	} | ||||
| 
 | ||||
| 	return rs.WorkVolumeClaimTemplate.validate() | ||||
| } | ||||
| 
 | ||||
| // RunnerStatus defines the observed state of Runner
 | ||||
| type RunnerStatus struct { | ||||
| 	// Turns true only if the runner pod is ready.
 | ||||
|  | @ -193,10 +250,60 @@ type RunnerStatus struct { | |||
| 	// +optional
 | ||||
| 	Message string `json:"message,omitempty"` | ||||
| 	// +optional
 | ||||
| 	WorkflowStatus *WorkflowStatus `json:"workflow"` | ||||
| 	// +optional
 | ||||
| 	// +nullable
 | ||||
| 	LastRegistrationCheckTime *metav1.Time `json:"lastRegistrationCheckTime,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // WorkflowStatus contains various information that is propagated
 | ||||
| // from GitHub Actions workflow run environment variables to
 | ||||
| // ease monitoring workflow run/job/steps that are triggerred on the runner.
 | ||||
| type WorkflowStatus struct { | ||||
| 	// +optional
 | ||||
| 	// Name is the name of the workflow
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_WORKFLOW defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	Name string `json:"name,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// Repository is the owner and repository name of the workflow
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_REPOSITORY defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	Repository string `json:"repository,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// ReositoryOwner is the repository owner's name for the workflow
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_REPOSITORY_OWNER defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	RepositoryOwner string `json:"repositoryOwner,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// GITHUB_RUN_NUMBER is the unique number for the current workflow run
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_RUN_ID defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	RunNumber string `json:"runNumber,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// RunID is the unique number for the current workflow run
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_RUN_ID defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	RunID string `json:"runID,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// Job is the name of the current job
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_JOB defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	Job string `json:"job,omitempty"` | ||||
| 	// +optional
 | ||||
| 	// Action is the name of the current action or the step ID of the current step
 | ||||
| 	// that is triggerred within the runner.
 | ||||
| 	// It corresponds to GITHUB_ACTION defined in
 | ||||
| 	// https://docs.github.com/en/actions/learn-github-actions/environment-variables
 | ||||
| 	Action string `json:"action,omitempty"` | ||||
| } | ||||
| 
 | ||||
| // RunnerStatusRegistration contains runner registration status
 | ||||
| type RunnerStatusRegistration struct { | ||||
| 	Enterprise   string      `json:"enterprise,omitempty"` | ||||
|  | @ -207,13 +314,62 @@ type RunnerStatusRegistration struct { | |||
| 	ExpiresAt    metav1.Time `json:"expiresAt"` | ||||
| } | ||||
| 
 | ||||
| type WorkVolumeClaimTemplate struct { | ||||
| 	StorageClassName string                              `json:"storageClassName"` | ||||
| 	AccessModes      []corev1.PersistentVolumeAccessMode `json:"accessModes"` | ||||
| 	Resources        corev1.VolumeResourceRequirements   `json:"resources"` | ||||
| } | ||||
| 
 | ||||
| func (w *WorkVolumeClaimTemplate) validate() error { | ||||
| 	if len(w.AccessModes) == 0 { | ||||
| 		return errors.New("access mode should have at least one mode specified") | ||||
| 	} | ||||
| 
 | ||||
| 	for _, accessMode := range w.AccessModes { | ||||
| 		switch accessMode { | ||||
| 		case corev1.ReadWriteOnce, corev1.ReadWriteMany: | ||||
| 		default: | ||||
| 			return fmt.Errorf("access mode %v is not supported", accessMode) | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func (w *WorkVolumeClaimTemplate) V1Volume() corev1.Volume { | ||||
| 	return corev1.Volume{ | ||||
| 		Name: "work", | ||||
| 		VolumeSource: corev1.VolumeSource{ | ||||
| 			Ephemeral: &corev1.EphemeralVolumeSource{ | ||||
| 				VolumeClaimTemplate: &corev1.PersistentVolumeClaimTemplate{ | ||||
| 					Spec: corev1.PersistentVolumeClaimSpec{ | ||||
| 						AccessModes:      w.AccessModes, | ||||
| 						StorageClassName: &w.StorageClassName, | ||||
| 						Resources:        w.Resources, | ||||
| 					}, | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (w *WorkVolumeClaimTemplate) V1VolumeMount(mountPath string) corev1.VolumeMount { | ||||
| 	return corev1.VolumeMount{ | ||||
| 		MountPath: mountPath, | ||||
| 		Name:      "work", | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.enterprise",name=Enterprise,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.organization",name=Organization,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.repository",name=Repository,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.group",name=Group,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.labels",name=Labels,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.phase",name=Status,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.message",name=Message,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.workflow.repository",name=WF Repo,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.workflow.runID",name=WF Run,type=string
 | ||||
| // +kubebuilder:printcolumn:name="Age",type="date",JSONPath=".metadata.creationTimestamp"
 | ||||
| 
 | ||||
| // Runner is the Schema for the runners API
 | ||||
|  | @ -235,11 +391,7 @@ func (r Runner) IsRegisterable() bool { | |||
| 	} | ||||
| 
 | ||||
| 	now := metav1.Now() | ||||
| 	if r.Status.Registration.ExpiresAt.Before(&now) { | ||||
| 		return false | ||||
| 	} | ||||
| 
 | ||||
| 	return true | ||||
| 	return !r.Status.Registration.ExpiresAt.Before(&now) | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:object:root=true
 | ||||
|  | @ -17,12 +17,16 @@ limitations under the License. | |||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||
| 	ctrl "sigs.k8s.io/controller-runtime" | ||||
| 	logf "sigs.k8s.io/controller-runtime/pkg/log" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||||
| ) | ||||
| 
 | ||||
| // log is for logging in this package.
 | ||||
|  | @ -31,50 +35,57 @@ var runnerLog = logf.Log.WithName("runner-resource") | |||
| func (r *Runner) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||
| 	return ctrl.NewWebhookManagedBy(mgr). | ||||
| 		For(r). | ||||
| 		WithDefaulter(&RunnerDefaulter{}). | ||||
| 		WithValidator(&RunnerValidator{}). | ||||
| 		Complete() | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=mutate.runner.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Defaulter = &Runner{} | ||||
| var _ webhook.CustomDefaulter = &RunnerDefaulter{} | ||||
| 
 | ||||
| type RunnerDefaulter struct{} | ||||
| 
 | ||||
| // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||
| func (r *Runner) Default() { | ||||
| func (*RunnerDefaulter) Default(ctx context.Context, obj runtime.Object) error { | ||||
| 	// Nothing to do.
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runner,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runners,versions=v1alpha1,name=validate.runner.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Validator = &Runner{} | ||||
| var _ webhook.CustomValidator = &RunnerValidator{} | ||||
| 
 | ||||
| type RunnerValidator struct{} | ||||
| 
 | ||||
| // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *Runner) ValidateCreate() error { | ||||
| func (*RunnerValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*Runner) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected Runner object, got %T", obj) | ||||
| 	} | ||||
| 	runnerLog.Info("validate resource to be created", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *Runner) ValidateUpdate(old runtime.Object) error { | ||||
| func (*RunnerValidator) ValidateUpdate(ctx context.Context, old, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*Runner) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected Runner object, got %T", obj) | ||||
| 	} | ||||
| 	runnerLog.Info("validate resource to be updated", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *Runner) ValidateDelete() error { | ||||
| 	return nil | ||||
| func (*RunnerValidator) ValidateDelete(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| // Validate validates resource spec.
 | ||||
| func (r *Runner) Validate() error { | ||||
| 	var ( | ||||
| 		errList field.ErrorList | ||||
| 		err     error | ||||
| 	) | ||||
| 
 | ||||
| 	err = r.Spec.ValidateRepository() | ||||
| 	if err != nil { | ||||
| 		errList = append(errList, field.Invalid(field.NewPath("spec", "repository"), r.Spec.Repository, err.Error())) | ||||
| 	} | ||||
| 	errList := r.Spec.Validate(field.NewPath("spec")) | ||||
| 
 | ||||
| 	if len(errList) > 0 { | ||||
| 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||
|  | @ -33,7 +33,7 @@ type RunnerDeploymentSpec struct { | |||
| 
 | ||||
| 	// EffectiveTime is the time the upstream controller requested to sync Replicas.
 | ||||
| 	// It is usually populated by the webhook-based autoscaler via HRA.
 | ||||
| 	// The value is inherited to RunnerRepicaSet(s) and used to prevent ephemeral runners from unnecessarily recreated.
 | ||||
| 	// The value is inherited to RunnerReplicaSet(s) and used to prevent ephemeral runners from unnecessarily recreated.
 | ||||
| 	//
 | ||||
| 	// +optional
 | ||||
| 	// +nullable
 | ||||
|  | @ -77,6 +77,11 @@ type RunnerDeploymentStatus struct { | |||
| // +kubebuilder:object:root=true
 | ||||
| // +kubebuilder:resource:shortName=rdeploy
 | ||||
| // +kubebuilder:subresource:status
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.template.spec.enterprise",name=Enterprise,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.template.spec.organization",name=Organization,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.template.spec.repository",name=Repository,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.template.spec.group",name=Group,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.template.spec.labels",name=Labels,type=string
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".spec.replicas",name=Desired,type=number
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.replicas",name=Current,type=number
 | ||||
| // +kubebuilder:printcolumn:JSONPath=".status.updatedReplicas",name=Up-To-Date,type=number
 | ||||
|  | @ -17,12 +17,16 @@ limitations under the License. | |||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||
| 	ctrl "sigs.k8s.io/controller-runtime" | ||||
| 	logf "sigs.k8s.io/controller-runtime/pkg/log" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||||
| ) | ||||
| 
 | ||||
| // log is for logging in this package.
 | ||||
|  | @ -31,50 +35,57 @@ var runnerDeploymentLog = logf.Log.WithName("runnerdeployment-resource") | |||
| func (r *RunnerDeployment) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||
| 	return ctrl.NewWebhookManagedBy(mgr). | ||||
| 		For(r). | ||||
| 		WithDefaulter(&RunnerDeploymentDefaulter{}). | ||||
| 		WithValidator(&RunnerDeploymentValidator{}). | ||||
| 		Complete() | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=mutate.runnerdeployment.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Defaulter = &RunnerDeployment{} | ||||
| var _ webhook.CustomDefaulter = &RunnerDeploymentDefaulter{} | ||||
| 
 | ||||
| type RunnerDeploymentDefaulter struct{} | ||||
| 
 | ||||
| // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||
| func (r *RunnerDeployment) Default() { | ||||
| func (*RunnerDeploymentDefaulter) Default(context.Context, runtime.Object) error { | ||||
| 	// Nothing to do.
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerdeployment,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerdeployments,versions=v1alpha1,name=validate.runnerdeployment.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Validator = &RunnerDeployment{} | ||||
| var _ webhook.CustomValidator = &RunnerDeploymentValidator{} | ||||
| 
 | ||||
| type RunnerDeploymentValidator struct{} | ||||
| 
 | ||||
| // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerDeployment) ValidateCreate() error { | ||||
| func (*RunnerDeploymentValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*RunnerDeployment) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected RunnerDeployment object, got %T", obj) | ||||
| 	} | ||||
| 	runnerDeploymentLog.Info("validate resource to be created", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerDeployment) ValidateUpdate(old runtime.Object) error { | ||||
| func (*RunnerDeploymentValidator) ValidateUpdate(ctx context.Context, old, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*RunnerDeployment) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected RunnerDeployment object, got %T", obj) | ||||
| 	} | ||||
| 	runnerDeploymentLog.Info("validate resource to be updated", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerDeployment) ValidateDelete() error { | ||||
| 	return nil | ||||
| func (*RunnerDeploymentValidator) ValidateDelete(context.Context, runtime.Object) (admission.Warnings, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| // Validate validates resource spec.
 | ||||
| func (r *RunnerDeployment) Validate() error { | ||||
| 	var ( | ||||
| 		errList field.ErrorList | ||||
| 		err     error | ||||
| 	) | ||||
| 
 | ||||
| 	err = r.Spec.Template.Spec.ValidateRepository() | ||||
| 	if err != nil { | ||||
| 		errList = append(errList, field.Invalid(field.NewPath("spec", "template", "spec", "repository"), r.Spec.Template.Spec.Repository, err.Error())) | ||||
| 	} | ||||
| 	errList := r.Spec.Template.Spec.Validate(field.NewPath("spec", "template", "spec")) | ||||
| 
 | ||||
| 	if len(errList) > 0 { | ||||
| 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||
|  | @ -17,12 +17,16 @@ limitations under the License. | |||
| package v1alpha1 | ||||
| 
 | ||||
| import ( | ||||
| 	"context" | ||||
| 	"fmt" | ||||
| 
 | ||||
| 	apierrors "k8s.io/apimachinery/pkg/api/errors" | ||||
| 	"k8s.io/apimachinery/pkg/runtime" | ||||
| 	"k8s.io/apimachinery/pkg/util/validation/field" | ||||
| 	ctrl "sigs.k8s.io/controller-runtime" | ||||
| 	logf "sigs.k8s.io/controller-runtime/pkg/log" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook" | ||||
| 	"sigs.k8s.io/controller-runtime/pkg/webhook/admission" | ||||
| ) | ||||
| 
 | ||||
| // log is for logging in this package.
 | ||||
|  | @ -31,50 +35,57 @@ var runnerReplicaSetLog = logf.Log.WithName("runnerreplicaset-resource") | |||
| func (r *RunnerReplicaSet) SetupWebhookWithManager(mgr ctrl.Manager) error { | ||||
| 	return ctrl.NewWebhookManagedBy(mgr). | ||||
| 		For(r). | ||||
| 		WithDefaulter(&RunnerReplicaSetDefaulter{}). | ||||
| 		WithValidator(&RunnerReplicaSetValidator{}). | ||||
| 		Complete() | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/mutate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=true,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=mutate.runnerreplicaset.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Defaulter = &RunnerReplicaSet{} | ||||
| var _ webhook.CustomDefaulter = &RunnerReplicaSetDefaulter{} | ||||
| 
 | ||||
| type RunnerReplicaSetDefaulter struct{} | ||||
| 
 | ||||
| // Default implements webhook.Defaulter so a webhook will be registered for the type
 | ||||
| func (r *RunnerReplicaSet) Default() { | ||||
| func (*RunnerReplicaSetDefaulter) Default(context.Context, runtime.Object) error { | ||||
| 	// Nothing to do.
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // +kubebuilder:webhook:path=/validate-actions-summerwind-dev-v1alpha1-runnerreplicaset,verbs=create;update,mutating=false,failurePolicy=fail,groups=actions.summerwind.dev,resources=runnerreplicasets,versions=v1alpha1,name=validate.runnerreplicaset.actions.summerwind.dev,sideEffects=None,admissionReviewVersions=v1beta1
 | ||||
| 
 | ||||
| var _ webhook.Validator = &RunnerReplicaSet{} | ||||
| var _ webhook.CustomValidator = &RunnerReplicaSetValidator{} | ||||
| 
 | ||||
| type RunnerReplicaSetValidator struct{} | ||||
| 
 | ||||
| // ValidateCreate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerReplicaSet) ValidateCreate() error { | ||||
| func (*RunnerReplicaSetValidator) ValidateCreate(ctx context.Context, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*RunnerReplicaSet) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected RunnerReplicaSet object, got %T", obj) | ||||
| 	} | ||||
| 	runnerReplicaSetLog.Info("validate resource to be created", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateUpdate implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerReplicaSet) ValidateUpdate(old runtime.Object) error { | ||||
| func (*RunnerReplicaSetValidator) ValidateUpdate(ctx context.Context, old, obj runtime.Object) (admission.Warnings, error) { | ||||
| 	r, ok := obj.(*RunnerReplicaSet) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("expected RunnerReplicaSet object, got %T", obj) | ||||
| 	} | ||||
| 	runnerReplicaSetLog.Info("validate resource to be updated", "name", r.Name) | ||||
| 	return r.Validate() | ||||
| 	return nil, r.Validate() | ||||
| } | ||||
| 
 | ||||
| // ValidateDelete implements webhook.Validator so a webhook will be registered for the type
 | ||||
| func (r *RunnerReplicaSet) ValidateDelete() error { | ||||
| 	return nil | ||||
| func (*RunnerReplicaSetValidator) ValidateDelete(context.Context, runtime.Object) (admission.Warnings, error) { | ||||
| 	return nil, nil | ||||
| } | ||||
| 
 | ||||
| // Validate validates resource spec.
 | ||||
| func (r *RunnerReplicaSet) Validate() error { | ||||
| 	var ( | ||||
| 		errList field.ErrorList | ||||
| 		err     error | ||||
| 	) | ||||
| 
 | ||||
| 	err = r.Spec.Template.Spec.ValidateRepository() | ||||
| 	if err != nil { | ||||
| 		errList = append(errList, field.Invalid(field.NewPath("spec", "template", "spec", "repository"), r.Spec.Template.Spec.Repository, err.Error())) | ||||
| 	} | ||||
| 	errList := r.Spec.Template.Spec.Validate(field.NewPath("spec", "template", "spec")) | ||||
| 
 | ||||
| 	if len(errList) > 0 { | ||||
| 		return apierrors.NewInvalid(r.GroupVersionKind().GroupKind(), r.Name, errList) | ||||
|  | @ -33,6 +33,12 @@ type RunnerSetSpec struct { | |||
| 	// +nullable
 | ||||
| 	EffectiveTime *metav1.Time `json:"effectiveTime,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	ServiceAccountName string `json:"serviceAccountName,omitempty"` | ||||
| 
 | ||||
| 	// +optional
 | ||||
| 	WorkVolumeClaimTemplate *WorkVolumeClaimTemplate `json:"workVolumeClaimTemplate,omitempty"` | ||||
| 
 | ||||
| 	appsv1.StatefulSetSpec `json:",inline"` | ||||
| } | ||||
| 
 | ||||
|  | @ -1,5 +1,4 @@ | |||
| //go:build !ignore_autogenerated
 | ||||
| // +build !ignore_autogenerated
 | ||||
| 
 | ||||
| /* | ||||
| Copyright 2020 The actions-runner-controller authors. | ||||
|  | @ -90,6 +89,22 @@ func (in *CheckRunSpec) DeepCopy() *CheckRunSpec { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *GitHubAPICredentialsFrom) DeepCopyInto(out *GitHubAPICredentialsFrom) { | ||||
| 	*out = *in | ||||
| 	out.SecretRef = in.SecretRef | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new GitHubAPICredentialsFrom.
 | ||||
| func (in *GitHubAPICredentialsFrom) DeepCopy() *GitHubAPICredentialsFrom { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(GitHubAPICredentialsFrom) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *GitHubEventScaleUpTriggerSpec) DeepCopyInto(out *GitHubEventScaleUpTriggerSpec) { | ||||
| 	*out = *in | ||||
|  | @ -231,6 +246,11 @@ func (in *HorizontalRunnerAutoscalerSpec) DeepCopyInto(out *HorizontalRunnerAuto | |||
| 			(*in)[i].DeepCopyInto(&(*out)[i]) | ||||
| 		} | ||||
| 	} | ||||
| 	if in.GitHubAPICredentialsFrom != nil { | ||||
| 		in, out := &in.GitHubAPICredentialsFrom, &out.GitHubAPICredentialsFrom | ||||
| 		*out = new(GitHubAPICredentialsFrom) | ||||
| 		**out = **in | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new HorizontalRunnerAutoscalerSpec.
 | ||||
|  | @ -415,6 +435,11 @@ func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) { | |||
| 		*out = new(string) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.DockerVarRunVolumeSizeLimit != nil { | ||||
| 		in, out := &in.DockerVarRunVolumeSizeLimit, &out.DockerVarRunVolumeSizeLimit | ||||
| 		x := (*in).DeepCopy() | ||||
| 		*out = &x | ||||
| 	} | ||||
| 	if in.VolumeSizeLimit != nil { | ||||
| 		in, out := &in.VolumeSizeLimit, &out.VolumeSizeLimit | ||||
| 		x := (*in).DeepCopy() | ||||
|  | @ -425,6 +450,11 @@ func (in *RunnerConfig) DeepCopyInto(out *RunnerConfig) { | |||
| 		*out = new(string) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.GitHubAPICredentialsFrom != nil { | ||||
| 		in, out := &in.GitHubAPICredentialsFrom, &out.GitHubAPICredentialsFrom | ||||
| 		*out = new(GitHubAPICredentialsFrom) | ||||
| 		**out = **in | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerConfig.
 | ||||
|  | @ -437,6 +467,21 @@ func (in *RunnerConfig) DeepCopy() *RunnerConfig { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerDefaulter) DeepCopyInto(out *RunnerDefaulter) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerDefaulter.
 | ||||
| func (in *RunnerDefaulter) DeepCopy() *RunnerDefaulter { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerDefaulter) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerDeployment) DeepCopyInto(out *RunnerDeployment) { | ||||
| 	*out = *in | ||||
|  | @ -464,6 +509,21 @@ func (in *RunnerDeployment) DeepCopyObject() runtime.Object { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerDeploymentDefaulter) DeepCopyInto(out *RunnerDeploymentDefaulter) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerDeploymentDefaulter.
 | ||||
| func (in *RunnerDeploymentDefaulter) DeepCopy() *RunnerDeploymentDefaulter { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerDeploymentDefaulter) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerDeploymentList) DeepCopyInto(out *RunnerDeploymentList) { | ||||
| 	*out = *in | ||||
|  | @ -566,6 +626,21 @@ func (in *RunnerDeploymentStatus) DeepCopy() *RunnerDeploymentStatus { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerDeploymentValidator) DeepCopyInto(out *RunnerDeploymentValidator) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerDeploymentValidator.
 | ||||
| func (in *RunnerDeploymentValidator) DeepCopy() *RunnerDeploymentValidator { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerDeploymentValidator) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerList) DeepCopyInto(out *RunnerList) { | ||||
| 	*out = *in | ||||
|  | @ -741,6 +816,11 @@ func (in *RunnerPodSpec) DeepCopyInto(out *RunnerPodSpec) { | |||
| 		*out = new(v1.PodDNSConfig) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	if in.WorkVolumeClaimTemplate != nil { | ||||
| 		in, out := &in.WorkVolumeClaimTemplate, &out.WorkVolumeClaimTemplate | ||||
| 		*out = new(WorkVolumeClaimTemplate) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerPodSpec.
 | ||||
|  | @ -780,6 +860,21 @@ func (in *RunnerReplicaSet) DeepCopyObject() runtime.Object { | |||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerReplicaSetDefaulter) DeepCopyInto(out *RunnerReplicaSetDefaulter) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSetDefaulter.
 | ||||
| func (in *RunnerReplicaSetDefaulter) DeepCopy() *RunnerReplicaSetDefaulter { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerReplicaSetDefaulter) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerReplicaSetList) DeepCopyInto(out *RunnerReplicaSetList) { | ||||
| 	*out = *in | ||||
|  | @ -872,6 +967,21 @@ func (in *RunnerReplicaSetStatus) DeepCopy() *RunnerReplicaSetStatus { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerReplicaSetValidator) DeepCopyInto(out *RunnerReplicaSetValidator) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerReplicaSetValidator.
 | ||||
| func (in *RunnerReplicaSetValidator) DeepCopy() *RunnerReplicaSetValidator { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerReplicaSetValidator) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerSet) DeepCopyInto(out *RunnerSet) { | ||||
| 	*out = *in | ||||
|  | @ -939,6 +1049,11 @@ func (in *RunnerSetSpec) DeepCopyInto(out *RunnerSetSpec) { | |||
| 		in, out := &in.EffectiveTime, &out.EffectiveTime | ||||
| 		*out = (*in).DeepCopy() | ||||
| 	} | ||||
| 	if in.WorkVolumeClaimTemplate != nil { | ||||
| 		in, out := &in.WorkVolumeClaimTemplate, &out.WorkVolumeClaimTemplate | ||||
| 		*out = new(WorkVolumeClaimTemplate) | ||||
| 		(*in).DeepCopyInto(*out) | ||||
| 	} | ||||
| 	in.StatefulSetSpec.DeepCopyInto(&out.StatefulSetSpec) | ||||
| } | ||||
| 
 | ||||
|  | @ -1013,6 +1128,11 @@ func (in *RunnerSpec) DeepCopy() *RunnerSpec { | |||
| func (in *RunnerStatus) DeepCopyInto(out *RunnerStatus) { | ||||
| 	*out = *in | ||||
| 	in.Registration.DeepCopyInto(&out.Registration) | ||||
| 	if in.WorkflowStatus != nil { | ||||
| 		in, out := &in.WorkflowStatus, &out.WorkflowStatus | ||||
| 		*out = new(WorkflowStatus) | ||||
| 		**out = **in | ||||
| 	} | ||||
| 	if in.LastRegistrationCheckTime != nil { | ||||
| 		in, out := &in.LastRegistrationCheckTime, &out.LastRegistrationCheckTime | ||||
| 		*out = (*in).DeepCopy() | ||||
|  | @ -1067,6 +1187,21 @@ func (in *RunnerTemplate) DeepCopy() *RunnerTemplate { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *RunnerValidator) DeepCopyInto(out *RunnerValidator) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RunnerValidator.
 | ||||
| func (in *RunnerValidator) DeepCopy() *RunnerValidator { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(RunnerValidator) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *ScaleTargetRef) DeepCopyInto(out *ScaleTargetRef) { | ||||
| 	*out = *in | ||||
|  | @ -1126,6 +1261,42 @@ func (in *ScheduledOverride) DeepCopy() *ScheduledOverride { | |||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *SecretReference) DeepCopyInto(out *SecretReference) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretReference.
 | ||||
| func (in *SecretReference) DeepCopy() *SecretReference { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(SecretReference) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *WorkVolumeClaimTemplate) DeepCopyInto(out *WorkVolumeClaimTemplate) { | ||||
| 	*out = *in | ||||
| 	if in.AccessModes != nil { | ||||
| 		in, out := &in.AccessModes, &out.AccessModes | ||||
| 		*out = make([]v1.PersistentVolumeAccessMode, len(*in)) | ||||
| 		copy(*out, *in) | ||||
| 	} | ||||
| 	in.Resources.DeepCopyInto(&out.Resources) | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkVolumeClaimTemplate.
 | ||||
| func (in *WorkVolumeClaimTemplate) DeepCopy() *WorkVolumeClaimTemplate { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(WorkVolumeClaimTemplate) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *WorkflowJobSpec) DeepCopyInto(out *WorkflowJobSpec) { | ||||
| 	*out = *in | ||||
|  | @ -1140,3 +1311,18 @@ func (in *WorkflowJobSpec) DeepCopy() *WorkflowJobSpec { | |||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
| 
 | ||||
| // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 | ||||
| func (in *WorkflowStatus) DeepCopyInto(out *WorkflowStatus) { | ||||
| 	*out = *in | ||||
| } | ||||
| 
 | ||||
| // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new WorkflowStatus.
 | ||||
| func (in *WorkflowStatus) DeepCopy() *WorkflowStatus { | ||||
| 	if in == nil { | ||||
| 		return nil | ||||
| 	} | ||||
| 	out := new(WorkflowStatus) | ||||
| 	in.DeepCopyInto(out) | ||||
| 	return out | ||||
| } | ||||
|  | @ -0,0 +1,6 @@ | |||
| package build | ||||
| 
 | ||||
| // This is overridden at build-time using go-build ldflags. dev is the fallback value
 | ||||
| var Version = "NA" | ||||
| 
 | ||||
| var CommitSHA = "NA" | ||||
|  | @ -0,0 +1,11 @@ | |||
| # This file defines the config for "ct" (chart tester) used by the helm linting GitHub workflow | ||||
| remote: origin | ||||
| target-branch: master | ||||
| lint-conf: charts/.ci/lint-config.yaml | ||||
| chart-repos: | ||||
|   - jetstack=https://charts.jetstack.io | ||||
| check-version-increment: false # Disable checking that the chart version has been bumped | ||||
| charts: | ||||
|   - charts/gha-runner-scale-set-controller | ||||
|   - charts/gha-runner-scale-set | ||||
| skip-clean-up: true | ||||
|  | @ -1,5 +1,9 @@ | |||
| # This file defines the config for "ct" (chart tester) used by the helm linting GitHub workflow | ||||
| remote: origin | ||||
| target-branch: master | ||||
| lint-conf: charts/.ci/lint-config.yaml | ||||
| chart-repos: | ||||
|   - jetstack=https://charts.jetstack.io | ||||
| check-version-increment: false # Disable checking that the chart version has been bumped | ||||
| charts: | ||||
|   - charts/actions-runner-controller | ||||
|  |  | |||
|  | @ -1,6 +1,5 @@ | |||
| #!/bin/bash | ||||
| 
 | ||||
| 
 | ||||
| for chart in `ls charts`; | ||||
| do | ||||
| helm template --values charts/$chart/ci/ci-values.yaml charts/$chart | kube-score score - \ | ||||
|  |  | |||
|  | @ -15,15 +15,15 @@ type: application | |||
| # This is the chart version. This version number should be incremented each time you make changes | ||||
| # to the chart and its templates, including the app version. | ||||
| # Versions are expected to follow Semantic Versioning (https://semver.org/) | ||||
| version: 0.19.0 | ||||
| version: 0.23.7 | ||||
| 
 | ||||
| # Used as the default manager tag value when no tag property is provided in the values.yaml | ||||
| appVersion: 0.24.0 | ||||
| appVersion: 0.27.6 | ||||
| 
 | ||||
| home: https://github.com/actions-runner-controller/actions-runner-controller | ||||
| home: https://github.com/actions/actions-runner-controller | ||||
| 
 | ||||
| sources: | ||||
|   - https://github.com/actions-runner-controller/actions-runner-controller | ||||
|   - https://github.com/actions/actions-runner-controller | ||||
| 
 | ||||
| maintainers: | ||||
|   - name: actions-runner-controller | ||||
|  |  | |||
|  | @ -4,108 +4,161 @@ All additional docs are kept in the `docs/` folder, this README is solely for do | |||
| 
 | ||||
| ## Values | ||||
| 
 | ||||
| **_The values are documented as of HEAD, to review the configuration options for your chart version ensure you view this file at the relevant [tag](https://github.com/actions-runner-controller/actions-runner-controller/tags)_** | ||||
| **_The values are documented as of HEAD, to review the configuration options for your chart version ensure you view this file at the relevant [tag](https://github.com/actions/actions-runner-controller/tags)_** | ||||
| 
 | ||||
| > _Default values are the defaults set in the charts `values.yaml`, some properties have default configurations in the code for when the property is omitted or invalid_ | ||||
| 
 | ||||
| | Key                                                      | Description                                                                                                                | Default                                                              | | ||||
| |----------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------| | ||||
| | `labels`                                                 | Set labels to apply to all resources in the chart                                                                          |                                                                      | | ||||
| | `replicaCount`                                           | Set the number of controller pods                                                                                          | 1                                                                    | | ||||
| | `webhookPort`                                            | Set the containerPort for the webhook Pod                                                                                  | 9443                                                                 | | ||||
| | `syncPeriod`                                             | Set the period in which the controler reconciles the desired runners count                                                 | 10m                                                                  | | ||||
| | `enableLeaderElection`                                   | Enable election configuration                                                                                              | true                                                                 | | ||||
| | `leaderElectionId`                                       | Set the election ID for the controller group                                                                               |                                                                      | | ||||
| | `githubEnterpriseServerURL`                              | Set the URL for a self-hosted GitHub Enterprise Server                                                                     |                                                                      | | ||||
| | `githubURL`                                              | Override GitHub URL to be used for GitHub API calls                                                                        |                                                                      | | ||||
| | `githubUploadURL`                                        | Override GitHub Upload URL to be used for GitHub API calls                                                                 |                                                                      | | ||||
| | `runnerGithubURL`                                        | Override GitHub URL to be used by runners during registration                                                              |                                                                      | | ||||
| | `logLevel`                                               | Set the log level of the controller container                                                                              |                                                                      | | ||||
| | `additionalVolumes`                                      | Set additional volumes to add to the manager container                                                                     |                                                                      | | ||||
| | `additionalVolumeMounts`                                 | Set additional volume mounts to add to the manager container                                                               |                                                                      | | ||||
| | `authSecret.create`                                      | Deploy the controller auth secret                                                                                          | false                                                                | | ||||
| | `authSecret.name`                                        | Set the name of the auth secret                                                                                            | controller-manager                                                   | | ||||
| | `authSecret.annotations`                                 | Set annotations for the auth Secret                                                                                        |                                                                      | | ||||
| | `authSecret.github_app_id`                               | The ID of your GitHub App. **This can't be set at the same time as `authSecret.github_token`**                             |                                                                      | | ||||
| | `authSecret.github_app_installation_id`                  | The ID of your GitHub App installation. **This can't be set at the same time as `authSecret.github_token`**                |                                                                      | | ||||
| | `authSecret.github_app_private_key`                      | The multiline string of your GitHub App's private key. **This can't be set at the same time as `authSecret.github_token`** |                                                                      | | ||||
| | `authSecret.github_token`                                | Your chosen GitHub PAT token. **This can't be set at the same time as the `authSecret.github_app_*`**                      |                                                                      | | ||||
| | `authSecret.github_basicauth_username`                     | Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API                 |                                                                      | | ||||
| | `authSecret.github_basicauth_password`                     | Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API                 |                                                                      | | ||||
| | `dockerRegistryMirror`                                   | The default Docker Registry Mirror used by runners.                                                                        |                                                                      | | ||||
| | `hostNetwork`                                            | The "hostNetwork" of the controller container                                                                              | false                                                                | | ||||
| | `image.repository`                                       | The "repository/image" of the controller container                                                                         | summerwind/actions-runner-controller                                 | | ||||
| | `image.tag`                                              | The tag of the controller container                                                                                        |                                                                      | | ||||
| | `image.actionsRunnerRepositoryAndTag`                    | The "repository/image" of the actions runner container                                                                     | summerwind/actions-runner:latest                                     | | ||||
| | `image.actionsRunnerImagePullSecrets`                    | Optional image pull secrets to be included in the runner pod's ImagePullSecrets                                            |                                                                      | | ||||
| | `image.dindSidecarRepositoryAndTag`                      | The "repository/image" of the dind sidecar container                                                                       | docker:dind                                                          | | ||||
| | `image.pullPolicy`                                       | The pull policy of the controller image                                                                                    | IfNotPresent                                                         | | ||||
| | `metrics.serviceMonitor`                                 | Deploy serviceMonitor kind for for use with prometheus-operator CRDs                                                       | false                                                                | | ||||
| | `metrics.serviceAnnotations`                             | Set annotations for the provisioned metrics service resource                                                               |                                                                      | | ||||
| | `metrics.port`                                           | Set port of metrics service                                                                                                | 8443                                                                 | | ||||
| | `metrics.proxy.enabled`                                  | Deploy kube-rbac-proxy container in controller pod                                                                         | true                                                                 | | ||||
| | `metrics.proxy.image.repository`                         | The "repository/image" of the kube-proxy container                                                                         | quay.io/brancz/kube-rbac-proxy                                       | | ||||
| | `metrics.proxy.image.tag`                                | The tag of the kube-proxy image to use when pulling the container                                                          | v0.10.0                                                              | | ||||
| | `metrics.serviceMonitorLabels`                           | Set labels to apply to ServiceMonitor resources                                                                            |                                                                      | | ||||
| | `imagePullSecrets`                                       | Specifies the secret to be used when pulling the controller pod containers                                                 |                                                                      | | ||||
| | `fullnameOverride`                                       | Override the full resource names	                                                                                        |                                                                      | | ||||
| | `nameOverride`                                           | Override the resource name prefix	                                                                                        |                                                                      | | ||||
| | `serviceAccount.annotations`                              | Set annotations to the service account                                                                                     |                                                                      | | ||||
| | `serviceAccount.create`                                  | Deploy the controller pod under a service account                                                                          | true                                                                 | | ||||
| | `podAnnotations`                                         | Set annotations for the controller pod                                                                                     |                                                                      | | ||||
| | `podLabels`                                              | Set labels for the controller pod                                                                                          |                                                                      | | ||||
| | `serviceAccount.name`                                    | Set the name of the service account                                                                                        |                                                                      | | ||||
| | `securityContext`                                        | Set the security context for each container in the controller pod                                                          |                                                                      | | ||||
| | `podSecurityContext`                                     | Set the security context to controller pod                                                                                 |                                                                      | | ||||
| | `service.annotations`                                    | Set annotations for the provisioned webhook service resource                                                               |                                                                      | | ||||
| | `service.port`                                           | Set controller service ports                                                                                                |                                                                      | | ||||
| | `service.type`                                           | Set controller service type                                                                                               |                                                                      | | ||||
| | `topologySpreadConstraints`                              | Set the controller pod topologySpreadConstraints                                                                           |                                                                      | | ||||
| | `nodeSelector`                                           | Set the controller pod nodeSelector                                                                                        |                                                                      | | ||||
| | `resources`                                              | Set the controller pod resources                                                                                           |                                                                      | | ||||
| | `affinity`                                               | Set the controller pod affinity rules                                                                                      |                                                                      | | ||||
| | `podDisruptionBudget.enabled`                            | Enables a PDB to ensure HA of controller pods                                                                              |      false                                                           | | ||||
| | `podDisruptionBudget.minAvailable`                       | Minimum number of pods that must be available after eviction                                                               |                                                                      | | ||||
| | `podDisruptionBudget.maxUnavailable`                     | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required.                                   |                                                                      | | ||||
| | `tolerations`                                            | Set the controller pod tolerations                                                                                         |                                                                      | | ||||
| | `env`                                                    | Set environment variables for the controller container                                                                     |                                                                      | | ||||
| | `priorityClassName`                                      | Set the controller pod priorityClassName                                                                                   |                                                                      | | ||||
| | `scope.watchNamespace`                                   | Tells the controller and the github webhook server which namespace to watch if `scope.singleNamespace` is true             | `Release.Namespace` (the default namespace of the helm chart).       | | ||||
| | `scope.singleNamespace`                                  | Limit the controller to watch a single namespace                                                                           | false                                                                | | ||||
| | `certManagerEnabled`                                     | Enable cert-manager. If disabled you must set admissionWebHooks.caBundle and create TLS secrets manually                   | true                                                                 | | ||||
| | `admissionWebHooks.caBundle`                             | Base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate                                  |                                                                      | | ||||
| | `githubWebhookServer.logLevel`                           | Set the log level of the githubWebhookServer container                                                                     |                                                                      | | ||||
| | `githubWebhookServer.replicaCount`                       | Set the number of webhook server pods                                                                                      | 1                                                                    | | ||||
| | `githubWebhookServer.useRunnerGroupsVisibility`          | Enable supporting runner groups with custom visibility. This will incur in extra API calls and may blow up your budget. Currently, you also need to set `githubWebhookServer.secret.enabled` to enable this feature. | false                                                                | | ||||
| | `githubWebhookServer.syncPeriod`                         | Set the period in which the controller reconciles the resources                                                            | 10m                                                                  | | ||||
| | `githubWebhookServer.enabled`                            | Deploy the webhook server pod                                                                                              | false                                                                | | ||||
| | `githubWebhookServer.secret.enabled`                      | Passes the webhook hook secret to the github-webhook-server                                                                             | false                                                                | | ||||
| | `githubWebhookServer.secret.create`                      | Deploy the webhook hook secret                                                                                             | false                                                                | | ||||
| | `githubWebhookServer.secret.name`                        | Set the name of the webhook hook secret                                                                                    | github-webhook-server                                                | | ||||
| | `githubWebhookServer.secret.github_webhook_secret_token` | Set the webhook secret token value                                                                                         |                                                                      | | ||||
| | `githubWebhookServer.imagePullSecrets`                   | Specifies the secret to be used when pulling the githubWebhookServer pod containers                                        |                                                                      | | ||||
| | `githubWebhookServer.nameOverride`                        | Override the resource name prefix	                                                                                        |                                                                      | | ||||
| | `githubWebhookServer.fullnameOverride`                    | Override the full resource names	                                                                                        |                                                                      | | ||||
| | `githubWebhookServer.serviceAccount.create`              | Deploy the githubWebhookServer under a service account                                                                     | true                                                                 | | ||||
| | `githubWebhookServer.serviceAccount.annotations`         | Set annotations for the service account                                                                                    |                                                                      | | ||||
| | `githubWebhookServer.serviceAccount.name`                | Set the service account name                                                                                               |                                                                      | | ||||
| | `githubWebhookServer.podAnnotations`                     | Set annotations for the githubWebhookServer pod                                                                            |                                                                      | | ||||
| | `githubWebhookServer.podLabels`                          | Set labels for the githubWebhookServer pod                                                                                 |                                                                      | | ||||
| | `githubWebhookServer.podSecurityContext`                 | Set the security context to githubWebhookServer pod                                                                        |                                                                      | | ||||
| | `githubWebhookServer.securityContext`                    | Set the security context for each container in the githubWebhookServer pod                                                 |                                                                      | | ||||
| | `githubWebhookServer.resources`                          | Set the githubWebhookServer pod resources                                                                                  |                                                                      | | ||||
| | `githubWebhookServer.topologySpreadConstraints`          | Set the githubWebhookServer pod topologySpreadConstraints                                                                  |                                                                      | | ||||
| | `githubWebhookServer.nodeSelector`                       | Set the githubWebhookServer pod nodeSelector                                                                               |                                                                      | | ||||
| | `githubWebhookServer.tolerations`                        | Set the githubWebhookServer pod tolerations                                                                                |                                                                      | | ||||
| | `githubWebhookServer.affinity`                           | Set the githubWebhookServer pod affinity rules                                                                             |                                                                      | | ||||
| | `githubWebhookServer.priorityClassName`                  | Set the githubWebhookServer pod priorityClassName                                                                          |                                                                      | | ||||
| | `githubWebhookServer.service.type`                       | Set githubWebhookServer service type                                                                                       |                                                                      | | ||||
| | `githubWebhookServer.service.ports`                      | Set githubWebhookServer service ports                                                                                      | `[{"port":80, "targetPort:"http", "protocol":"TCP", "name":"http"}]` | | ||||
| | `githubWebhookServer.ingress.enabled`                    | Deploy an ingress kind for the githubWebhookServer                                                                         | false                                                                | | ||||
| | `githubWebhookServer.ingress.annotations`                | Set annotations for the ingress kind                                                                                       |                                                                      | | ||||
| | `githubWebhookServer.ingress.hosts`                      | Set hosts configuration for ingress                                                                                        | `[{"host": "chart-example.local", "paths": []}]`                     | | ||||
| | `githubWebhookServer.ingress.tls`                        | Set tls configuration for ingress                                                                                          |                                                                      | | ||||
| | `githubWebhookServer.ingress.ingressClassName`           | Set ingress class name                                                                                                     |                                                                      | | ||||
| | `githubWebhookServer.podDisruptionBudget.enabled`        | Enables a PDB to ensure HA of githubwebhook pods                                                                           |      false                                                           | | ||||
| | `githubWebhookServer.podDisruptionBudget.minAvailable`   | Minimum number of pods that must be available after eviction                                                               |                                                                      | | ||||
| | `githubWebhookServer.podDisruptionBudget.maxUnavailable` | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required.                                   |                                                                      | | ||||
| | Key                                                       | Description                                                                                                                               | Default                                                                                         | | ||||
| |-----------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------| | ||||
| | `labels`                                                  | Set labels to apply to all resources in the chart                                                                                         |                                                                                                 | | ||||
| | `replicaCount`                                            | Set the number of controller pods                                                                                                         | 1                                                                                               | | ||||
| | `webhookPort`                                             | Set the containerPort for the webhook Pod                                                                                                 | 9443                                                                                            | | ||||
| | `syncPeriod`                                              | Set the period in which the controller reconciles the desired runners count                                                               | 1m                                                                                              | | ||||
| | `enableLeaderElection`                                    | Enable election configuration                                                                                                             | true                                                                                            | | ||||
| | `leaderElectionId`                                        | Set the election ID for the controller group                                                                                              |                                                                                                 | | ||||
| | `githubEnterpriseServerURL`                               | Set the URL for a self-hosted GitHub Enterprise Server                                                                                    |                                                                                                 | | ||||
| | `githubURL`                                               | Override GitHub URL to be used for GitHub API calls                                                                                       |                                                                                                 | | ||||
| | `githubUploadURL`                                         | Override GitHub Upload URL to be used for GitHub API calls                                                                                |                                                                                                 | | ||||
| | `runnerGithubURL`                                         | Override GitHub URL to be used by runners during registration                                                                             |                                                                                                 | | ||||
| | `logLevel`                                                | Set the log level of the controller container                                                                                             |                                                                                                 | | ||||
| | `logFormat`                                               | Set the log format of the controller. Valid options are "text" and "json"                                                                 | text                                                                                            | | ||||
| | `additionalVolumes`                                       | Set additional volumes to add to the manager container                                                                                    |                                                                                                 | | ||||
| | `additionalVolumeMounts`                                  | Set additional volume mounts to add to the manager container                                                                              |                                                                                                 | | ||||
| | `authSecret.create`                                       | Deploy the controller auth secret                                                                                                         | false                                                                                           | | ||||
| | `authSecret.name`                                         | Set the name of the auth secret                                                                                                           | controller-manager                                                                              | | ||||
| | `authSecret.annotations`                                  | Set annotations for the auth Secret                                                                                                       |                                                                                                 | | ||||
| | `authSecret.github_app_id`                                | The ID of your GitHub App. **This can't be set at the same time as `authSecret.github_token`**                                            |                                                                                                 | | ||||
| | `authSecret.github_app_installation_id`                   | The ID of your GitHub App installation. **This can't be set at the same time as `authSecret.github_token`**                               |                                                                                                 | | ||||
| | `authSecret.github_app_private_key`                       | The multiline string of your GitHub App's private key. **This can't be set at the same time as `authSecret.github_token`**                |                                                                                                 | | ||||
| | `authSecret.github_token`                                 | Your chosen GitHub PAT token. **This can't be set at the same time as the `authSecret.github_app_*`**                                     |                                                                                                 | | ||||
| | `authSecret.github_basicauth_username`                    | Username for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API                                |                                                                                                 | | ||||
| | `authSecret.github_basicauth_password`                    | Password for GitHub basic auth to use instead of PAT or GitHub APP in case it's running behind a proxy API                                |                                                                                                 | | ||||
| | `dockerRegistryMirror`                                    | The default Docker Registry Mirror used by runners.                                                                                       |                                                                                                 | | ||||
| | `hostNetwork`                                             | The "hostNetwork" of the controller container                                                                                             | false                                                                                           | | ||||
| | `dnsPolicy`                                               | The "dnsPolicy" of the controller container                                                                                               | ClusterFirst                                                                                    | | ||||
| | `image.repository`                                        | The "repository/image" of the controller container                                                                                        | summerwind/actions-runner-controller                                                            | | ||||
| | `image.tag`                                               | The tag of the controller container                                                                                                       |                                                                                                 | | ||||
| | `image.actionsRunnerRepositoryAndTag`                     | The "repository/image" of the actions runner container                                                                                    | summerwind/actions-runner:latest                                                                | | ||||
| | `image.actionsRunnerImagePullSecrets`                     | Optional image pull secrets to be included in the runner pod's ImagePullSecrets                                                           |                                                                                                 | | ||||
| | `image.dindSidecarRepositoryAndTag`                       | The "repository/image" of the dind sidecar container                                                                                      | docker:dind                                                                                     | | ||||
| | `image.pullPolicy`                                        | The pull policy of the controller image                                                                                                   | IfNotPresent                                                                                    | | ||||
| | `metrics.serviceMonitor.enable`                           | Deploy serviceMonitor kind for for use with prometheus-operator CRDs                                                                      | false                                                                                           | | ||||
| | `metrics.serviceMonitor.interval`                         | Configure the interval that Prometheus should scrap the controller's metrics                                                              | 1m                                                                                              | | ||||
| | `metrics.serviceMonitor.namespace`                        | Namespace which Prometheus is running in                                                                                                  | `Release.Namespace` (the default namespace of the helm chart).                                  | | ||||
| | `metrics.serviceMonitor.timeout`                          | Configure the timeout the timeout of Prometheus scrapping.                                                                                | 30s                                                                                             | | ||||
| | `metrics.serviceAnnotations`                              | Set annotations for the provisioned metrics service resource                                                                              |                                                                                                 | | ||||
| | `metrics.port`                                            | Set port of metrics service                                                                                                               | 8443                                                                                            | | ||||
| | `metrics.proxy.enabled`                                   | Deploy kube-rbac-proxy container in controller pod                                                                                        | true                                                                                            | | ||||
| | `metrics.proxy.image.repository`                          | The "repository/image" of the kube-proxy container                                                                                        | quay.io/brancz/kube-rbac-proxy                                                                  | | ||||
| | `metrics.proxy.image.tag`                                 | The tag of the kube-proxy image to use when pulling the container                                                                         | v0.13.1                                                                                         | | ||||
| | `metrics.serviceMonitorLabels`                            | Set labels to apply to ServiceMonitor resources                                                                                           |                                                                                                 | | ||||
| | `imagePullSecrets`                                        | Specifies the secret to be used when pulling the controller pod containers                                                                |                                                                                                 | | ||||
| | `fullnameOverride`                                        | Override the full resource names	                                                                                                        |                                                                                                 | | ||||
| | `nameOverride`                                            | Override the resource name prefix	                                                                                                        |                                                                                                 | | ||||
| | `serviceAccount.annotations`                              | Set annotations to the service account                                                                                                    |                                                                                                 | | ||||
| | `serviceAccount.create`                                   | Deploy the controller pod under a service account                                                                                         | true                                                                                            | | ||||
| | `podAnnotations`                                          | Set annotations for the controller pod                                                                                                    |                                                                                                 | | ||||
| | `podLabels`                                               | Set labels for the controller pod                                                                                                         |                                                                                                 | | ||||
| | `serviceAccount.name`                                     | Set the name of the service account                                                                                                       |                                                                                                 | | ||||
| | `securityContext`                                         | Set the security context for each container in the controller pod                                                                         |                                                                                                 | | ||||
| | `podSecurityContext`                                      | Set the security context to controller pod                                                                                                |                                                                                                 | | ||||
| | `service.annotations`                                     | Set annotations for the provisioned webhook service resource                                                                              |                                                                                                 | | ||||
| | `service.port`                                            | Set controller service ports                                                                                                              |                                                                                                 | | ||||
| | `service.type`                                            | Set controller service type                                                                                                               |                                                                                                 | | ||||
| | `topologySpreadConstraints`                               | Set the controller pod topologySpreadConstraints                                                                                          |                                                                                                 | | ||||
| | `nodeSelector`                                            | Set the controller pod nodeSelector                                                                                                       |                                                                                                 | | ||||
| | `resources`                                               | Set the controller pod resources                                                                                                          |                                                                                                 | | ||||
| | `affinity`                                                | Set the controller pod affinity rules                                                                                                     |                                                                                                 | | ||||
| | `podDisruptionBudget.enabled`                             | Enables a PDB to ensure HA of controller pods                                                                                             | false                                                                                      | | ||||
| | `podDisruptionBudget.minAvailable`                        | Minimum number of pods that must be available after eviction                                                                              |                                                                                                 | | ||||
| | `podDisruptionBudget.maxUnavailable`                      | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required.                                                  |                                                                                                 | | ||||
| | `tolerations`                                             | Set the controller pod tolerations                                                                                                        |                                                                                                 | | ||||
| | `env`                                                     | Set environment variables for the controller container                                                                                    |                                                                                                 | | ||||
| | `priorityClassName`                                       | Set the controller pod priorityClassName                                                                                                  |                                                                                                 | | ||||
| | `scope.watchNamespace`                                    | Tells the controller and the github webhook server which namespace to watch if `scope.singleNamespace` is true                            | `Release.Namespace` (the default namespace of the helm chart).                                  | | ||||
| | `scope.singleNamespace`                                   | Limit the controller to watch a single namespace                                                                                          | false                                                                                           | | ||||
| | `certManagerEnabled`                                      | Enable cert-manager. If disabled you must set admissionWebHooks.caBundle and create TLS secrets manually                                  | true                                                                                            | | ||||
| | `runner.statusUpdateHook.enabled`                         | Use custom RBAC for runners (role, role binding and service account), this will enable reporting runner statuses                          | false                                                                                           | | ||||
| | `admissionWebHooks.caBundle`                              | Base64-encoded PEM bundle containing the CA that signed the webhook's serving certificate                                                 |                                                                                                 | | ||||
| | `githubWebhookServer.logLevel`                            | Set the log level of the githubWebhookServer container                                                                                    |                                                                                                 | | ||||
| | `githubWebhookServer.logFormat`                           | Set the log format of the githubWebhookServer controller. Valid options are "text" and "json"                                             | text                                                                                            | | ||||
| | `githubWebhookServer.replicaCount`                        | Set the number of webhook server pods                                                                                                     | 1                                                                                               | | ||||
| | `githubWebhookServer.useRunnerGroupsVisibility`           | Enable supporting runner groups with custom visibility, you also need to set `githubWebhookServer.secret.enabled` to enable this feature. | false                                                                                           | | ||||
| | `githubWebhookServer.enabled`                             | Deploy the webhook server pod                                                                                                             | false                                                                                           | | ||||
| | `githubWebhookServer.queueLimit`                          | Set the queue size limit in the githubWebhookServer                                                                                       |                                                                                                 | | ||||
| | `githubWebhookServer.secret.enabled`                      | Passes the webhook hook secret to the github-webhook-server                                                                               | false                                                                                           | | ||||
| | `githubWebhookServer.secret.create`                       | Deploy the webhook hook secret                                                                                                            | false                                                                                           | | ||||
| | `githubWebhookServer.secret.name`                         | Set the name of the webhook hook secret                                                                                                   | github-webhook-server                                                                           | | ||||
| | `githubWebhookServer.secret.github_webhook_secret_token`  | Set the webhook secret token value                                                                                                        |                                                                                                 | | ||||
| | `githubWebhookServer.imagePullSecrets`                    | Specifies the secret to be used when pulling the githubWebhookServer pod containers                                                       |                                                                                                 | | ||||
| | `githubWebhookServer.nameOverride`                        | Override the resource name prefix	                                                                                                        |                                                                                                 | | ||||
| | `githubWebhookServer.fullnameOverride`                    | Override the full resource names	                                                                                                        |                                                                                                 | | ||||
| | `githubWebhookServer.serviceAccount.create`               | Deploy the githubWebhookServer under a service account                                                                                    | true                                                                                            | | ||||
| | `githubWebhookServer.serviceAccount.annotations`          | Set annotations for the service account                                                                                                   |                                                                                                 | | ||||
| | `githubWebhookServer.serviceAccount.name`                 | Set the service account name                                                                                                              |                                                                                                 | | ||||
| | `githubWebhookServer.podAnnotations`                      | Set annotations for the githubWebhookServer pod                                                                                           |                                                                                                 | | ||||
| | `githubWebhookServer.podLabels`                           | Set labels for the githubWebhookServer pod                                                                                                |                                                                                                 | | ||||
| | `githubWebhookServer.podSecurityContext`                  | Set the security context to githubWebhookServer pod                                                                                       |                                                                                                 | | ||||
| | `githubWebhookServer.securityContext`                     | Set the security context for each container in the githubWebhookServer pod                                                                |                                                                                                 | | ||||
| | `githubWebhookServer.resources`                           | Set the githubWebhookServer pod resources                                                                                                 |                                                                                                 | | ||||
| | `githubWebhookServer.topologySpreadConstraints`           | Set the githubWebhookServer pod topologySpreadConstraints                                                                                 |                                                                                                 | | ||||
| | `githubWebhookServer.nodeSelector`                        | Set the githubWebhookServer pod nodeSelector                                                                                              |                                                                                                 | | ||||
| | `githubWebhookServer.tolerations`                         | Set the githubWebhookServer pod tolerations                                                                                               |                                                                                                 | | ||||
| | `githubWebhookServer.affinity`                            | Set the githubWebhookServer pod affinity rules                                                                                            |                                                                                                 | | ||||
| | `githubWebhookServer.priorityClassName`                   | Set the githubWebhookServer pod priorityClassName                                                                                         |                                                                                                 | | ||||
| | `githubWebhookServer.terminationGracePeriodSeconds`       | Set the githubWebhookServer pod terminationGracePeriodSeconds. Useful when using preStop hooks to drain/sleep.                            | `10`                                                                                            | | ||||
| | `githubWebhookServer.lifecycle`                           | Set the githubWebhookServer pod lifecycle hooks                                                                                           | `{}`                                                                                            | | ||||
| | `githubWebhookServer.service.type`                        | Set githubWebhookServer service type                                                                                                      |                                                                                                 | | ||||
| | `githubWebhookServer.service.ports`                       | Set githubWebhookServer service ports                                                                                                     | `[{"port":80, "targetPort:"http", "protocol":"TCP", "name":"http"}]`                            | | ||||
| | `githubWebhookServer.service.loadBalancerSourceRanges`    | Set githubWebhookServer loadBalancerSourceRanges for restricting loadBalancer type services                                               | `[]`                                                                                            | | ||||
| | `githubWebhookServer.ingress.enabled`                     | Deploy an ingress kind for the githubWebhookServer                                                                                        | false                                                                                           | | ||||
| | `githubWebhookServer.ingress.annotations`                 | Set annotations for the ingress kind                                                                                                      |                                                                                                 | | ||||
| | `githubWebhookServer.ingress.hosts`                       | Set hosts configuration for ingress                                                                                                       | `[{"host": "chart-example.local", "paths": []}]`                                                | | ||||
| | `githubWebhookServer.ingress.tls`                         | Set tls configuration for ingress                                                                                                         |                                                                                                 | | ||||
| | `githubWebhookServer.ingress.ingressClassName`            | Set ingress class name                                                                                                                    |                                                                                                 | | ||||
| | `githubWebhookServer.podDisruptionBudget.enabled`         | Enables a PDB to ensure HA of githubwebhook pods                                                                                          | false                                                                                           | | ||||
| | `githubWebhookServer.podDisruptionBudget.minAvailable`    | Minimum number of pods that must be available after eviction                                                                              |                                                                                                 | | ||||
| | `githubWebhookServer.podDisruptionBudget.maxUnavailable`  | Maximum number of pods that can be unavailable after eviction. Kubernetes 1.7+ required.                                                  |                                                                                                 | | ||||
| | `actionsMetricsServer.logLevel`                           | Set the log level of the actionsMetricsServer container                                                                                   |                                                                                                 | | ||||
| | `actionsMetricsServer.logFormat`                          | Set the log format of the actionsMetricsServer controller. Valid options are "text" and "json"                                            | text                                                                                            | | ||||
| | `actionsMetricsServer.enabled`                            | Deploy the actions metrics server pod                                                                                                     | false                                                                                           | | ||||
| | `actionsMetricsServer.secret.enabled`                     | Passes the webhook hook secret to the actions-metrics-server                                                                              | false                                                                                           | | ||||
| | `actionsMetricsServer.secret.create`                      | Deploy the webhook hook secret                                                                                                            | false                                                                                           | | ||||
| | `actionsMetricsServer.secret.name`                        | Set the name of the webhook hook secret                                                                                                   | actions-metrics-server                                                                          | | ||||
| | `actionsMetricsServer.secret.github_webhook_secret_token` | Set the webhook secret token value                                                                                                        |                                                                                                 | | ||||
| | `actionsMetricsServer.imagePullSecrets`                   | Specifies the secret to be used when pulling the actionsMetricsServer pod containers                                                      |                                                                                                 | | ||||
| | `actionsMetricsServer.nameOverride`                       | Override the resource name prefix	                                                                                                        |                                                                                                 | | ||||
| | `actionsMetricsServer.fullnameOverride`                   | Override the full resource names	                                                                                                        |                                                                                                 | | ||||
| | `actionsMetricsServer.serviceAccount.create`              | Deploy the actionsMetricsServer under a service account                                                                                   | true                                                                                            | | ||||
| | `actionsMetricsServer.serviceAccount.annotations`         | Set annotations for the service account                                                                                                   |                                                                                                 | | ||||
| | `actionsMetricsServer.serviceAccount.name`                | Set the service account name                                                                                                              |                                                                                                 | | ||||
| | `actionsMetricsServer.podAnnotations`                     | Set annotations for the actionsMetricsServer pod                                                                                          |                                                                                                 | | ||||
| | `actionsMetricsServer.podLabels`                          | Set labels for the actionsMetricsServer pod                                                                                               |                                                                                                 | | ||||
| | `actionsMetricsServer.podSecurityContext`                 | Set the security context to actionsMetricsServer pod                                                                                      |                                                                                                 | | ||||
| | `actionsMetricsServer.securityContext`                    | Set the security context for each container in the actionsMetricsServer pod                                                               |                                                                                                 | | ||||
| | `actionsMetricsServer.resources`                          | Set the actionsMetricsServer pod resources                                                                                                |                                                                                                 | | ||||
| | `actionsMetricsServer.topologySpreadConstraints`          | Set the actionsMetricsServer pod topologySpreadConstraints                                                                                |                                                                                                 | | ||||
| | `actionsMetricsServer.nodeSelector`                       | Set the actionsMetricsServer pod nodeSelector                                                                                             |                                                                                                 | | ||||
| | `actionsMetricsServer.tolerations`                        | Set the actionsMetricsServer pod tolerations                                                                                              |                                                                                                 | | ||||
| | `actionsMetricsServer.affinity`                           | Set the actionsMetricsServer pod affinity rules                                                                                           |                                                                                                 | | ||||
| | `actionsMetricsServer.priorityClassName`                  | Set the actionsMetricsServer pod priorityClassName                                                                                        |                                                                                                 | | ||||
| | `actionsMetricsServer.terminationGracePeriodSeconds`      | Set the actionsMetricsServer pod terminationGracePeriodSeconds. Useful when using preStop hooks to drain/sleep.                           | `10`                                                                                            | | ||||
| | `actionsMetricsServer.lifecycle`                          | Set the actionsMetricsServer pod lifecycle hooks                                                                                          | `{}`                                                                                            | | ||||
| | `actionsMetricsServer.service.type`                       | Set actionsMetricsServer service type                                                                                                     |                                                                                                 | | ||||
| | `actionsMetricsServer.service.ports`                      | Set actionsMetricsServer service ports                                                                                                    | `[{"port":80, "targetPort:"http", "protocol":"TCP", "name":"http"}]`                            | | ||||
| | `actionsMetricsServer.service.loadBalancerSourceRanges`   | Set actionsMetricsServer loadBalancerSourceRanges for restricting loadBalancer type services                                              | `[]`                                                                                            | | ||||
| | `actionsMetricsServer.ingress.enabled`                    | Deploy an ingress kind for the actionsMetricsServer                                                                                       | false                                                                                           | | ||||
| | `actionsMetricsServer.ingress.annotations`                | Set annotations for the ingress kind                                                                                                      |                                                                                                 | | ||||
| | `actionsMetricsServer.ingress.hosts`                      | Set hosts configuration for ingress                                                                                                       | `[{"host": "chart-example.local", "paths": []}]`                                                | | ||||
| | `actionsMetricsServer.ingress.tls`                        | Set tls configuration for ingress                                                                                                         |                                                                                                 | | ||||
| | `actionsMetricsServer.ingress.ingressClassName`           | Set ingress class name                                                                                                                    |                                                                                                 | | ||||
| | `actionsMetrics.serviceMonitor.enable`                    | Deploy serviceMonitor kind for for use with prometheus-operator CRDs                                                                      | false                                                                                           | | ||||
| | `actionsMetrics.serviceMonitor.interval`                  | Configure the interval that Prometheus should scrap the controller's metrics                                                              | 1m                                                                                              | | ||||
| | `actionsMetrics.serviceMonitor.namespace`                 | Namespace which Prometheus is running in.                                                                                                 | `Release.Namespace` (the default namespace of the helm chart).                                  | | ||||
| | `actionsMetrics.serviceMonitor.timeout`                   | Configure the timeout the timeout of Prometheus scrapping.                                                                                | 30s                                                                                             | | ||||
| | `actionsMetrics.serviceAnnotations`                       | Set annotations for the provisioned actions metrics service resource                                                                      |                                                                                                 | | ||||
| | `actionsMetrics.port`                                     | Set port of actions metrics service                                                                                                       | 8443                                                                                            | | ||||
| | `actionsMetrics.proxy.enabled`                            | Deploy kube-rbac-proxy container in controller pod                                                                                        | true                                                                                            | | ||||
| | `actionsMetrics.proxy.image.repository`                   | The "repository/image" of the kube-proxy container                                                                                        | quay.io/brancz/kube-rbac-proxy                                                                  | | ||||
| | `actionsMetrics.proxy.image.tag`                          | The tag of the kube-proxy image to use when pulling the container                                                                         | v0.13.1                                                                                         | | ||||
| | `actionsMetrics.serviceMonitorLabels`                     | Set labels to apply to ServiceMonitor resources                                                                                           |                                                                                                 | | ||||
|  |  | |||
|  | @ -1,9 +1,9 @@ | |||
| --- | ||||
| apiVersion: apiextensions.k8s.io/v1 | ||||
| kind: CustomResourceDefinition | ||||
| metadata: | ||||
|   annotations: | ||||
|     controller-gen.kubebuilder.io/version: v0.7.0 | ||||
|   creationTimestamp: null | ||||
|     controller-gen.kubebuilder.io/version: v0.19.0 | ||||
|   name: horizontalrunnerautoscalers.actions.summerwind.dev | ||||
| spec: | ||||
|   group: actions.summerwind.dev | ||||
|  | @ -12,238 +12,313 @@ spec: | |||
|     listKind: HorizontalRunnerAutoscalerList | ||||
|     plural: horizontalrunnerautoscalers | ||||
|     shortNames: | ||||
|       - hra | ||||
|     - hra | ||||
|     singular: horizontalrunnerautoscaler | ||||
|   scope: Namespaced | ||||
|   versions: | ||||
|     - additionalPrinterColumns: | ||||
|         - jsonPath: .spec.minReplicas | ||||
|           name: Min | ||||
|           type: number | ||||
|         - jsonPath: .spec.maxReplicas | ||||
|           name: Max | ||||
|           type: number | ||||
|         - jsonPath: .status.desiredReplicas | ||||
|           name: Desired | ||||
|           type: number | ||||
|         - jsonPath: .status.scheduledOverridesSummary | ||||
|           name: Schedule | ||||
|           type: string | ||||
|       name: v1alpha1 | ||||
|       schema: | ||||
|         openAPIV3Schema: | ||||
|           description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler API | ||||
|           properties: | ||||
|             apiVersion: | ||||
|               description: 'APIVersion defines the versioned schema of this representation of an object. Servers should convert recognized schemas to the latest internal value, and may reject unrecognized values. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources' | ||||
|               type: string | ||||
|             kind: | ||||
|               description: 'Kind is a string value representing the REST resource this object represents. Servers may infer this from the endpoint the client submits requests to. Cannot be updated. In CamelCase. More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds' | ||||
|               type: string | ||||
|             metadata: | ||||
|               type: object | ||||
|             spec: | ||||
|               description: HorizontalRunnerAutoscalerSpec defines the desired state of HorizontalRunnerAutoscaler | ||||
|               properties: | ||||
|                 capacityReservations: | ||||
|                   items: | ||||
|                     description: CapacityReservation specifies the number of replicas temporarily added to the scale target until ExpirationTime. | ||||
|                     properties: | ||||
|                       effectiveTime: | ||||
|                         format: date-time | ||||
|                         type: string | ||||
|                       expirationTime: | ||||
|                         format: date-time | ||||
|                         type: string | ||||
|                       name: | ||||
|                         type: string | ||||
|                       replicas: | ||||
|                         type: integer | ||||
|                     type: object | ||||
|                   type: array | ||||
|                 maxReplicas: | ||||
|                   description: MaxReplicas is the maximum number of replicas the deployment is allowed to scale | ||||
|                   type: integer | ||||
|                 metrics: | ||||
|                   description: Metrics is the collection of various metric targets to calculate desired number of runners | ||||
|                   items: | ||||
|                     properties: | ||||
|                       repositoryNames: | ||||
|                         description: RepositoryNames is the list of repository names to be used for calculating the metric. For example, a repository name is the REPO part of `github.com/USER/REPO`. | ||||
|                         items: | ||||
|                           type: string | ||||
|                         type: array | ||||
|                       scaleDownAdjustment: | ||||
|                         description: ScaleDownAdjustment is the number of runners removed on scale-down. You can only specify either ScaleDownFactor or ScaleDownAdjustment. | ||||
|                         type: integer | ||||
|                       scaleDownFactor: | ||||
|                         description: ScaleDownFactor is the multiplicative factor applied to the current number of runners used to determine how many pods should be removed. | ||||
|                         type: string | ||||
|                       scaleDownThreshold: | ||||
|                         description: ScaleDownThreshold is the percentage of busy runners less than which will trigger the hpa to scale the runners down. | ||||
|                         type: string | ||||
|                       scaleUpAdjustment: | ||||
|                         description: ScaleUpAdjustment is the number of runners added on scale-up. You can only specify either ScaleUpFactor or ScaleUpAdjustment. | ||||
|                         type: integer | ||||
|                       scaleUpFactor: | ||||
|                         description: ScaleUpFactor is the multiplicative factor applied to the current number of runners used to determine how many pods should be added. | ||||
|                         type: string | ||||
|                       scaleUpThreshold: | ||||
|                         description: ScaleUpThreshold is the percentage of busy runners greater than which will trigger the hpa to scale runners up. | ||||
|                         type: string | ||||
|                       type: | ||||
|                         description: Type is the type of metric to be used for autoscaling. The only supported Type is TotalNumberOfQueuedAndInProgressWorkflowRuns | ||||
|                         type: string | ||||
|                     type: object | ||||
|                   type: array | ||||
|                 minReplicas: | ||||
|                   description: MinReplicas is the minimum number of replicas the deployment is allowed to scale | ||||
|                   type: integer | ||||
|                 scaleDownDelaySecondsAfterScaleOut: | ||||
|                   description: ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up Used to prevent flapping (down->up->down->... loop) | ||||
|                   type: integer | ||||
|                 scaleTargetRef: | ||||
|                   description: ScaleTargetRef sis the reference to scaled resource like RunnerDeployment | ||||
|   - additionalPrinterColumns: | ||||
|     - jsonPath: .spec.minReplicas | ||||
|       name: Min | ||||
|       type: number | ||||
|     - jsonPath: .spec.maxReplicas | ||||
|       name: Max | ||||
|       type: number | ||||
|     - jsonPath: .status.desiredReplicas | ||||
|       name: Desired | ||||
|       type: number | ||||
|     - jsonPath: .status.scheduledOverridesSummary | ||||
|       name: Schedule | ||||
|       type: string | ||||
|     name: v1alpha1 | ||||
|     schema: | ||||
|       openAPIV3Schema: | ||||
|         description: HorizontalRunnerAutoscaler is the Schema for the horizontalrunnerautoscaler | ||||
|           API | ||||
|         properties: | ||||
|           apiVersion: | ||||
|             description: |- | ||||
|               APIVersion defines the versioned schema of this representation of an object. | ||||
|               Servers should convert recognized schemas to the latest internal value, and | ||||
|               may reject unrecognized values. | ||||
|               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources | ||||
|             type: string | ||||
|           kind: | ||||
|             description: |- | ||||
|               Kind is a string value representing the REST resource this object represents. | ||||
|               Servers may infer this from the endpoint the client submits requests to. | ||||
|               Cannot be updated. | ||||
|               In CamelCase. | ||||
|               More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds | ||||
|             type: string | ||||
|           metadata: | ||||
|             type: object | ||||
|           spec: | ||||
|             description: HorizontalRunnerAutoscalerSpec defines the desired state | ||||
|               of HorizontalRunnerAutoscaler | ||||
|             properties: | ||||
|               capacityReservations: | ||||
|                 items: | ||||
|                   description: |- | ||||
|                     CapacityReservation specifies the number of replicas temporarily added | ||||
|                     to the scale target until ExpirationTime. | ||||
|                   properties: | ||||
|                     kind: | ||||
|                       description: Kind is the type of resource being referenced | ||||
|                       enum: | ||||
|                         - RunnerDeployment | ||||
|                         - RunnerSet | ||||
|                     effectiveTime: | ||||
|                       format: date-time | ||||
|                       type: string | ||||
|                     expirationTime: | ||||
|                       format: date-time | ||||
|                       type: string | ||||
|                     name: | ||||
|                       description: Name is the name of resource being referenced | ||||
|                       type: string | ||||
|                     replicas: | ||||
|                       type: integer | ||||
|                   type: object | ||||
|                 scaleUpTriggers: | ||||
|                   description: "ScaleUpTriggers is an experimental feature to increase the desired replicas by 1 on each webhook requested received by the webhookBasedAutoscaler. \n This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster. \n Note that the added runners remain until the next sync period at least, and they may or may not be used by GitHub Actions depending on the timing. They are intended to be used to gain \"resource slack\" immediately after you receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available." | ||||
|                   items: | ||||
|                 type: array | ||||
|               githubAPICredentialsFrom: | ||||
|                 properties: | ||||
|                   secretRef: | ||||
|                     properties: | ||||
|                       amount: | ||||
|                         type: integer | ||||
|                       duration: | ||||
|                         type: string | ||||
|                       githubEvent: | ||||
|                         properties: | ||||
|                           checkRun: | ||||
|                             description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run | ||||
|                             properties: | ||||
|                               names: | ||||
|                                 description: Names is a list of GitHub Actions glob patterns. Any check_run event whose name matches one of patterns in the list can trigger autoscaling. Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file. So it is very likely that you can utilize this to trigger depending on the job. | ||||
|                                 items: | ||||
|                                   type: string | ||||
|                                 type: array | ||||
|                               repositories: | ||||
|                                 description: Repositories is a list of GitHub repositories. Any check_run event whose repository matches one of repositories in the list can trigger autoscaling. | ||||
|                                 items: | ||||
|                                   type: string | ||||
|                                 type: array | ||||
|                               status: | ||||
|                                 type: string | ||||
|                               types: | ||||
|                                 description: 'One of: created, rerequested, or completed' | ||||
|                                 items: | ||||
|                                   type: string | ||||
|                                 type: array | ||||
|                             type: object | ||||
|                           pullRequest: | ||||
|                             description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request | ||||
|                             properties: | ||||
|                               branches: | ||||
|                                 items: | ||||
|                                   type: string | ||||
|                                 type: array | ||||
|                               types: | ||||
|                                 items: | ||||
|                                   type: string | ||||
|                                 type: array | ||||
|                             type: object | ||||
|                           push: | ||||
|                             description: PushSpec is the condition for triggering scale-up on push event Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push | ||||
|                             type: object | ||||
|                           workflowJob: | ||||
|                             description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job | ||||
|                             type: object | ||||
|                         type: object | ||||
|                     type: object | ||||
|                   type: array | ||||
|                 scheduledOverrides: | ||||
|                   description: ScheduledOverrides is the list of ScheduledOverride. It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule. The earlier a scheduled override is, the higher it is prioritized. | ||||
|                   items: | ||||
|                     description: ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule. A schedule can optionally be recurring, so that the correspoding override happens every day, week, month, or year. | ||||
|                     properties: | ||||
|                       endTime: | ||||
|                         description: EndTime is the time at which the first override ends. | ||||
|                         format: date-time | ||||
|                         type: string | ||||
|                       minReplicas: | ||||
|                         description: MinReplicas is the number of runners while overriding. If omitted, it doesn't override minReplicas. | ||||
|                         minimum: 0 | ||||
|                         nullable: true | ||||
|                         type: integer | ||||
|                       recurrenceRule: | ||||
|                         properties: | ||||
|                           frequency: | ||||
|                             description: Frequency is the name of a predefined interval of each recurrence. The valid values are "Daily", "Weekly", "Monthly", and "Yearly". If empty, the corresponding override happens only once. | ||||
|                             enum: | ||||
|                               - Daily | ||||
|                               - Weekly | ||||
|                               - Monthly | ||||
|                               - Yearly | ||||
|                             type: string | ||||
|                           untilTime: | ||||
|                             description: UntilTime is the time of the final recurrence. If empty, the schedule recurs forever. | ||||
|                             format: date-time | ||||
|                             type: string | ||||
|                         type: object | ||||
|                       startTime: | ||||
|                         description: StartTime is the time at which the first override starts. | ||||
|                         format: date-time | ||||
|                       name: | ||||
|                         type: string | ||||
|                     required: | ||||
|                       - endTime | ||||
|                       - startTime | ||||
|                     - name | ||||
|                     type: object | ||||
|                   type: array | ||||
|               type: object | ||||
|             status: | ||||
|               properties: | ||||
|                 cacheEntries: | ||||
|                   items: | ||||
|                     properties: | ||||
|                       expirationTime: | ||||
|                         format: date-time | ||||
|                 type: object | ||||
|               maxReplicas: | ||||
|                 description: MaxReplicas is the maximum number of replicas the deployment | ||||
|                   is allowed to scale | ||||
|                 type: integer | ||||
|               metrics: | ||||
|                 description: Metrics is the collection of various metric targets to | ||||
|                   calculate desired number of runners | ||||
|                 items: | ||||
|                   properties: | ||||
|                     repositoryNames: | ||||
|                       description: |- | ||||
|                         RepositoryNames is the list of repository names to be used for calculating the metric. | ||||
|                         For example, a repository name is the REPO part of `github.com/USER/REPO`. | ||||
|                       items: | ||||
|                         type: string | ||||
|                       key: | ||||
|                         type: string | ||||
|                       value: | ||||
|                         type: integer | ||||
|                     type: object | ||||
|                   type: array | ||||
|                 desiredReplicas: | ||||
|                   description: DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet This doesn't include outdated pods while upgrading the deployment and replacing the runnerset. | ||||
|                   type: integer | ||||
|                 lastSuccessfulScaleOutTime: | ||||
|                   format: date-time | ||||
|                   nullable: true | ||||
|                   type: string | ||||
|                 observedGeneration: | ||||
|                   description: ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g. RunnerDeployment's generation, which is updated on mutation by the API Server. | ||||
|                   format: int64 | ||||
|                   type: integer | ||||
|                 scheduledOverridesSummary: | ||||
|                   description: ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output for observability. | ||||
|                   type: string | ||||
|               type: object | ||||
|           type: object | ||||
|       served: true | ||||
|       storage: true | ||||
|       subresources: | ||||
|         status: {} | ||||
|   preserveUnknownFields: false | ||||
| status: | ||||
|   acceptedNames: | ||||
|     kind: "" | ||||
|     plural: "" | ||||
|   conditions: [] | ||||
|   storedVersions: [] | ||||
|                       type: array | ||||
|                     scaleDownAdjustment: | ||||
|                       description: |- | ||||
|                         ScaleDownAdjustment is the number of runners removed on scale-down. | ||||
|                         You can only specify either ScaleDownFactor or ScaleDownAdjustment. | ||||
|                       type: integer | ||||
|                     scaleDownFactor: | ||||
|                       description: |- | ||||
|                         ScaleDownFactor is the multiplicative factor applied to the current number of runners used | ||||
|                         to determine how many pods should be removed. | ||||
|                       type: string | ||||
|                     scaleDownThreshold: | ||||
|                       description: |- | ||||
|                         ScaleDownThreshold is the percentage of busy runners less than which will | ||||
|                         trigger the hpa to scale the runners down. | ||||
|                       type: string | ||||
|                     scaleUpAdjustment: | ||||
|                       description: |- | ||||
|                         ScaleUpAdjustment is the number of runners added on scale-up. | ||||
|                         You can only specify either ScaleUpFactor or ScaleUpAdjustment. | ||||
|                       type: integer | ||||
|                     scaleUpFactor: | ||||
|                       description: |- | ||||
|                         ScaleUpFactor is the multiplicative factor applied to the current number of runners used | ||||
|                         to determine how many pods should be added. | ||||
|                       type: string | ||||
|                     scaleUpThreshold: | ||||
|                       description: |- | ||||
|                         ScaleUpThreshold is the percentage of busy runners greater than which will | ||||
|                         trigger the hpa to scale runners up. | ||||
|                       type: string | ||||
|                     type: | ||||
|                       description: |- | ||||
|                         Type is the type of metric to be used for autoscaling. | ||||
|                         It can be TotalNumberOfQueuedAndInProgressWorkflowRuns or PercentageRunnersBusy. | ||||
|                       type: string | ||||
|                   type: object | ||||
|                 type: array | ||||
|               minReplicas: | ||||
|                 description: MinReplicas is the minimum number of replicas the deployment | ||||
|                   is allowed to scale | ||||
|                 type: integer | ||||
|               scaleDownDelaySecondsAfterScaleOut: | ||||
|                 description: |- | ||||
|                   ScaleDownDelaySecondsAfterScaleUp is the approximate delay for a scale down followed by a scale up | ||||
|                   Used to prevent flapping (down->up->down->... loop) | ||||
|                 type: integer | ||||
|               scaleTargetRef: | ||||
|                 description: ScaleTargetRef is the reference to scaled resource like | ||||
|                   RunnerDeployment | ||||
|                 properties: | ||||
|                   kind: | ||||
|                     description: Kind is the type of resource being referenced | ||||
|                     enum: | ||||
|                     - RunnerDeployment | ||||
|                     - RunnerSet | ||||
|                     type: string | ||||
|                   name: | ||||
|                     description: Name is the name of resource being referenced | ||||
|                     type: string | ||||
|                 type: object | ||||
|               scaleUpTriggers: | ||||
|                 description: |- | ||||
|                   ScaleUpTriggers is an experimental feature to increase the desired replicas by 1 | ||||
|                   on each webhook requested received by the webhookBasedAutoscaler. | ||||
| 
 | ||||
|                   This feature requires you to also enable and deploy the webhookBasedAutoscaler onto your cluster. | ||||
| 
 | ||||
|                   Note that the added runners remain until the next sync period at least, | ||||
|                   and they may or may not be used by GitHub Actions depending on the timing. | ||||
|                   They are intended to be used to gain "resource slack" immediately after you | ||||
|                   receive a webhook from GitHub, so that you can loosely expect MinReplicas runners to be always available. | ||||
|                 items: | ||||
|                   properties: | ||||
|                     amount: | ||||
|                       type: integer | ||||
|                     duration: | ||||
|                       type: string | ||||
|                     githubEvent: | ||||
|                       properties: | ||||
|                         checkRun: | ||||
|                           description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#check_run | ||||
|                           properties: | ||||
|                             names: | ||||
|                               description: |- | ||||
|                                 Names is a list of GitHub Actions glob patterns. | ||||
|                                 Any check_run event whose name matches one of patterns in the list can trigger autoscaling. | ||||
|                                 Note that check_run name seem to equal to the job name you've defined in your actions workflow yaml file. | ||||
|                                 So it is very likely that you can utilize this to trigger depending on the job. | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                             repositories: | ||||
|                               description: |- | ||||
|                                 Repositories is a list of GitHub repositories. | ||||
|                                 Any check_run event whose repository matches one of repositories in the list can trigger autoscaling. | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                             status: | ||||
|                               type: string | ||||
|                             types: | ||||
|                               description: 'One of: created, rerequested, or completed' | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                           type: object | ||||
|                         pullRequest: | ||||
|                           description: https://docs.github.com/en/actions/reference/events-that-trigger-workflows#pull_request | ||||
|                           properties: | ||||
|                             branches: | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                             types: | ||||
|                               items: | ||||
|                                 type: string | ||||
|                               type: array | ||||
|                           type: object | ||||
|                         push: | ||||
|                           description: |- | ||||
|                             PushSpec is the condition for triggering scale-up on push event | ||||
|                             Also see https://docs.github.com/en/actions/reference/events-that-trigger-workflows#push | ||||
|                           type: object | ||||
|                         workflowJob: | ||||
|                           description: https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#workflow_job | ||||
|                           type: object | ||||
|                       type: object | ||||
|                   type: object | ||||
|                 type: array | ||||
|               scheduledOverrides: | ||||
|                 description: |- | ||||
|                   ScheduledOverrides is the list of ScheduledOverride. | ||||
|                   It can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule. | ||||
|                   The earlier a scheduled override is, the higher it is prioritized. | ||||
|                 items: | ||||
|                   description: |- | ||||
|                     ScheduledOverride can be used to override a few fields of HorizontalRunnerAutoscalerSpec on schedule. | ||||
|                     A schedule can optionally be recurring, so that the corresponding override happens every day, week, month, or year. | ||||
|                   properties: | ||||
|                     endTime: | ||||
|                       description: EndTime is the time at which the first override | ||||
|                         ends. | ||||
|                       format: date-time | ||||
|                       type: string | ||||
|                     minReplicas: | ||||
|                       description: |- | ||||
|                         MinReplicas is the number of runners while overriding. | ||||
|                         If omitted, it doesn't override minReplicas. | ||||
|                       minimum: 0 | ||||
|                       nullable: true | ||||
|                       type: integer | ||||
|                     recurrenceRule: | ||||
|                       properties: | ||||
|                         frequency: | ||||
|                           description: |- | ||||
|                             Frequency is the name of a predefined interval of each recurrence. | ||||
|                             The valid values are "Daily", "Weekly", "Monthly", and "Yearly". | ||||
|                             If empty, the corresponding override happens only once. | ||||
|                           enum: | ||||
|                           - Daily | ||||
|                           - Weekly | ||||
|                           - Monthly | ||||
|                           - Yearly | ||||
|                           type: string | ||||
|                         untilTime: | ||||
|                           description: |- | ||||
|                             UntilTime is the time of the final recurrence. | ||||
|                             If empty, the schedule recurs forever. | ||||
|                           format: date-time | ||||
|                           type: string | ||||
|                       type: object | ||||
|                     startTime: | ||||
|                       description: StartTime is the time at which the first override | ||||
|                         starts. | ||||
|                       format: date-time | ||||
|                       type: string | ||||
|                   required: | ||||
|                   - endTime | ||||
|                   - startTime | ||||
|                   type: object | ||||
|                 type: array | ||||
|             type: object | ||||
|           status: | ||||
|             properties: | ||||
|               cacheEntries: | ||||
|                 items: | ||||
|                   properties: | ||||
|                     expirationTime: | ||||
|                       format: date-time | ||||
|                       type: string | ||||
|                     key: | ||||
|                       type: string | ||||
|                     value: | ||||
|                       type: integer | ||||
|                   type: object | ||||
|                 type: array | ||||
|               desiredReplicas: | ||||
|                 description: |- | ||||
|                   DesiredReplicas is the total number of desired, non-terminated and latest pods to be set for the primary RunnerSet | ||||
|                   This doesn't include outdated pods while upgrading the deployment and replacing the runnerset. | ||||
|                 type: integer | ||||
|               lastSuccessfulScaleOutTime: | ||||
|                 format: date-time | ||||
|                 nullable: true | ||||
|                 type: string | ||||
|               observedGeneration: | ||||
|                 description: |- | ||||
|                   ObservedGeneration is the most recent generation observed for the target. It corresponds to e.g. | ||||
|                   RunnerDeployment's generation, which is updated on mutation by the API Server. | ||||
|                 format: int64 | ||||
|                 type: integer | ||||
|               scheduledOverridesSummary: | ||||
|                 description: |- | ||||
|                   ScheduledOverridesSummary is the summary of active and upcoming scheduled overrides to be shown in e.g. a column of a `kubectl get hra` output | ||||
|                   for observability. | ||||
|                 type: string | ||||
|             type: object | ||||
|         type: object | ||||
|     served: true | ||||
|     storage: true | ||||
|     subresources: | ||||
|       status: {} | ||||
|  |  | |||
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -24,11 +24,13 @@ Due to the above you can't just do a `helm upgrade` to release the latest versio | |||
| # REMEMBER TO UPDATE THE CHART_VERSION TO RELEVANT CHART VERISON!!!! | ||||
| CHART_VERSION=0.18.0 | ||||
| 
 | ||||
| curl -L https://github.com/actions-runner-controller/actions-runner-controller/releases/download/actions-runner-controller-${CHART_VERSION}/actions-runner-controller-${CHART_VERSION}.tgz | tar zxv --strip 1 actions-runner-controller/crds | ||||
| curl -L https://github.com/actions/actions-runner-controller/releases/download/actions-runner-controller-${CHART_VERSION}/actions-runner-controller-${CHART_VERSION}.tgz | tar zxv --strip 1 actions-runner-controller/crds | ||||
| 
 | ||||
| kubectl replace -f crds/ | ||||
| ``` | ||||
| 
 | ||||
| Note that in case you're going to create prometheus-operator `ServiceMonitor` resources via the chart, you'd need to deploy prometheus-operator-related CRDs as well. | ||||
| 
 | ||||
| 2. Upgrade the Helm release | ||||
| 
 | ||||
| ```shell | ||||
|  |  | |||
|  | @ -6,17 +6,17 @@ | |||
|   {{- end }} | ||||
| {{- end }} | ||||
| {{- else if contains "NodePort" .Values.service.type }} | ||||
|   export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "actions-runner-controller.fullname" . }}) | ||||
|   export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") | ||||
|   export NODE_PORT=$(kubectl get --namespace {{ include "actions-runner-controller.namespace" . }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "actions-runner-controller.fullname" . }}) | ||||
|   export NODE_IP=$(kubectl get nodes --namespace {{ include "actions-runner-controller.namespace" . }} -o jsonpath="{.items[0].status.addresses[0].address}") | ||||
|   echo http://$NODE_IP:$NODE_PORT | ||||
| {{- else if contains "LoadBalancer" .Values.service.type }} | ||||
|      NOTE: It may take a few minutes for the LoadBalancer IP to be available. | ||||
|            You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "actions-runner-controller.fullname" . }}' | ||||
|   export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "actions-runner-controller.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") | ||||
|            You can watch the status of by running 'kubectl get --namespace {{ include "actions-runner-controller.namespace" . }} svc -w {{ include "actions-runner-controller.fullname" . }}' | ||||
|   export SERVICE_IP=$(kubectl get svc --namespace {{ include "actions-runner-controller.namespace" . }} {{ include "actions-runner-controller.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") | ||||
|   echo http://$SERVICE_IP:{{ .Values.service.port }} | ||||
| {{- else if contains "ClusterIP" .Values.service.type }} | ||||
|   export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "actions-runner-controller.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") | ||||
|   export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") | ||||
|   export POD_NAME=$(kubectl get pods --namespace {{ include "actions-runner-controller.namespace" . }} -l "app.kubernetes.io/name={{ include "actions-runner-controller.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") | ||||
|   export CONTAINER_PORT=$(kubectl get pod --namespace {{ include "actions-runner-controller.namespace" . }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") | ||||
|   echo "Visit http://127.0.0.1:8080 to use your application" | ||||
|   kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT | ||||
|   kubectl --namespace {{ include "actions-runner-controller.namespace" . }} port-forward $POD_NAME 8080:$CONTAINER_PORT | ||||
| {{- end }} | ||||
|  |  | |||
|  | @ -0,0 +1,60 @@ | |||
| {{/* | ||||
| Expand the name of the chart. | ||||
| */}} | ||||
| {{- define "actions-runner-controller-actions-metrics-server.name" -}} | ||||
| {{- default .Chart.Name .Values.actionsMetricsServer.nameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-actions-metrics-server.instance" -}} | ||||
| {{- printf "%s-%s" .Release.Name "actions-metrics-server" }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Create a default fully qualified app name. | ||||
| We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). | ||||
| If release name contains chart name it will be used as a full name. | ||||
| */}} | ||||
| {{- define "actions-runner-controller-actions-metrics-server.fullname" -}} | ||||
| {{- if .Values.actionsMetricsServer.fullnameOverride }} | ||||
| {{- .Values.actionsMetricsServer.fullnameOverride | trunc 63 | trimSuffix "-" }} | ||||
| {{- else }} | ||||
| {{- $name := default .Chart.Name .Values.actionsMetricsServer.nameOverride }} | ||||
| {{- $instance := include "actions-runner-controller-actions-metrics-server.instance" . }} | ||||
| {{- if contains $name $instance }} | ||||
| {{- $instance | trunc 63 | trimSuffix "-" }} | ||||
| {{- else }} | ||||
| {{- printf "%s-%s-%s" .Release.Name $name "actions-metrics-server" | trunc 63 | trimSuffix "-" }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Selector labels | ||||
| */}} | ||||
| {{- define "actions-runner-controller-actions-metrics-server.selectorLabels" -}} | ||||
| app.kubernetes.io/name: {{ include "actions-runner-controller-actions-metrics-server.name" . }} | ||||
| app.kubernetes.io/instance: {{ include "actions-runner-controller-actions-metrics-server.instance" . }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Create the name of the service account to use | ||||
| */}} | ||||
| {{- define "actions-runner-controller-actions-metrics-server.serviceAccountName" -}} | ||||
| {{- if .Values.actionsMetricsServer.serviceAccount.create }} | ||||
| {{- default (include "actions-runner-controller-actions-metrics-server.fullname" .) .Values.actionsMetricsServer.serviceAccount.name }} | ||||
| {{- else }} | ||||
| {{- default "default" .Values.actionsMetricsServer.serviceAccount.name }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-actions-metrics-server.secretName" -}} | ||||
| {{- default (include "actions-runner-controller-actions-metrics-server.fullname" .) .Values.actionsMetricsServer.secret.name }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-actions-metrics-server.roleName" -}} | ||||
| {{- include "actions-runner-controller-actions-metrics-server.fullname" . }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{- define "actions-runner-controller-actions-metrics-server.serviceMonitorName" -}} | ||||
| {{- include "actions-runner-controller-actions-metrics-server.fullname" . | trunc 47 }}-service-monitor | ||||
| {{- end }} | ||||
|  | @ -1,3 +1,14 @@ | |||
| {{/* | ||||
| Allow overriding the namespace for the resources. | ||||
| */}} | ||||
| {{- define "actions-runner-controller.namespace" -}} | ||||
| {{- if .Values.namespaceOverride }} | ||||
|   {{- .Values.namespaceOverride }} | ||||
| {{- else }} | ||||
|   {{- .Release.Namespace }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| 
 | ||||
| {{/* | ||||
| Expand the name of the chart. | ||||
| */}} | ||||
|  |  | |||
|  | @ -0,0 +1,172 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled }} | ||||
| apiVersion: apps/v1 | ||||
| kind: Deployment | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.fullname" . }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
| spec: | ||||
|   replicas: {{ .Values.actionsMetricsServer.replicaCount }} | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       {{- include "actions-runner-controller-actions-metrics-server.selectorLabels" . | nindent 6 }} | ||||
|   template: | ||||
|     metadata: | ||||
|       {{- with .Values.actionsMetricsServer.podAnnotations }} | ||||
|       annotations: | ||||
|         kubectl.kubernetes.io/default-container: "actions-metrics-server" | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       labels: | ||||
|         {{- include "actions-runner-controller-actions-metrics-server.selectorLabels" . | nindent 8 }} | ||||
|       {{- with .Values.actionsMetricsServer.podLabels }} | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|     spec: | ||||
|       {{- with .Values.actionsMetricsServer.imagePullSecrets }} | ||||
|       imagePullSecrets: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       serviceAccountName: {{ include "actions-runner-controller-actions-metrics-server.serviceAccountName" . }} | ||||
|       securityContext: | ||||
|         {{- toYaml .Values.actionsMetricsServer.podSecurityContext | nindent 8 }} | ||||
|       {{- with .Values.actionsMetricsServer.priorityClassName }} | ||||
|       priorityClassName: "{{ . }}" | ||||
|       {{- end }} | ||||
|       containers: | ||||
|       - args: | ||||
|         {{- $metricsHost := .Values.actionsMetrics.proxy.enabled | ternary "127.0.0.1" "0.0.0.0" }} | ||||
|         {{- $metricsPort := .Values.actionsMetrics.proxy.enabled | ternary "8080" .Values.actionsMetrics.port }} | ||||
|         - "--metrics-addr={{ $metricsHost }}:{{ $metricsPort }}" | ||||
|         {{- if .Values.actionsMetricsServer.logLevel }} | ||||
|         - "--log-level={{ .Values.actionsMetricsServer.logLevel }}" | ||||
|         {{- end }} | ||||
|         {{- if .Values.runnerGithubURL  }} | ||||
|         - "--runner-github-url={{ .Values.runnerGithubURL }}" | ||||
|         {{- end }} | ||||
|         {{- if .Values.actionsMetricsServer.logFormat  }} | ||||
|         - "--log-format={{ .Values.actionsMetricsServer.logFormat }}" | ||||
|         {{- end }} | ||||
|         command: | ||||
|         - "/actions-metrics-server" | ||||
|         {{- if .Values.actionsMetricsServer.lifecycle }} | ||||
|         {{- with .Values.actionsMetricsServer.lifecycle }} | ||||
|         lifecycle: | ||||
|           {{- toYaml . | nindent 10 }} | ||||
|         {{- end }} | ||||
|         {{- end }} | ||||
|         env: | ||||
|         - name: GITHUB_WEBHOOK_SECRET_TOKEN | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_webhook_secret_token | ||||
|               name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|               optional: true | ||||
|         {{- if .Values.githubEnterpriseServerURL  }} | ||||
|         - name: GITHUB_ENTERPRISE_URL | ||||
|           value: {{ .Values.githubEnterpriseServerURL }} | ||||
|         {{- end }} | ||||
|         {{- if .Values.githubURL  }} | ||||
|         - name: GITHUB_URL | ||||
|           value: {{ .Values.githubURL }} | ||||
|         {{- end }} | ||||
|         {{- if .Values.githubUploadURL  }} | ||||
|         - name: GITHUB_UPLOAD_URL | ||||
|           value: {{ .Values.githubUploadURL }} | ||||
|         {{- end }} | ||||
|         {{- if .Values.actionsMetricsServer.secret.enabled }} | ||||
|         - name: GITHUB_TOKEN | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_token | ||||
|               name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|               optional: true | ||||
|         - name: GITHUB_APP_ID | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_app_id | ||||
|               name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|               optional: true | ||||
|         - name: GITHUB_APP_INSTALLATION_ID | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_app_installation_id | ||||
|               name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|               optional: true | ||||
|         - name: GITHUB_APP_PRIVATE_KEY | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_app_private_key | ||||
|               name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|               optional: true | ||||
|         {{- if .Values.authSecret.github_basicauth_username }} | ||||
|         - name: GITHUB_BASICAUTH_USERNAME | ||||
|           value: {{ .Values.authSecret.github_basicauth_username }} | ||||
|         {{- end }} | ||||
|         - name: GITHUB_BASICAUTH_PASSWORD | ||||
|           valueFrom: | ||||
|             secretKeyRef: | ||||
|               key: github_basicauth_password | ||||
|               name: {{ include "actions-runner-controller.secretName" . }} | ||||
|               optional: true | ||||
|         {{- end }} | ||||
|         {{- if kindIs "slice" .Values.actionsMetricsServer.env }} | ||||
|         {{- toYaml .Values.actionsMetricsServer.env | nindent 8 }} | ||||
|         {{- else }} | ||||
|         {{- range $key, $val := .Values.actionsMetricsServer.env }} | ||||
|         - name: {{ $key }} | ||||
|           value: {{ $val | quote }} | ||||
|         {{- end }} | ||||
|         {{- end }} | ||||
|         image: "{{ .Values.image.repository }}:{{ .Values.image.tag  | default (cat "v" .Chart.AppVersion | replace " " "") }}" | ||||
|         name: actions-metrics-server | ||||
|         imagePullPolicy: {{ .Values.image.pullPolicy }} | ||||
|         ports: | ||||
|         - containerPort: 8000 | ||||
|           name: http | ||||
|           protocol: TCP | ||||
|         {{- if not .Values.actionsMetrics.proxy.enabled }} | ||||
|         - containerPort: {{ .Values.actionsMetrics.port }} | ||||
|           name: metrics-port | ||||
|           protocol: TCP | ||||
|         {{- end }} | ||||
|         resources: | ||||
|           {{- toYaml .Values.actionsMetricsServer.resources | nindent 12 }} | ||||
|         securityContext: | ||||
|           {{- toYaml .Values.actionsMetricsServer.securityContext | nindent 12 }} | ||||
|       {{- if .Values.actionsMetrics.proxy.enabled }} | ||||
|       - args: | ||||
|         - "--secure-listen-address=0.0.0.0:{{ .Values.actionsMetrics.port }}" | ||||
|         - "--upstream=http://127.0.0.1:8080/" | ||||
|         - "--logtostderr=true" | ||||
|         - "--v=10" | ||||
|         image: "{{ .Values.actionsMetrics.proxy.image.repository }}:{{ .Values.actionsMetrics.proxy.image.tag }}" | ||||
|         name: kube-rbac-proxy | ||||
|         imagePullPolicy: {{ .Values.image.pullPolicy }} | ||||
|         ports: | ||||
|         - containerPort: {{ .Values.actionsMetrics.port }} | ||||
|           name: metrics-port | ||||
|         resources: | ||||
|           {{- toYaml .Values.resources | nindent 12 }} | ||||
|         securityContext: | ||||
|           {{- toYaml .Values.securityContext | nindent 12 }} | ||||
|       {{- end }} | ||||
|       terminationGracePeriodSeconds: {{ .Values.actionsMetricsServer.terminationGracePeriodSeconds }} | ||||
|       {{- with .Values.actionsMetricsServer.nodeSelector }} | ||||
|       nodeSelector: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.actionsMetricsServer.affinity }} | ||||
|       affinity: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.actionsMetricsServer.tolerations }} | ||||
|       tolerations: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
|       {{- with .Values.actionsMetricsServer.topologySpreadConstraints }} | ||||
|       topologySpreadConstraints: | ||||
|         {{- toYaml . | nindent 8 }} | ||||
|       {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,47 @@ | |||
| {{- if .Values.actionsMetricsServer.ingress.enabled -}} | ||||
| {{- $fullName := include "actions-runner-controller-actions-metrics-server.fullname" . -}} | ||||
| {{- $svcPort := (index .Values.actionsMetricsServer.service.ports 0).port -}} | ||||
| apiVersion: networking.k8s.io/v1 | ||||
| kind: Ingress | ||||
| metadata: | ||||
|   name: {{ $fullName }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
|   {{- with .Values.actionsMetricsServer.ingress.annotations }} | ||||
|   annotations: | ||||
|     {{- toYaml . | nindent 4 }} | ||||
|   {{- end }} | ||||
| spec: | ||||
|   {{- if .Values.actionsMetricsServer.ingress.tls }} | ||||
|   tls: | ||||
|     {{- range .Values.actionsMetricsServer.ingress.tls }} | ||||
|     - hosts: | ||||
|         {{- range .hosts }} | ||||
|         - {{ . | quote }} | ||||
|         {{- end }} | ||||
|       secretName: {{ .secretName }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
|   {{- with .Values.actionsMetricsServer.ingress.ingressClassName }} | ||||
|   ingressClassName: {{ . }} | ||||
|   {{- end }} | ||||
|   rules: | ||||
|     {{- range .Values.actionsMetricsServer.ingress.hosts }} | ||||
|     - host: {{ .host | quote }} | ||||
|       http: | ||||
|         paths: | ||||
|           {{- if .extraPaths }} | ||||
|           {{- toYaml .extraPaths | nindent 10 }} | ||||
|           {{- end }} | ||||
|           {{- range .paths }} | ||||
|           - path: {{ .path }} | ||||
|             pathType: {{ .pathType }} | ||||
|             backend: | ||||
|               service: | ||||
|                name: {{ $fullName }} | ||||
|                port: | ||||
|                  number: {{ $svcPort }} | ||||
|           {{- end }} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
|  | @ -0,0 +1,90 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled }} | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRole | ||||
| metadata: | ||||
|   creationTimestamp: null | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.roleName" . }} | ||||
| rules: | ||||
| - apiGroups:  | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - horizontalrunnerautoscalers | ||||
|   verbs: | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - horizontalrunnerautoscalers/finalizers | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - horizontalrunnerautoscalers/status | ||||
|   verbs: | ||||
|   - get | ||||
|   - patch | ||||
|   - update | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - runnersets | ||||
|   verbs: | ||||
|   - get | ||||
|   - list | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - runnerdeployments | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - runnerdeployments/finalizers | ||||
|   verbs: | ||||
|   - create | ||||
|   - delete | ||||
|   - get | ||||
|   - list | ||||
|   - patch | ||||
|   - update | ||||
|   - watch | ||||
| - apiGroups: | ||||
|   - actions.summerwind.dev | ||||
|   resources: | ||||
|   - runnerdeployments/status | ||||
|   verbs: | ||||
|   - get | ||||
|   - patch | ||||
|   - update | ||||
| - apiGroups: | ||||
|   - authentication.k8s.io | ||||
|   resources: | ||||
|   - tokenreviews | ||||
|   verbs: | ||||
|   - create | ||||
| - apiGroups: | ||||
|   - authorization.k8s.io | ||||
|   resources: | ||||
|   - subjectaccessreviews | ||||
|   verbs: | ||||
|   - create | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,14 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled }} | ||||
| apiVersion: rbac.authorization.k8s.io/v1 | ||||
| kind: ClusterRoleBinding | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.roleName" . }} | ||||
| roleRef: | ||||
|   apiGroup: rbac.authorization.k8s.io | ||||
|   kind: ClusterRole | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.roleName" . }} | ||||
| subjects: | ||||
|   - kind: ServiceAccount | ||||
|     name: {{ include "actions-runner-controller-actions-metrics-server.serviceAccountName" . }} | ||||
|     namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,28 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled }} | ||||
| {{- if .Values.actionsMetricsServer.secret.create }} | ||||
| apiVersion: v1 | ||||
| kind: Secret | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.secretName" . }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
| type: Opaque | ||||
| data: | ||||
| {{- if .Values.actionsMetricsServer.secret.github_webhook_secret_token }} | ||||
|   github_webhook_secret_token: {{ .Values.actionsMetricsServer.secret.github_webhook_secret_token | toString | b64enc }} | ||||
| {{- end }} | ||||
| {{- if .Values.actionsMetricsServer.secret.github_app_id }} | ||||
|   github_app_id: {{ .Values.actionsMetricsServer.secret.github_app_id | toString | b64enc }} | ||||
| {{- end }} | ||||
| {{- if .Values.actionsMetricsServer.secret.github_app_installation_id }} | ||||
|   github_app_installation_id: {{ .Values.actionsMetricsServer.secret.github_app_installation_id | toString | b64enc }} | ||||
| {{- end }} | ||||
| {{- if .Values.actionsMetricsServer.secret.github_app_private_key }} | ||||
|   github_app_private_key: {{ .Values.actionsMetricsServer.secret.github_app_private_key | toString | b64enc }} | ||||
| {{- end }} | ||||
| {{- if .Values.actionsMetricsServer.secret.github_token }} | ||||
|   github_token: {{ .Values.actionsMetricsServer.secret.github_token | toString | b64enc }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,32 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled }} | ||||
| apiVersion: v1 | ||||
| kind: Service | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.fullname" . }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller-actions-metrics-server.selectorLabels" . | nindent 4 }} | ||||
| {{- if .Values.actionsMetricsServer.service.annotations }} | ||||
|   annotations: | ||||
|     {{ toYaml .Values.actionsMetricsServer.service.annotations | nindent 4 }} | ||||
| {{- end }} | ||||
| spec: | ||||
|   type: {{ .Values.actionsMetricsServer.service.type }} | ||||
|   ports: | ||||
|     {{ range $_, $port := .Values.actionsMetricsServer.service.ports -}} | ||||
|     - {{ $port | toYaml | nindent 6 }} | ||||
|     {{- end }} | ||||
|     {{- if .Values.actionsMetrics.serviceMonitor.enable }} | ||||
|     - name: metrics-port | ||||
|       port: {{ .Values.actionsMetrics.port }} | ||||
|       targetPort: metrics-port | ||||
|     {{- end }} | ||||
|   selector: | ||||
|     {{- include "actions-runner-controller-actions-metrics-server.selectorLabels" . | nindent 4 }} | ||||
|   {{- if .Values.actionsMetricsServer.service.loadBalancerSourceRanges }} | ||||
|   loadBalancerSourceRanges: | ||||
|     {{- range $ip := .Values.actionsMetricsServer.service.loadBalancerSourceRanges }} | ||||
|     - {{ $ip -}} | ||||
|     {{- end }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,15 @@ | |||
| {{- if .Values.actionsMetricsServer.enabled -}} | ||||
| {{- if .Values.actionsMetricsServer.serviceAccount.create -}} | ||||
| apiVersion: v1 | ||||
| kind: ServiceAccount | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.serviceAccountName" . }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
|   {{- with .Values.actionsMetricsServer.serviceAccount.annotations }} | ||||
|   annotations: | ||||
|     {{- toYaml . | nindent 4 }} | ||||
|   {{- end }} | ||||
| {{- end }} | ||||
| {{- end }} | ||||
|  | @ -0,0 +1,28 @@ | |||
| {{- if and .Values.actionsMetricsServer.enabled .Values.actionsMetrics.serviceMonitor.enable }} | ||||
| {{- $servicemonitornamespace := .Values.actionsMetrics.serviceMonitor.namespace | default (include "actions-runner-controller.namespace" .) }} | ||||
| apiVersion: monitoring.coreos.com/v1 | ||||
| kind: ServiceMonitor | ||||
| metadata: | ||||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
|   {{- with .Values.actionsMetrics.serviceMonitorLabels }} | ||||
|     {{- toYaml . | nindent 4 }} | ||||
|   {{- end }} | ||||
|   name: {{ include "actions-runner-controller-actions-metrics-server.serviceMonitorName" . }} | ||||
|   namespace: {{ $servicemonitornamespace }} | ||||
| spec: | ||||
|   endpoints: | ||||
|     - path: /metrics | ||||
|       port: metrics-port | ||||
|       {{- if .Values.actionsMetrics.proxy.enabled }} | ||||
|       bearerTokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token | ||||
|       scheme: https | ||||
|       tlsConfig: | ||||
|         insecureSkipVerify: true | ||||
|       {{- end }} | ||||
|       interval: {{ .Values.actionsMetrics.serviceMonitor.interval }} | ||||
|       scrapeTimeout: {{ .Values.actionsMetrics.serviceMonitor.timeout }} | ||||
|   selector: | ||||
|     matchLabels: | ||||
|       {{- include "actions-runner-controller-actions-metrics-server.selectorLabels" . | nindent 6 }} | ||||
| {{- end }} | ||||
|  | @ -10,5 +10,5 @@ roleRef: | |||
| subjects: | ||||
| - kind: ServiceAccount | ||||
|   name: {{ include "actions-runner-controller.serviceAccountName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
| {{- end }} | ||||
|  |  | |||
|  | @ -6,7 +6,7 @@ apiVersion: cert-manager.io/v1 | |||
| kind: Issuer | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller.selfsignedIssuerName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
| spec: | ||||
|   selfSigned: {} | ||||
| --- | ||||
|  | @ -14,11 +14,11 @@ apiVersion: cert-manager.io/v1 | |||
| kind: Certificate | ||||
| metadata: | ||||
|   name: {{ include "actions-runner-controller.servingCertName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
| spec: | ||||
|   dnsNames: | ||||
|   - {{ include "actions-runner-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc | ||||
|   - {{ include "actions-runner-controller.webhookServiceName" . }}.{{ .Release.Namespace }}.svc.cluster.local | ||||
|   - {{ include "actions-runner-controller.webhookServiceName" . }}.{{ include "actions-runner-controller.namespace" . }}.svc | ||||
|   - {{ include "actions-runner-controller.webhookServiceName" . }}.{{ include "actions-runner-controller.namespace" . }}.svc.cluster.local | ||||
|   issuerRef: | ||||
|     kind: Issuer | ||||
|     name: {{ include "actions-runner-controller.selfsignedIssuerName" . }} | ||||
|  |  | |||
|  | @ -4,7 +4,7 @@ metadata: | |||
|   labels: | ||||
|     {{- include "actions-runner-controller.labels" . | nindent 4 }} | ||||
|   name: {{ include "actions-runner-controller.metricsServiceName" . }} | ||||
|   namespace: {{ .Release.Namespace }} | ||||
|   namespace: {{ include "actions-runner-controller.namespace" . }} | ||||
|   {{- with .Values.metrics.serviceAnnotations }} | ||||
|   annotations: | ||||
|     {{- toYaml . | nindent 4 }} | ||||
|  |  | |||
Some files were not shown because too many files have changed in this diff Show More
		Loading…
	
		Reference in New Issue