API reference
Use the guides for workflows and examples. This reference follows the public import paths used by applications.
Resources and clients
Resource
Bases: BaseResource
Source code in cloudcoil/resources.py
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | |
async_client(config=None, *, namespace=None, cached=None)
async
classmethod
Get a typed client, discovering resources without blocking the loop.
Source code in cloudcoil/resources.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 | |
async_patch(operations, *, subresource=None, dry_run=False)
async
Asynchronously apply a JSON Patch to this resource or its status.
Source code in cloudcoil/resources.py
206 207 208 209 210 211 212 213 214 215 216 217 | |
async_scale(replicas)
async
Asynchronously scale the resource to the specified number of replicas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
replicas
|
int
|
The desired number of replicas |
required |
Returns:
| Type | Description |
|---|---|
Self
|
The updated resource after scaling |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the resource does not support scaling or metadata is not set |
ResourceNotFound
|
If the resource does not exist |
APIError
|
If the API request fails |
Source code in cloudcoil/resources.py
529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | |
client(config=None, *, namespace=None, cached=None)
classmethod
Get this resource's typed client using an explicit or active Config.
The returned client shares Config's transport and lifetime. A namespace override applies only to this client; it does not change Config.
Source code in cloudcoil/resources.py
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
patch(operations, *, subresource=None, dry_run=False)
Apply a JSON Patch; cloudcoil.patches.diff adds UID/version preconditions.
Source code in cloudcoil/resources.py
193 194 195 196 197 198 199 200 201 202 203 204 | |
save(dry_run=False)
Create or replace, preserving optimistic concurrency on existing resources.
Source code in cloudcoil/resources.py
229 230 231 232 233 234 235 236 237 238 239 240 241 242 | |
scale(replicas)
Scale the resource to the specified number of replicas.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
replicas
|
int
|
The desired number of replicas |
required |
Returns:
| Type | Description |
|---|---|
Self
|
The updated resource after scaling |
Raises:
| Type | Description |
|---|---|
ValueError
|
If the resource does not support scaling or metadata is not set |
ResourceNotFound
|
If the resource does not exist |
APIError
|
If the API request fails |
Source code in cloudcoil/resources.py
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 | |
ResourceList
Bases: BaseResource, Generic[T]
Source code in cloudcoil/resources.py
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 | |
Unstructured
Bases: Resource
Source code in cloudcoil/resources.py
769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 | |
raw
property
Return a wire-format snapshot of the current validated model.
get_model(kind, *, api_version='')
Source code in cloudcoil/resources.py
765 766 | |
parse(obj)
parse(obj: list[dict]) -> list[Resource]
parse(obj: dict) -> Resource
Source code in cloudcoil/resources.py
730 731 732 733 734 735 736 737 | |
parse_file(path, load_all=False)
parse_file(
path: str | Path, load_all: Literal[True]
) -> list[Resource]
parse_file(
path: str | Path, load_all: Literal[False] = False
) -> Resource
Source code in cloudcoil/resources.py
748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 | |
Kubernetes clients; Config is loaded lazily to avoid the informer import cycle.
Config
Source code in cloudcoil/client/_config.py
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 | |
async_client_for(resource, cached=None)
async
Get an async client without blocking on discovery or concurrent refresh.
Source code in cloudcoil/client/_config.py
604 605 606 607 608 609 610 611 612 613 | |
async_initialize()
async
Discover resources without blocking the event loop.
Source code in cloudcoil/client/_config.py
598 599 600 601 602 | |
client_for(resource, sync=True, cached=None)
client_for(
resource: Type[T],
sync: Literal[True] = True,
cached: bool | None = None,
) -> APIClient[T]
client_for(
resource: Type[T],
sync: Literal[False] = False,
cached: bool | None = None,
) -> AsyncAPIClient[T]
Get a client for the specified resource type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource
|
Type[T]
|
The resource type to get a client for |
required |
sync
|
Literal[False, True]
|
Whether to return a sync or async client |
True
|
cached
|
bool | None
|
Whether to use caching. If None, uses cache config setting. If True, forces cached client (requires cache to be enabled). If False, forces non-cached client. |
None
|
Returns:
| Type | Description |
|---|---|
APIClient[T] | AsyncAPIClient[T]
|
A client that may use caching based on configuration |
Source code in cloudcoil/client/_config.py
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 | |
clone(**overrides)
Create a new Config instance with the same parameters but with specified overrides.
This method creates a new Config using the original kubeconfig path if available, ensuring proper certificate handling, and applies any specified overrides.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
**overrides
|
Unpack[ConfigOptions]
|
Any Config constructor parameters to override |
{}
|
Returns:
| Type | Description |
|---|---|
Config
|
A new Config instance with the same base configuration but with overrides applied |
Source code in cloudcoil/client/_config.py
715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 | |
with_cache(cache)
Create a new Config instance with the same parameters but different cache settings.
Source code in cloudcoil/client/_config.py
749 750 751 | |
APIClient
Bases: _BaseAPIClient[T]
Source code in cloudcoil/client/_api_client.py
150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 | |
patch(body, operations, *, subresource=None, dry_run=False)
Apply an RFC 6902 JSON Patch; include tests for optimistic concurrency.
Source code in cloudcoil/client/_api_client.py
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 | |
AsyncAPIClient
Bases: _BaseAPIClient[T]
Source code in cloudcoil/client/_api_client.py
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 | |
patch(body, operations, *, subresource=None, dry_run=False)
async
Apply an RFC 6902 JSON Patch without blocking the event loop.
Source code in cloudcoil/client/_api_client.py
655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 | |
wait_for(resource, predicates, timeout=None)
async
Async version of wait_for that uses asyncio for timing out the watch.
Source code in cloudcoil/client/_api_client.py
954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 | |
Controllers
Typed asynchronous Kubernetes reconciliation and controller lifecycle.
Controller
Reconcile one primary kind, with optional child and dependency watches.
Configure watches before run(). Each instance runs once. The runtime owns its informers and worker tasks; Config ownership remains with the caller. Workers run only after every informer has synced. Failures retry with capped backoff; cancellation and fatal watch errors stop the controller and its sibling tasks.
Source code in cloudcoil/controller/_controller.py
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | |
ready
property
Whether all watches have synced and reconcile workers are running.
status
property
Return local queue and reconcile statistics without inspecting cached objects.
cached(resource)
Read a declared informer, including from a secondary-event mapper.
The primary informer syncs before secondary mappers run. Use explicit namespaces when mapping all-namespace dependencies. No new watch starts.
Source code in cloudcoil/controller/_controller.py
260 261 262 263 264 265 266 267 268 269 270 271 272 | |
enqueue(key)
Request a primary key explicitly, including from an external event source.
Source code in cloudcoil/controller/_controller.py
254 255 256 257 258 | |
mutate(**options)
Register admission mutation returning the edited resource.
Source code in cloudcoil/controller/_controller.py
184 185 186 | |
owns(*resources)
Enqueue primary owners when a child changes (direct controller references).
Owner matching uses group/kind and UID, including across served versions. For indirect or non-owning relationships use watch(..., mapper=...). Application manifests grant get/list/watch/create/patch for owned children. Deletion is left to Kubernetes garbage collection or explicit RBAC.
Source code in cloudcoil/controller/_controller.py
210 211 212 213 214 215 216 217 218 219 220 | |
reconcile(request=None, *, every=None)
reconcile(
request: Request[T],
) -> Awaitable[T | Result | Wait | None]
reconcile(
*, every: float | None = None
) -> Callable[[F], F]
Register an async (resource, optional ctx) handler.
Passing Request explicitly executes a reconciliation for low-level embedding.
Source code in cloudcoil/controller/_controller.py
146 147 148 149 150 151 152 153 154 155 | |
run(*, stop=None)
async
Run until stop is set or the caller cancels; drain on an explicit stop.
An explicit stop drains accepted ready work up to shutdown_timeout, then cancels remaining workers. Cancellation/fatal errors cancel workers directly. Delayed retries are discarded; the next process recovers by listing state.
Source code in cloudcoil/controller/_controller.py
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 | |
validate(**options)
Register admission validation for this controller's resource.
Source code in cloudcoil/controller/_controller.py
180 181 182 | |
wait_ready(timeout=30)
async
Wait for startup, propagating startup failure instead of hanging.
Source code in cloudcoil/controller/_controller.py
295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 | |
watch(resource, *, mapper=None)
watch(resource: type[U], *, mapper: Mapper[U]) -> Self
watch(
resource: type[U],
) -> Callable[[Mapper[U]], Mapper[U]]
Register a synchronous dependency mapper; updates map old and new state.
Source code in cloudcoil/controller/_controller.py
228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 | |
Context
Explicit clients and reporting for one primary resource.
Status and Events are queued; ensure and live clients perform I/O immediately. Context instances belong to one pass and must not be stored on the controller.
Source code in cloudcoil/controller/_context.py
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | |
event(reason, message, *, type='Normal')
Queue a bounded, best-effort Event, flushed after status persistence.
Source code in cloudcoil/controller/_context.py
56 57 58 59 60 61 62 63 64 | |
get(resource, name, *, namespace=None)
async
Read live, defaulting to the primary namespace.
Source code in cloudcoil/controller/_context.py
33 34 35 36 37 38 | |
StageScope
One automatically executed stage, containing a handler or first-match cases.
Usually created through Controller.stage(). A decorator returns the original function, preserving its signature; a named scope can register case handlers.
Source code in cloudcoil/controller/_registry.py
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | |
ResourceKey
dataclass
Identity within a controller's primary resource kind; None is cluster scope.
Source code in cloudcoil/controller/_types.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | |
Result
dataclass
Successful reconciliation; optionally persist a resource and schedule another pass.
resource is a modified copy of this request's primary snapshot. The controller patches its differences before scheduling requeue_after. None performs no write.
Source code in cloudcoil/controller/_types.py
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | |
Wait
Bases: Exception
Expected pending work; raise to stop a pass without increasing backoff.
The low-level returned-Wait interface and requeue_after spelling remain usable.
Source code in cloudcoil/controller/_types.py
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 | |
TerminalError
Bases: Exception
Do not retry this failure; a later event or resync can still reconcile the key.
Source code in cloudcoil/controller/_types.py
233 234 | |
ReconcileStatus
Bases: BaseModel
Optional base for CR status models used by staged reconcilers.
Source code in cloudcoil/controller/_status.py
15 16 17 18 19 20 21 | |
EventRecorder
Emit diagnostics, suppressing repeated reasons per resource UID for interval.
Memory is bounded by max_keys and traffic by a 20-event burst / 5 events per second token bucket per recorder. Changing messages do not defeat suppression. Delivery has a timeout and never raises an API/transport error to a reconciler. No background tasks or durable/exactly-once delivery guarantees.
Source code in cloudcoil/controller/_events.py
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
emit(resource, reason, message, *, type='Normal', action=None, config=None)
async
Return whether delivered; False means suppressed, disabled identity, or failed.
Programmer errors (invalid reason/type/action) raise. Cancellation propagates. Cluster-scoped objects use the recorder namespace or the Config namespace.
Source code in cloudcoil/controller/_events.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 | |
get_condition(resource, condition)
Read a standard metav1 condition by type, returning an independent copy.
Source code in cloudcoil/controller/_status.py
56 57 58 59 60 61 62 | |
set_condition(resource, condition, status, *, reason, message='')
Upsert a standard condition without churning lastTransitionTime.
Only a status change updates the timestamp; reason/message/generation changes preserve it. Other condition types and status fields survive. No API I/O.
Source code in cloudcoil/controller/_status.py
65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 | |
update_status(resource, **changes)
Edit supplied status fields, preserving other fields; return the resource.
Accepts Python field names or wire aliases. Creates an absent status through its schema (required fields must be provided), validates updates, and rejects typos. This is a local edit: return the resource from an ordinary reconciler to save it.
Source code in cloudcoil/controller/_status.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | |
Applications
Shared operator manifests, installation, and process entry point.
Application
Describe, install, and run controllers and admission policies.
Construction and manifest generation are offline. Config is created lazily; an explicitly passed Config remains owned by its caller. Installation uses the caller's privileges; generated runtime RBAC never grants CRD/RBAC setup privileges implicitly. Declare extra RBAC rules for application API calls.
Source code in cloudcoil/application/_application.py
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 | |
ready
property
Admission readiness on every replica; controller readiness is separate.
controller(resource, **options)
Create and include a controller registry.
Source code in cloudcoil/application/_application.py
113 114 115 116 117 | |
include(controller)
Explicitly include a reusable controller group.
Source code in cloudcoil/application/_application.py
103 104 105 106 107 108 109 110 111 | |
install(*, image=None, command=None, replicas=1, include_webhooks=True, timeout=120, force=False)
async
Apply desired objects, establish CRDs, and enable webhooks after rollout.
Existing objects are updated with server-side apply; ownership conflicts fail unless force=True. A failure leaves already applied objects in place for inspection and retry. No resources are deleted or rolled back.
Source code in cloudcoil/application/_application.py
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 | |
lifespan(*, scope='process')
Pair process or elected-leader startup and shutdown around handlers.
Source code in cloudcoil/application/_application.py
129 130 131 132 133 | |
main(argv=None)
Shared manifests, install, and run command-line entry point.
Source code in cloudcoil/application/_application.py
444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 | |
manifests(*, image=None, command=None, replicas=1, include_webhooks=True)
Return fresh CRD/RBAC/Service/Deployment/admission manifests, offline.
image enables a Deployment; command replaces its container entry point. TLS Secrets and namespaces must already exist. include_webhooks=False exports the CRD/RBAC foundation without admission registration or hosting.
Source code in cloudcoil/application/_application.py
180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | |
run(*, stop=None)
async
Serve admission on every replica and run the manager until stopped.
Installation is an explicit earlier step. Workers start after discovery; manager leader election does not gate webhook serving. Embedded use does not replace signal handlers; main() supplies SIGINT/SIGTERM shutdown.
Source code in cloudcoil/application/_application.py
328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 | |
to_yaml(**options)
Serialize manifests for review, kubectl, or GitOps.
Source code in cloudcoil/application/_application.py
213 214 215 | |
LifecycleEvent
dataclass
A per-scope event whose type/error are updated before lifespan cleanup.
Read type inside the handler's finally block to distinguish normal shutdown, leadership loss, and failure. identity is populated for elected leaders.
Source code in cloudcoil/application/_lifecycle.py
22 23 24 25 26 27 28 29 30 31 32 33 | |
LifecycleType
Bases: StrEnum
Source code in cloudcoil/application/_lifecycle.py
14 15 16 17 18 19 | |
RBACRule
dataclass
Additional access, with offline API metadata for generated resource classes.
Custom resources use their CRD declaration; generated models carry API metadata.
Older models require plural and scope once. Namespaced access defaults to the operator's namespace;
use all_namespaces=True explicitly for a cluster-wide grant. subresources
selects those endpoints instead of the main resource. Reconcile and admission
function bodies cannot be inspected to infer their additional access needs.
Source code in cloudcoil/application/_manifests.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | |
WebhookServer
dataclass
TLS files are provided by the deployment, typically from a mounted Secret.
The certificate must cover <operator-name>.<namespace>.svc. ca_bundle
contains public PEM certificates only; private keys never enter manifests.
Source code in cloudcoil/application/_server.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | |
Custom resources
Generate single-version Kubernetes CRDs from the models used by controllers.
Pydantic validators are Python code: use a validation webhook or explicit CEL rules for checks that cannot be represented by the model's JSON Schema.
CRD
A single served/storage version derived from a controller Resource model.
The plural is explicit; group, version and kind come from resource.gvk().
Status is enabled automatically when the model has an optional status field.
Passing columns=[] disables the default Age column. No cluster writes occur.
Source code in cloudcoil/crd.py
505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 | |
manifest()
Return an independent manifest suitable for YAML export or API submission.
Source code in cloudcoil/crd.py
625 626 627 | |
to_yaml()
Serialize the CRD as one YAML document without Python-specific tags.
Source code in cloudcoil/crd.py
629 630 631 | |
PrinterColumn
dataclass
A kubectl column; Annotated fields infer the wire path and scalar type.
For explicit CRD columns supply json_path; type defaults to string there.
Source code in cloudcoil/crd.py
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | |
CEL
dataclass
An Annotated constraint enforced by Kubernetes, not by Python validators.
Source code in cloudcoil/crd.py
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 | |
ListType
dataclass
Kubernetes list merge semantics for an Annotated list field.
Map keys refer to serialized field names, just like Kubernetes manifests.
Source code in cloudcoil/crd.py
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 | |
SchemaError
Bases: ValueError
A model cannot be represented faithfully as a structural CRD schema.
Source code in cloudcoil/crd.py
25 26 | |
custom_resource(*, plural, api_version=None, kind=None, scope='Namespaced', singular=None, short_names=(), categories=(), status=None, columns=None)
Keep CRD metadata with a Resource; generate with CRD(Model).
The decorator preserves the class and performs no cluster I/O or app registration. Supply api_version to define the wire fields here; kind defaults to the class name. Explicit Literal fields remain supported for precise static typing.
Source code in cloudcoil/crd.py
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 | |
Admission
Typed, side-effect-free Kubernetes admission webhooks.
AdmissionWebhook
Register typed async mutators/validators and serve them as an ASGI app.
Use an ASGI server for HTTPS and deployment. Callbacks must be side-effect free. An explicit Config enables injected clients for lookups; returned mutations are applied by the API server. Register all routes before serving or generating configurations.
Source code in cloudcoil/admission/_webhook.py
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 | |
configurations(*, name, service_name, service_namespace, ca_bundle, service_port=443)
Generate v1 webhook configurations from registered routes.
ca_bundle is PEM bytes (not base64); Kubernetes needs a certificate valid for service_name.service_namespace.svc. This method only returns manifests.
Source code in cloudcoil/admission/_webhook.py
332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | |
mutating(model, *, target=None, resource=None, path, operations=('CREATE', 'UPDATE'), subresource='', scope=None, namespace_selector=None, timeout_seconds=5, failure_policy='Fail')
Register a mutator that returns its edited resource, or None for no patch.
Source code in cloudcoil/admission/_webhook.py
186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 | |
register(*models)
Register policies declared on @custom_resource models, atomically.
Paths default to /{mutate|validate}/{group}/{version}/{plural}/{method}. The optional Config and its HTTP clients remain owned by the caller. Client-taking handlers require Config; no discovery occurs during registration.
Source code in cloudcoil/admission/_webhook.py
120 121 122 123 124 125 126 127 | |
validating(model, *, target=None, resource=None, path, operations=('CREATE', 'UPDATE'), subresource='', scope=None, namespace_selector=None, timeout_seconds=5, failure_policy='Fail')
Register a validator; return None to allow or raise AdmissionDenied.
Source code in cloudcoil/admission/_webhook.py
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 | |
AdmissionRequest
Bases: BaseModel
A typed snapshot of one admission request; DELETE has resource=None.
Callbacks must have no external side effects, including during dry runs. Return an edited resource from a mutator; editing this snapshot and returning None has no effect. raw_object and raw_old_object are copies for inspection.
Source code in cloudcoil/admission/_types.py
26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | |
config
property
Caller-owned config injected by AdmissionWebhook, for other resource clients.
cached(resource)
Read an explicitly preconfigured Config cache, never a leader's cache.
Admission serves on every replica. Declare Cache(resources=[...]) on Config, with wait_for_sync=True and mode='strict'. Staleness remains; use client() for checks requiring a live read.
Source code in cloudcoil/admission/_types.py
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | |
client(resource)
async
Read any resource kind using the webhook's connection and request namespace.
Admission handlers must only read: API writes would have side effects even when the admission request is a dry run or is subsequently rejected.
Source code in cloudcoil/admission/_types.py
43 44 45 46 47 48 49 50 51 52 53 | |
AdmissionDenied
Bases: Exception
Reject admission with a message visible to the requesting Kubernetes user.
Source code in cloudcoil/admission/_types.py
89 90 91 92 93 94 95 96 97 98 99 | |
UserInfo
Bases: BaseModel
Identity supplied by the Kubernetes API server, not independently authenticated here.
Source code in cloudcoil/admission/_types.py
17 18 19 20 21 22 23 | |
mutating(*, path=None, operations=('CREATE', 'UPDATE'), subresource='', timeout_seconds=5, failure_policy='Fail')
Mark an async Resource class/static method that returns an edited resource.
The bound method takes AdmissionRequest and optionally an injected AsyncAPIClient. Register the model explicitly with AdmissionWebhook.register before serving.
Source code in cloudcoil/admission/_decorators.py
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | |
validating(*, path=None, operations=('CREATE', 'UPDATE'), subresource='', timeout_seconds=5, failure_policy='Fail')
Mark an async Resource class/static method; raise AdmissionDenied to reject.
Source code in cloudcoil/admission/_decorators.py
57 58 59 60 61 62 63 64 65 66 67 68 69 70 | |
Caching and runtime
CloudCoil Caching - Efficient client-side caching for Kubernetes resources.
This module provides a caching system powered by informers that watch Kubernetes resources and maintain a local cache, similar to client-go's informer pattern.
Key components: - Cache: Configuration and control for the informer system - AsyncInformer/SyncInformer: Watch and cache individual resource types - ConcurrentStore: Thread-safe storage with custom indexing - CachedClient/AsyncCachedClient: Client wrappers that use cache for reads
Example usage:
from cloudcoil.caching import Cache
from cloudcoil.client import Config
import cloudcoil.models.kubernetes as k8s
# Basic usage - just enable caching
config = Config(cache=True)
with config:
deployment = k8s.apps.v1.Deployment.get("my-app") # From cache
# Advanced configuration
cache_config = Cache(
resync_period=600, # 10 minutes
mode="strict", # Cache-only mode
resources=[k8s.apps.v1.Deployment, k8s.core.v1.Pod]
)
config = Config(cache=cache_config)
# Event handling
async with config:
informer = config.cache.get_informer(k8s.apps.v1.Deployment)
@informer.on_add
def handle_new_deployment(deployment):
print(f"New deployment: {deployment.metadata.name}")
Cache
Bases: Cache
Cache configuration and runtime control.
This extends the CacheConfig Pydantic model with runtime methods for controlling the informer system lifecycle.
Configuration fields are validated by Pydantic, while runtime methods provide lifecycle control following CloudCoil's async-first patterns.
Source code in cloudcoil/caching/_cache.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | |
__init__(**data)
Initialize cache with configuration.
Source code in cloudcoil/caching/_cache.py
46 47 48 49 50 51 52 53 54 55 | |
async_start()
async
Start all informers asynchronously.
Source code in cloudcoil/caching/_cache.py
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | |
async_stop()
async
Stop all informers asynchronously.
Source code in cloudcoil/caching/_cache.py
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 | |
async_wait(timeout=None)
async
Wait for cache to be ready asynchronously.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
Optional[float]
|
Maximum time to wait (uses sync_timeout if not provided) |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if ready, False if timeout |
Source code in cloudcoil/caching/_cache.py
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 | |
fallback_mode()
Temporarily use fallback mode within this context.
Source code in cloudcoil/caching/_cache.py
391 392 393 394 395 396 397 398 399 | |
get_informer(resource_type, sync=False, namespace=None)
Get or create informer for a specific resource type.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
resource_type
|
Type[T]
|
The resource type |
required |
sync
|
bool
|
Whether to return sync wrapper |
False
|
namespace
|
Optional[str]
|
Optional namespace scope |
None
|
Returns:
| Type | Description |
|---|---|
Optional[Union[AsyncInformer[T], SyncInformer[T]]]
|
The informer instance, or None if not available |
Source code in cloudcoil/caching/_cache.py
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 | |
pause()
Temporarily disable cache within this context.
Supports nested usage with reference counting.
Source code in cloudcoil/caching/_cache.py
360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 | |
ready()
Check if cache is synced and ready (non-blocking check).
Source code in cloudcoil/caching/_cache.py
244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | |
set_client_factory(factory)
Set the client factory function (called by Config).
Source code in cloudcoil/caching/_cache.py
57 58 59 | |
start()
Start all informers synchronously (blocks until started).
Source code in cloudcoil/caching/_cache.py
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 | |
status()
Get cache status information.
Source code in cloudcoil/caching/_cache.py
401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 | |
stop()
Stop all informers synchronously (blocks until stopped).
Source code in cloudcoil/caching/_cache.py
196 197 198 199 200 201 202 203 204 205 206 207 208 | |
strict_mode()
Temporarily use strict mode within this context.
Source code in cloudcoil/caching/_cache.py
381 382 383 384 385 386 387 388 389 | |
wait(timeout=None)
Wait for cache to be ready synchronously.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
timeout
|
Optional[float]
|
Maximum time to wait (uses sync_timeout if not provided) |
None
|
Returns:
| Type | Description |
|---|---|
bool
|
True if ready, False if timeout |
Source code in cloudcoil/caching/_cache.py
210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 | |
CachedResources
Local get/list with no API fallback; values are independent deep copies.
Missing objects return None. An unsynced or stopped informer raises instead of presenting an empty cache as authoritative. Lists cover only the watched scope, are eventually consistent, and have no server pagination tokens.
Source code in cloudcoil/caching/_reader.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
list(namespace=None, *, all_namespaces=False, labels=None)
List cached objects; labels is an AND of exact label matches.
all_namespaces means all namespaces in this informer's configured scope, not an expansion of its watch. Filtering scans the in-memory snapshot.
Source code in cloudcoil/caching/_reader.py
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | |
AsyncInformer
Bases: Generic[T]
Async informer with minimal public API and better concurrency patterns.
Public API: - get(name, namespace) - Get resource from cache - list(namespace, label_selector, field_selector) - List resources from cache - on_add(handler) - Register add event handler - on_update(handler) - Register update event handler - on_delete(handler) - Register delete event handler
All other methods and attributes are private implementation details.
Source code in cloudcoil/caching/_informer.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 | |
__init__(client, options)
Initialize the async informer.
Source code in cloudcoil/caching/_informer.py
44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | |
add_index(name, index_func)
Add a custom index for fast lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the index |
required |
index_func
|
Callable[[T], str]
|
Function that extracts index key from a resource |
required |
Source code in cloudcoil/caching/_informer.py
252 253 254 255 256 257 258 259 | |
get(name, namespace=None)
Get a resource from cache by name.
Source code in cloudcoil/caching/_informer.py
72 73 74 | |
get_by_index(index_name, index_key)
Get resources by custom index.
Source code in cloudcoil/caching/_informer.py
261 262 263 | |
has_synced()
Check if initial sync is complete.
Source code in cloudcoil/caching/_informer.py
271 272 273 | |
list(namespace=None, label_selector=None, field_selector=None)
List resources from cache with optional filtering.
Source code in cloudcoil/caching/_informer.py
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | |
list_index_keys(index_name)
List all keys for a given index.
Source code in cloudcoil/caching/_informer.py
265 266 267 | |
on_add(handler=None)
on_add(
handler: Union[EventHandler, AsyncEventHandler],
) -> None
on_add(
handler: None = None,
) -> Callable[
[Union[EventHandler, AsyncEventHandler]],
Union[EventHandler, AsyncEventHandler],
]
Register a handler for add events. Can be used as a decorator.
Usage
As a decorator
@informer.on_add def handle_add(obj): print(f"Added: {obj.metadata.name}")
As a regular method
informer.on_add(handle_add)
Source code in cloudcoil/caching/_informer.py
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 | |
on_delete(handler=None)
on_delete(
handler: Union[EventHandler, AsyncEventHandler],
) -> None
on_delete(
handler: None = None,
) -> Callable[
[Union[EventHandler, AsyncEventHandler]],
Union[EventHandler, AsyncEventHandler],
]
Register a handler for delete events. Can be used as a decorator.
Usage
As a decorator
@informer.on_delete def handle_delete(obj): print(f"Deleted: {obj.metadata.name}")
As a regular method
informer.on_delete(handle_delete)
Source code in cloudcoil/caching/_informer.py
215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | |
on_update(handler=None)
on_update(
handler: Union[UpdateHandler, AsyncUpdateHandler],
) -> None
on_update(
handler: None = None,
) -> Callable[
[Union[UpdateHandler, AsyncUpdateHandler]],
Union[UpdateHandler, AsyncUpdateHandler],
]
Register a handler for update events. Can be used as a decorator.
Usage
As a decorator
@informer.on_update def handle_update(old_obj, new_obj): print(f"Updated: {new_obj.metadata.name}")
As a regular method
informer.on_update(handle_update)
Source code in cloudcoil/caching/_informer.py
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 | |
SyncInformer
Bases: Generic[T]
Sync informer with minimal public API and better threading patterns.
Public API: - get(name, namespace) - Get resource from cache - list(namespace, label_selector, field_selector) - List resources from cache - on_add(handler) - Register add event handler - on_update(handler) - Register update event handler - on_delete(handler) - Register delete event handler
All other methods and attributes are private implementation details.
Source code in cloudcoil/caching/_informer.py
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 | |
__init__(client, options)
Initialize the sync informer.
Source code in cloudcoil/caching/_informer.py
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 | |
add_index(name, index_func)
Add a custom index for fast lookups.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
The name of the index |
required |
index_func
|
Callable[[T], str]
|
Function that extracts index key from a resource |
required |
Source code in cloudcoil/caching/_informer.py
598 599 600 601 602 603 604 605 | |
get(name, namespace=None)
Get a resource from cache by name.
Source code in cloudcoil/caching/_informer.py
458 459 460 | |
get_by_index(index_name, index_key)
Get resources by custom index.
Source code in cloudcoil/caching/_informer.py
607 608 609 | |
has_synced()
Check if initial sync is complete.
Source code in cloudcoil/caching/_informer.py
617 618 619 | |
list(namespace=None, label_selector=None, field_selector=None)
List resources from cache with optional filtering.
Source code in cloudcoil/caching/_informer.py
462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 | |
list_index_keys(index_name)
List all keys for a given index.
Source code in cloudcoil/caching/_informer.py
611 612 613 | |
on_add(handler=None)
on_add(handler: EventHandler) -> None
on_add(
handler: None = None,
) -> Callable[[EventHandler], EventHandler]
Register a handler for add events. Can be used as a decorator.
Usage
As a decorator
@informer.on_add def handle_add(obj): print(f"Added: {obj.metadata.name}")
As a regular method
informer.on_add(handle_add)
Source code in cloudcoil/caching/_informer.py
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 | |
on_delete(handler=None)
on_delete(handler: EventHandler) -> None
on_delete(
handler: None = None,
) -> Callable[[EventHandler], EventHandler]
Register a handler for delete events. Can be used as a decorator.
Usage
As a decorator
@informer.on_delete def handle_delete(obj): print(f"Deleted: {obj.metadata.name}")
As a regular method
informer.on_delete(handle_delete)
Source code in cloudcoil/caching/_informer.py
571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 | |
on_update(handler=None)
on_update(handler: UpdateHandler) -> None
on_update(
handler: None = None,
) -> Callable[[UpdateHandler], UpdateHandler]
Register a handler for update events. Can be used as a decorator.
Usage
As a decorator
@informer.on_update def handle_update(old_obj, new_obj): print(f"Updated: {new_obj.metadata.name}")
As a regular method
informer.on_update(handle_update)
Source code in cloudcoil/caching/_informer.py
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 | |
Run controllers together, sharing compatible watches and stopping on failure.
Configs may be specified per controller, on the manager, or in the active context, in that order. Watch sharing never crosses Config instances. Each manager runs once and owns the shared informers until all workers have stopped.
Source code in cloudcoil/controller/_manager.py
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
healthy
property
Running without fatal failure, including startup and standby.
informer_count
property
Number of distinct manager-owned watch subscriptions.
metrics()
Prometheus text exposition; local counters persist after shutdown.
Source code in cloudcoil/controller/_manager.py
69 70 71 | |
run(*, stop=None)
async
Run until explicit stop, cancellation, or a fatal controller failure.
Source code in cloudcoil/controller/_manager.py
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | |
Elect one active manager using a coordination.k8s.io/v1 Lease.
Identity defaults to a process-unique hostname/UUID. Explicit identities must also be unique per participant. Takeover waits for the observed record to stop changing for its lease duration, measured locally; remote wall clocks are not used for expiry. Like client-go, this is coordination, not distributed fencing. Reconciliation and external operations must remain idempotent and cancellable.
Source code in cloudcoil/controller/_leader.py
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 | |
Serve GET /healthz, /readyz, and /metrics; opt in through Manager(health=...).
Defaults to loopback. Bind host="0.0.0.0" for container probes. This is a plain HTTP diagnostics listener; protect access with your network configuration. Connections have bounded headers, a read deadline, and no keep-alive.
Source code in cloudcoil/controller/_health.py
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | |
address
property
Bound host and port (including an assigned port=0), or None when stopped.
Immutable local snapshot; counts reset when a controller is recreated.
Source code in cloudcoil/controller/_metrics.py
13 14 15 16 17 18 19 20 21 22 23 24 25 | |
Serialize each key while allowing different keys to run concurrently.
Call add/done/retry from the same event loop as get. Repeated adds coalesce; an add during processing guarantees one more pass after done. Delayed work uses one timer per key, never a sleeping task per event. This is an in-memory queue: restart recovery comes from listing the desired Kubernetes state.
Source code in cloudcoil/controller/_queue.py
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 | |
delayed
property
Keys with a pending retry or scheduled requeue.
depth
property
Ready keys waiting for a worker; excludes in-flight and delayed keys.
processing
property
Keys currently reserved by workers.
add(key)
Request reconciliation now; fresh events supersede a delayed retry.
Source code in cloudcoil/controller/_queue.py
59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
add_after(key, delay)
Schedule a key, preserving the earliest pending deadline.
Source code in cloudcoil/controller/_queue.py
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | |
done(key)
Release a processing key and queue any update that arrived meanwhile.
Source code in cloudcoil/controller/_queue.py
132 133 134 135 136 137 138 139 140 | |
forget(key)
Reset failure history after success or a terminal error.
Source code in cloudcoil/controller/_queue.py
112 113 114 | |
get()
async
Take the next key; always pair a successful get with done in finally.
Source code in cloudcoil/controller/_queue.py
120 121 122 123 124 125 126 127 128 129 130 | |
join()
async
Wait until ready, processing, and delayed work are all finished.
Source code in cloudcoil/controller/_queue.py
142 143 144 | |
num_retries(key)
Return consecutive retry requests since the last forget.
Source code in cloudcoil/controller/_queue.py
116 117 118 | |
retry(key)
Schedule exponential backoff with jitter and return the chosen delay.
Source code in cloudcoil/controller/_queue.py
99 100 101 102 103 104 105 106 107 108 109 110 | |
shutdown(*, immediate=False)
Reject new work and discard timers; optionally discard ready work too.
With immediate=False, consumers can drain accepted ready/dirty work. In-flight work always requires done; shutdown never cancels callers.
Source code in cloudcoil/controller/_queue.py
146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 | |
Explicit reconciliation and writes
These APIs support embedding and existing Request callbacks. Start with the decorator guide for new applications.
Typed asynchronous Kubernetes reconciliation and controller lifecycle.
Request
dataclass
Latest cached state at worker dispatch, copied so mutation cannot corrupt the cache.
resource=None means the key is absent from the watched scope (deleted or no longer selected). It is not a deletion proof for destructive external cleanup; use a finalizer and a live API read for that. Reads are eventually consistent.
Source code in cloudcoil/controller/_types.py
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | |
object
property
The present primary object; stages are only invoked for present objects.
cached(resource)
Read the primary or a declared .owns/.watch informer, without I/O.
Source code in cloudcoil/controller/_types.py
151 152 153 154 155 | |
client(resource)
async
A live client for any kind, sharing this operator's connection.
Namespaced clients default to this request's namespace. Pass a namespace to client operations for cross-namespace reads. Clients share the Config lifetime and must not be closed by handlers.
Source code in cloudcoil/controller/_types.py
157 158 159 160 161 162 163 164 | |
condition(condition, status, *, reason, message='', event=False, warning=False, action=None)
Stage a standard condition; optionally emit an Event on a transition.
A changed truth value or reason counts as an Event transition. Message and generation-only changes do not. Events flush only after status persistence.
Source code in cloudcoil/controller/_types.py
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 | |
ensure(desired)
async
Create or patch an owned child; omitted fields remain untouched.
Defaults name and namespace from the parent. Refuses unrelated existing objects. Maps merge, lists replace, and explicit None removes a field. Child events are subscribed separately with Controller.owns(...).
Source code in cloudcoil/controller/_types.py
166 167 168 169 170 171 172 173 174 175 176 177 | |
event(reason, message, *, type='Normal')
async
Record a bounded, best-effort Kubernetes Event regarding this resource.
Source code in cloudcoil/controller/_types.py
141 142 143 144 145 146 147 148 149 | |
set_status(**changes)
Stage validated status fields for persistence, even if the handler fails.
Only explicit helper updates are saved on failure, never spec or metadata. Ordinary resource edits still require returning the resource on success.
Source code in cloudcoil/controller/_types.py
77 78 79 80 81 82 83 84 85 | |
Stage
dataclass
An idempotent action named by the condition it establishes.
Source code in cloudcoil/controller/_stages.py
17 18 19 20 21 22 23 24 25 26 27 28 29 30 | |
Stages
Run stages in explicit order, stopping on waiting or failure.
Every pass starts from the first stage, including when previously Ready. Conditions are observations, never checkpoints that skip drift repair. The controller persists status on waits/errors and applies its normal retries.
Source code in cloudcoil/controller/_stages.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | |
Cases
Register first-match cases on an instance before the controller starts.
Without priorities, registration order is execution order. When priorities are supplied, every case must have a distinct integer priority (higher runs first). Predicates are synchronous, side-effect-free reads of current state. They are evaluated lazily; only the first matching action executes, even if it waits.
Source code in cloudcoil/controller/_stages.py
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 | |
otherwise(name)
Register the explicit fallback, which always follows all predicates.
Source code in cloudcoil/controller/_stages.py
168 169 170 171 172 173 174 175 176 177 178 | |
mutate(resource, change, *, status=False, config=None)
async
Fetch live state, edit a copy, and patch only changes with UID/version tests.
A no-op issues no PATCH. The synchronous callback must only edit the copy and have no external side effects. Conflicts propagate to the reconcile retry loop, which will read fresh state on its next attempt. The supplied resource must have a UID; never apply work for a deleted object to a replacement with the same name.
Source code in cloudcoil/controller/_mutations.py
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | |
ensure_finalizer(resource, finalizer, *, config=None)
async
Persist this controller's finalizer before creating external resources.
Refuses to add a missing finalizer once deletion has begun. Existing finalizers are preserved. Complete cleanup before calling remove_finalizer.
Source code in cloudcoil/controller/_mutations.py
52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 | |
remove_finalizer(resource, finalizer, *, config=None)
async
Remove only this finalizer after successful, idempotent external cleanup.
Source code in cloudcoil/controller/_mutations.py
75 76 77 78 79 80 81 82 83 84 85 86 | |
Dependency-free JSON Patch calculation and optimistic resource diffs.
diff(before, after)
Diff copies of one fetched resource, guarded by UID and resourceVersion.
Returns [] for no changes. Identity/version changes are rejected. Keep the original snapshot unchanged and edit a deep copy. None-valued model fields are omitted, matching Resource writes; clearing a field generates a remove.
Source code in cloudcoil/patches.py
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 | |
json_patch(before, after)
Calculate RFC 6902 operations for JSON values, preserving explicit nulls.
Object members are diffed recursively. Arrays are replaced as a whole; this does not infer Kubernetes strategic-merge keys. Values are copied into the patch so later mutation of the desired document cannot change the request.
Source code in cloudcoil/patches.py
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | |