{"id":18284477,"url":"https://github.com/pplu/io-k8s-p5","last_synced_at":"2026-04-28T08:06:09.681Z","repository":{"id":56838756,"uuid":"132057654","full_name":"pplu/io-k8s-p5","owner":"pplu","description":"Objects representing things found in the Kubernetes API","archived":false,"fork":false,"pushed_at":"2026-03-19T21:30:27.000Z","size":2288,"stargazers_count":1,"open_issues_count":2,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2026-03-20T11:52:04.123Z","etag":null,"topics":["kubernetes","kubernetes-api","perl"],"latest_commit_sha":null,"homepage":"","language":"Perl","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/pplu.png","metadata":{"files":{"readme":"README.md","changelog":"Changes","contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2018-05-03T22:53:46.000Z","updated_at":"2026-03-19T21:30:35.000Z","dependencies_parsed_at":"2022-09-12T11:51:38.184Z","dependency_job_id":null,"html_url":"https://github.com/pplu/io-k8s-p5","commit_stats":null,"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/pplu/io-k8s-p5","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pplu%2Fio-k8s-p5","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pplu%2Fio-k8s-p5/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pplu%2Fio-k8s-p5/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pplu%2Fio-k8s-p5/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/pplu","download_url":"https://codeload.github.com/pplu/io-k8s-p5/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/pplu%2Fio-k8s-p5/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32371737,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-27T20:07:02.737Z","status":"online","status_checked_at":"2026-04-28T02:00:07.250Z","response_time":56,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["kubernetes","kubernetes-api","perl"],"created_at":"2024-11-05T13:13:40.704Z","updated_at":"2026-04-28T08:06:09.662Z","avatar_url":"https://github.com/pplu.png","language":"Perl","funding_links":[],"categories":[],"sub_categories":[],"readme":"# IO::K8s\n\nPerl objects representing the Kubernetes API (v1.31).\n\n## Description\n\nThis module provides Perl objects and serialization/deserialization methods that represent the structures found in the Kubernetes API (v1.31).\n\nKubernetes API is strict about input types. When a value is expected to be an integer, sending it as a string will cause rejection. This module ensures correct value types in JSON that can be sent to Kubernetes.\n\nIt also inflates JSON returned by Kubernetes into typed Perl objects.\n\n## Installation\n\nFrom CPAN:\n\n```bash\ncpanm IO::K8s\n```\n\nFrom source:\n\n```bash\ncpanm --installdeps .\ndzil build\ndzil test\ndzil install\n```\n\n## Usage\n\n```perl\nuse IO::K8s;\n\nmy $k8s = IO::K8s-\u003enew;\n\n# Create objects with short names\nmy $pod = $k8s-\u003enew_object('Pod',\n    metadata =\u003e { name =\u003e 'my-pod', namespace =\u003e 'default' },\n    spec =\u003e { containers =\u003e [{ name =\u003e 'app', image =\u003e 'nginx' }] }\n);\n\n# Load and validate YAML manifests\nmy $resources = $k8s-\u003eload_yaml('deployment.yaml');\n\n# Save to YAML file\n$pod-\u003esave('pod.yaml');\n\n# Inflate JSON/struct into typed objects (auto-detect class from 'kind')\nmy $svc = $k8s-\u003ejson_to_object('Service', '{\"kind\":\"Service\"}');\nmy $obj = $k8s-\u003einflate({ kind =\u003e 'Pod', metadata =\u003e { name =\u003e 'test' } });\n\n# Serialize back to JSON\nmy $json = $k8s-\u003eobject_to_json($svc);\nmy $struct = $k8s-\u003eobject_to_struct($pod);\n```\n\n## Bundled CRD Providers\n\nIO::K8s ships with CRD classes for popular Kubernetes ecosystem projects. None are loaded by default - opt in at construction:\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e [\n    'IO::K8s::Cilium',\n    'IO::K8s::Traefik',\n    'IO::K8s::CertManager',\n    'IO::K8s::K3s',\n    'IO::K8s::GatewayAPI',\n    'IO::K8s::AgentSandbox',\n]);\n```\n\n### Cilium (21 CRDs)\n\n`IO::K8s::Cilium` covers `cilium.io/v2` and `cilium.io/v2alpha1` (upstream v1.19.2):\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::Cilium']);\nmy $cnp = $k8s-\u003enew_object('CiliumNetworkPolicy',\n    metadata =\u003e { name =\u003e 'allow-dns', namespace =\u003e 'kube-system' },\n    spec =\u003e { endpointSelector =\u003e {} },\n);\n```\n\n### Traefik (10 CRDs)\n\n`IO::K8s::Traefik` covers `traefik.io/v1alpha1`:\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::Traefik']);\nmy $ir = $k8s-\u003enew_object('IngressRoute',\n    metadata =\u003e { name =\u003e 'my-route', namespace =\u003e 'default' },\n    spec =\u003e { entryPoints =\u003e ['web'], routes =\u003e [{ match =\u003e 'Host(`example.com`)' }] },\n);\n```\n\n### cert-manager (6 CRDs)\n\n`IO::K8s::CertManager` covers `cert-manager.io/v1` and `acme.cert-manager.io/v1`:\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::CertManager']);\nmy $cert = $k8s-\u003enew_object('Certificate',\n    metadata =\u003e { name =\u003e 'my-cert', namespace =\u003e 'default' },\n    spec =\u003e { secretName =\u003e 'my-cert-tls', issuerRef =\u003e { name =\u003e 'letsencrypt' } },\n);\n```\n\n### K3s (4 CRDs)\n\n`IO::K8s::K3s` covers `helm.cattle.io/v1` and `k3s.cattle.io/v1` (upstream v1.35.1+k3s1):\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::K3s']);\nmy $hc = $k8s-\u003enew_object('HelmChart',\n    metadata =\u003e { name =\u003e 'traefik', namespace =\u003e 'kube-system' },\n    spec =\u003e { chart =\u003e 'traefik' },\n);\n```\n\n### Gateway API (5 CRDs)\n\n`IO::K8s::GatewayAPI` covers `gateway.networking.k8s.io/v1` and `gateway.networking.k8s.io/v1beta1`:\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::GatewayAPI']);\nmy $gw = $k8s-\u003enew_object('Gateway',\n    metadata =\u003e { name =\u003e 'my-gateway', namespace =\u003e 'default' },\n    spec =\u003e { gatewayClassName =\u003e 'istio', listeners =\u003e [{ name =\u003e 'http', port =\u003e 80 }] },\n);\n```\n\n### AgentSandbox (4 CRDs)\n\n`IO::K8s::AgentSandbox` covers `agents.x-k8s.io/v1alpha1` and `extensions.agents.x-k8s.io/v1alpha1` (upstream v0.2.1):\n\n```perl\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::AgentSandbox']);\nmy $sandbox = $k8s-\u003enew_object('Sandbox',\n    metadata =\u003e { name =\u003e 'my-sandbox', namespace =\u003e 'default' },\n    spec =\u003e { replicas =\u003e 1, shutdownPolicy =\u003e 'Retain' },\n);\n```\n\n## Convenience Roles\n\nAll API objects automatically get label, annotation, condition, and owner reference methods:\n\n```perl\n# Labels \u0026 annotations (all API objects)\n$pod-\u003eadd_label(app =\u003e 'web');\n$pod-\u003eadd_labels(app =\u003e 'web', tier =\u003e 'frontend');\n$pod-\u003ehas_label('app');            # true\n$pod-\u003ematch_labels(app =\u003e 'web');  # true\n$pod-\u003eadd_annotation('prometheus.io/scrape' =\u003e 'true');\n\n# Status conditions (objects with status)\n$deploy-\u003eis_ready;\n$deploy-\u003eis_condition_true('Available');\n$deploy-\u003econdition_message('Progressing');\n\n# Owner references\n$pod-\u003eset_owner($deployment);\n$pod-\u003eis_owned_by($deployment);\n```\n\nCRD classes automatically get deep-path spec manipulation via `SpecBuilder`:\n\n```perl\n$ir-\u003espec_set('tls.secretName', 'my-cert');\n$ir-\u003espec_get('routes.0.match');\n$ir-\u003espec_push('routes', { match =\u003e 'Host(`api.example.com`)' });\n$ir-\u003espec_merge(entryPoints =\u003e ['web', 'websecure']);\n$ir-\u003espec_delete('tls');\n```\n\nDomain-specific builder roles provide fluent APIs for common tasks:\n\n```perl\n# Network policies (core K8s + Cilium)\n$netpol-\u003eselect_pods(app =\u003e 'web')\n       -\u003eallow_ingress_from_pods({ app =\u003e 'nginx' }, ports =\u003e [{ port =\u003e 8080 }])\n       -\u003eallow_egress_to_dns\n       -\u003edeny_all_egress;\n\n# HTTP routing (Ingress, HTTPRoute, IngressRoute)\n$route-\u003eadd_hostname('example.com')\n      -\u003eadd_backend('api-v1', port =\u003e 8080, weight =\u003e 90)\n      -\u003eadd_path_match('/api', type =\u003e 'Prefix');\n\n# cert-manager\n$cert-\u003efor_domains('example.com', '*.example.com')\n     -\u003ewith_issuer('letsencrypt-prod', kind =\u003e 'ClusterIssuer')\n     -\u003estore_in_secret('example-tls');\n\n# K3s Helm charts\n$chart-\u003efrom_repo('https://traefik.github.io/charts', 'traefik')\n      -\u003eset_version('25.0.0')\n      -\u003eset_values(replicas =\u003e 3);\n\n# Traefik middleware\n$mw-\u003erate_limit(average =\u003e 100, burst =\u003e 200)\n   -\u003estrip_prefix('/api')\n   -\u003eredirect_https;\n```\n\n### IP Type Validation\n\n`IO::K8s::Types::Net` provides Net::IP-backed type constraints:\n\n```perl\nuse IO::K8s::Types::Net qw( IPv4 IPv6 IPAddress CIDR NetIP );\nuse IO::K8s::Types::Net qw( parse_ip cidr_contains is_rfc1918 );\n\ncidr_contains('10.0.0.0/8', '10.1.2.3');  # true\nis_rfc1918('192.168.1.1');                 # true\n```\n\n## External Resource Maps\n\nMerge resource maps from external packages (e.g. `IO::K8s::Cilium` or your own CRD packages):\n\n```perl\n# At construction time\nmy $k8s = IO::K8s-\u003enew(with =\u003e ['IO::K8s::Cilium']);\n\n# Or at runtime\n$k8s-\u003eadd('IO::K8s::Cilium');\n\n# Disambiguate colliding kind names with domain-qualified strings\n$k8s-\u003enew_object('cilium.io/v2/CiliumNetworkPolicy', { ... });\n\n# Or with api_version parameter\n$k8s-\u003enew_object('CiliumNetworkPolicy', { ... }, 'cilium.io/v2');\n\n# inflate() auto-uses apiVersion from JSON data\n$k8s-\u003einflate('{\"kind\":\"CiliumNetworkPolicy\",\"apiVersion\":\"cilium.io/v2\",...}');\n```\n\n### pk8s DSL\n\nIn `.pk8s` manifest files, Cilium kinds work directly:\n\n```perl\nCiliumNetworkPolicy {\n    name =\u003e 'allow-dns',\n    namespace =\u003e 'kube-system',\n    spec =\u003e { endpointSelector =\u003e {} },\n};\n\nCiliumNode {\n    name =\u003e 'worker-1',\n    spec =\u003e { addresses =\u003e [{ type =\u003e 'InternalIP', ip =\u003e '10.0.0.1' }] },\n};\n```\n\n## Custom Resource Definitions (CRDs)\n\nWrite your own CRD classes using `IO::K8s::APIObject`:\n\n```perl\npackage My::StaticWebSite;\nuse IO::K8s::APIObject\n    api_version     =\u003e 'homelab.example.com/v1',\n    resource_plural =\u003e 'staticwebsites';\nwith 'IO::K8s::Role::Namespaced';\n\nk8s spec   =\u003e { Str =\u003e 1 };\nk8s status =\u003e { Str =\u003e 1 };\n1;\n```\n\nOr generate them dynamically from an OpenAPI schema using `IO::K8s::AutoGen`.\n\nSee the full POD documentation for details on the class architecture and CRD support.\n\n## Features\n\n- Support for Kubernetes v1.31 API objects\n- Type-safe object creation and serialization\n- Lightweight Moo-based implementation\n- Handles all Kubernetes resource types (Pods, Services, Deployments, etc.)\n- Custom Resource Definition (CRD) support with `IO::K8s::APIObject` import parameters\n- External resource map support with collision handling (`add()`, `with` constructor param)\n- Domain-qualified resource names for disambiguation (`api_version/Kind`)\n- Dynamic class generation from OpenAPI schemas via `IO::K8s::AutoGen`\n- Convenience methods: labels, annotations, conditions, owner references on all API objects\n- Deep-path spec manipulation for CRD classes via `SpecBuilder`\n- Domain-specific builder roles for network policies, routing, certificates, Helm, and more\n- Net::IP-backed IP/CIDR type constraints (`IO::K8s::Types::Net`)\n- Proper handling of namespaced resources\n- Canonical JSON output for consistent API requests\n\n## Links\n\n- CPAN: https://metacpan.org/pod/IO::K8s\n- GitHub: https://github.com/pplu/io-k8s-p5\n- Issues: https://github.com/pplu/io-k8s-p5/issues\n- Kubernetes API Reference: https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.31/\n\n## Authors\n\n- Torsten Raudssus \u003ctorsten@raudssus.de\u003e\n- Jose Luis Martinez \u003cjlmartin@cpan.org\u003e (original author, inactive)\n\n## License\n\nCopyright (c) 2018 by Jose Luis Martinez\n\nThis code is distributed under the Apache 2 License. The full text of the license can be found in the LICENSE file included with this module.\n\n## Support\n\n- IRC: #kubernetes on irc.perl.org\n- Issues: https://github.com/pplu/io-k8s-p5/issues\n\n## See Also\n\n- [Kubernetes::REST](https://metacpan.org/pod/Kubernetes::REST) - Kubernetes REST API client\n- [IO::K8s::Resource](https://metacpan.org/pod/IO::K8s::Resource) - Base class for all Kubernetes resources\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpplu%2Fio-k8s-p5","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpplu%2Fio-k8s-p5","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpplu%2Fio-k8s-p5/lists"}