File Coverage

blib/lib/IO/K8s/Role/CertManaged.pm
Criterion Covered Total %
statement 76 79 96.2
branch 11 22 50.0
condition 26 43 60.4
subroutine 12 12 100.0
pod 0 10 0.0
total 125 166 75.3


line stmt bran cond sub pod time code
1             package IO::K8s::Role::CertManaged;
2             # ABSTRACT: Role for cert-manager certificate and issuer management
3             our $VERSION = '1.008';
4 3     3   2159 use Moo::Role;
  3         7  
  3         27  
5 3     3   1989 use Carp qw(croak);
  3         7  
  3         3824  
6              
7             # --- Certificate methods ---
8              
9             sub for_domains {
10 2     2 0 461314 my ($self, @domains) = @_;
11 2   50     64 my $spec = $self->spec // {};
12 2   50     42 my $existing = $spec->{dnsNames} // [];
13 2         8 push @$existing, @domains;
14 2         6 $spec->{dnsNames} = $existing;
15 2         53 $self->spec($spec);
16 2         74 return $self;
17             }
18              
19             sub with_issuer {
20 2     2 0 5393 my ($self, $name, %opts) = @_;
21 2   100     51 my $spec = $self->spec // {};
22             $spec->{issuerRef} = {
23             name => $name,
24             kind => $opts{kind} // 'Issuer',
25 2 50 50     40 $opts{group} ? (group => $opts{group}) : (group => 'cert-manager.io'),
26             };
27 2         51 $self->spec($spec);
28 2         65 return $self;
29             }
30              
31             sub store_in_secret {
32 2     2 0 7420 my ($self, $secret_name) = @_;
33 2   100     53 my $spec = $self->spec // {};
34 2         23 $spec->{secretName} = $secret_name;
35 2         48 $self->spec($spec);
36 2         62 return $self;
37             }
38              
39             sub add_ip_san {
40 2     2 0 6255 my ($self, @ips) = @_;
41 2         846 require IO::K8s::Types::Net;
42 2         10 for my $ip (@ips) {
43 3 100       1118 croak "'$ip' is not a valid IP address"
44             unless IO::K8s::Types::Net::IPAddress()->check($ip);
45             }
46 1   50     949 my $spec = $self->spec // {};
47 1   50     24 my $existing = $spec->{ipAddresses} // [];
48 1         3 push @$existing, @ips;
49 1         5 $spec->{ipAddresses} = $existing;
50 1         47 $self->spec($spec);
51 1         48 return $self;
52             }
53              
54             sub renew_before {
55 2     2 0 5473 my ($self, %opts) = @_;
56 2   100     53 my $spec = $self->spec // {};
57 2 50       25 if ($opts{days}) {
    0          
58 2         10 $spec->{renewBefore} = ($opts{days} * 24) . 'h0m0s';
59             } elsif ($opts{hours}) {
60 0         0 $spec->{renewBefore} = $opts{hours} . 'h0m0s';
61             }
62 2         49 $self->spec($spec);
63 2         65 return $self;
64             }
65              
66             # --- Issuer/ClusterIssuer methods ---
67              
68             sub letsencrypt {
69 5     5 0 25553 my ($self, %opts) = @_;
70 5 50       14 my $email = $opts{email} or croak 'email is required for letsencrypt';
71 5   100     18 my $production = $opts{production} // 0;
72 5 100       9 my $server = $production
73             ? 'https://acme-v02.api.letsencrypt.org/directory'
74             : 'https://acme-staging-v02.api.letsencrypt.org/directory';
75              
76 5   50     70 my $spec = $self->spec // {};
77             $spec->{acme} = {
78             email => $email,
79             server => $server,
80 5   50     51 privateKeySecretRef => { name => $opts{secret} // 'letsencrypt-account-key' },
81             };
82 5         55 $self->spec($spec);
83 5         103 return $self;
84             }
85              
86             sub self_signed {
87 1     1 0 2521 my ($self) = @_;
88 1   50     13 my $spec = $self->spec // {};
89 1         8 $spec->{selfSigned} = {};
90 1         12 $self->spec($spec);
91 1         64 return $self;
92             }
93              
94             sub ca {
95 2     2 0 3008 my ($self, %opts) = @_;
96 2   50     25 my $spec = $self->spec // {};
97             $spec->{ca} = {
98 2   66     43 secretName => $opts{secret} // croak('secret is required for ca'),
99             };
100 1         14 $self->spec($spec);
101 1         17 return $self;
102             }
103              
104             sub add_http01_solver {
105 2     2 0 4 my ($self, %opts) = @_;
106 2   50     21 my $spec = $self->spec // {};
107 2   50     12 my $acme = $spec->{acme} //= {};
108 2   50     7 my $solvers = $acme->{solvers} //= [];
109 2         4 my $solver = { http01 => { ingress => {} } };
110 2 100       6 $solver->{http01}{ingress}{class} = $opts{class} if $opts{class};
111 2         3 push @$solvers, $solver;
112 2         23 $self->spec($spec);
113 2         29 return $self;
114             }
115              
116             sub add_dns01_solver {
117 1     1 0 4 my ($self, %opts) = @_;
118 1   50     11 my $spec = $self->spec // {};
119 1   50     7 my $acme = $spec->{acme} //= {};
120 1   50     11 my $solvers = $acme->{solvers} //= [];
121 1         2 my %dns01;
122 1 50       4 if ($opts{provider} eq 'cloudflare') {
    0          
123             $dns01{cloudflare} = {
124 1 50 50     9 $opts{secret} ? (apiTokenSecretRef => { name => $opts{secret}, key => $opts{key} // 'api-token' }) : (),
125             };
126             } elsif ($opts{provider} eq 'route53') {
127             $dns01{route53} = {
128 0 0       0 $opts{region} ? (region => $opts{region}) : (),
129             };
130             } else {
131 0         0 $dns01{$opts{provider}} = {};
132             }
133 1         3 push @$solvers, { dns01 => \%dns01 };
134 1         12 $self->spec($spec);
135 1         16 return $self;
136             }
137              
138             1;
139              
140             __END__