77 "time"
88
99 "github.com/go-logr/logr"
10+ "github.com/golang-jwt/jwt/v4"
1011 "github.com/metal-stack/duros-go"
1112 durosv2 "github.com/metal-stack/duros-go/api/duros/v2"
1213
@@ -38,6 +39,9 @@ const (
3839
3940 lbCSIControllerName = "lb-csi-controller"
4041 lbCSINodeName = "lb-csi-node"
42+
43+ tokenLifetime = 8 * 24 * time .Hour
44+ tokenRenewalBefore = 1 * 24 * time .Hour
4145)
4246
4347var (
@@ -728,15 +732,68 @@ var (
728732 }
729733)
730734
731- func (r * DurosReconciler ) deployStorageClassSecret (ctx context.Context , credential * durosv2.Credential , adminKey []byte ) error {
735+ func (r * DurosReconciler ) reconcileStorageClassSecret (ctx context.Context , credential * durosv2.Credential , adminKey []byte ) error {
736+ var (
737+ log = r .Log .WithName ("storage-class" )
738+ secret = & corev1.Secret {}
739+ )
740+
741+ key := types.NamespacedName {Name : storageClassCredentialsRef , Namespace : namespace }
742+ err := r .Shoot .Get (ctx , key , secret )
743+ if err != nil && apierrors .IsNotFound (err ) {
744+ log .Info ("deploy storage-class-secret" )
745+ return r .deployStorageClassSecret (ctx , log , credential , adminKey )
746+ }
747+ if err != nil {
748+ return fmt .Errorf ("unable to read secret: %w" , err )
749+ }
750+
751+ // secret already exists, check for renewal
752+ token , ok := secret .Data ["jwt" ]
753+ if ! ok {
754+ log .Error (fmt .Errorf ("no storage class token present in existing token" ), "recreating storage-class-secret" )
755+ err := r .deleteResourceWithWait (ctx , log , deletionResource {
756+ Key : key ,
757+ Object : secret ,
758+ })
759+ if err != nil {
760+ return err
761+ }
762+ return r .deployStorageClassSecret (ctx , log , credential , adminKey )
763+ }
764+
765+ claims := & jwt.StandardClaims {}
766+ _ , _ , err = new (jwt.Parser ).ParseUnverified (string (token ), claims )
767+ if err != nil {
768+ log .Error (err , "storage class token not parsable, recreating storage-class-secret" )
769+ err := r .deleteResourceWithWait (ctx , log , deletionResource {
770+ Key : key ,
771+ Object : secret ,
772+ })
773+ if err != nil {
774+ return err
775+ }
776+ return r .deployStorageClassSecret (ctx , log , credential , adminKey )
777+ }
778+
779+ expiresAt := time .Unix (claims .ExpiresAt , 0 )
780+ renewalAt := expiresAt .Add (- tokenRenewalBefore )
781+ if time .Now ().After (renewalAt ) {
782+ log .Info ("storage class token is expiring soon, refreshing token" , "expires-at" , expiresAt .String ())
783+ return r .deployStorageClassSecret (ctx , log , credential , adminKey )
784+ }
785+
786+ log .Info ("storage class token is not expiring soon, not doing anything" , "expires-at" , expiresAt .String (), "renewal-at" , renewalAt .String ())
787+
788+ return nil
789+ }
790+
791+ func (r * DurosReconciler ) deployStorageClassSecret (ctx context.Context , log logr.Logger , credential * durosv2.Credential , adminKey []byte ) error {
732792 key , err := extract (adminKey )
733793 if err != nil {
734794 return err
735795 }
736- log := r .Log .WithName ("storage-class" )
737- log .Info ("deploy storage-class-secret" )
738796
739- tokenLifetime := 360 * 24 * time .Hour
740797 token , err := duros .NewJWTTokenForCredential (r .Namespace , "duros-controller" , credential , []string {credential .ProjectName + ":admin" }, tokenLifetime , key )
741798 if err != nil {
742799 return fmt .Errorf ("unable to create jwt token:%w" , err )
@@ -754,9 +811,13 @@ func (r *DurosReconciler) deployStorageClassSecret(ctx context.Context, credenti
754811
755812 return nil
756813 })
814+ if err != nil {
815+ return err
816+ }
817+
757818 log .Info ("storageclasssecret" , "name" , storageClassCredentialsRef , "operation" , op )
758819
759- return err
820+ return nil
760821}
761822
762823func (r * DurosReconciler ) deployCSI (ctx context.Context , projectID string , scs []storagev1.StorageClass ) error {
0 commit comments