29
29
from oras .schemas import manifest as oras_manifest_schema
30
30
31
31
from gardenlinux .features import Parser
32
- from ..constants import OCI_ANNOTATION_SIGNATURE_KEY , OCI_ANNOTATION_SIGNED_STRING_KEY
32
+ from ..constants import (
33
+ OCI_ANNOTATION_SIGNATURE_KEY ,
34
+ OCI_ANNOTATION_SIGNED_STRING_KEY ,
35
+ GL_USER_AGENT_REGISTRY ,
36
+ )
33
37
from .checksum import (
34
38
calculate_sha256 ,
35
39
verify_sha256 ,
@@ -670,40 +674,59 @@ def push_from_dir(
670
674
cname : str ,
671
675
directory : str ,
672
676
manifest_file : str ,
673
- commit : Optional [ str ] = None ,
677
+ additional_tags : list = None ,
674
678
):
675
- # Step 1 scan and extract nested artifacts:
676
- for file in os .listdir (directory ):
677
- try :
678
- if file .endswith (".pxe.tar.gz" ):
679
- logger .info (f"Found nested artifact { file } " )
680
- nested_tar_obj = tarfile .open (f"{ directory } /{ file } " )
681
- nested_tar_obj .extractall (filter = "data" , path = directory )
682
- nested_tar_obj .close ()
683
- except (OSError , tarfile .FilterError , tarfile .TarError ) as e :
684
- print (f"Failed to extract nested artifact { file } " , e )
685
- exit (1 )
679
+ """
680
+ Push artifacts from a directory to a registry
681
+
682
+ Args:
683
+ architecture: Target architecture of the image
684
+ version: Version tag for the image
685
+ cname: Canonical name of the image
686
+ directory: Directory containing the artifacts
687
+ manifest_file: File to write the manifest index entry to
688
+ additional_tags: Additional tags to push the manifest with
689
+
690
+ Returns:
691
+ The digest of the pushed manifest
692
+ """
693
+ if additional_tags is None :
694
+ additional_tags = []
686
695
687
696
try :
697
+ # scan and extract nested artifacts
698
+ for file in os .listdir (directory ):
699
+ try :
700
+ if file .endswith (".pxe.tar.gz" ):
701
+ logger .info (f"Found nested artifact { file } " )
702
+ nested_tar_obj = tarfile .open (f"{ directory } /{ file } " )
703
+ nested_tar_obj .extractall (filter = "data" , path = directory )
704
+ nested_tar_obj .close ()
705
+ except (OSError , tarfile .FilterError , tarfile .TarError ) as e :
706
+ print (f"Failed to extract nested artifact { file } " , e )
707
+ exit (1 )
708
+
709
+ # Get metadata from files
688
710
oci_metadata = get_oci_metadata_from_fileset (
689
711
os .listdir (directory ), architecture
690
712
)
691
713
692
714
features = ""
715
+ commit = ""
693
716
for artifact in oci_metadata :
694
717
if artifact ["media_type" ] == "application/io.gardenlinux.release" :
695
- file = open (f"{ directory } /{ artifact ["file_name" ]} " , "r" )
696
- lines = file . readlines ()
697
- for line in lines :
698
- if line . strip () .startswith ("GARDENLINUX_FEATURES=" ):
699
- features = line .strip (). removeprefix (
700
- "GARDENLINUX_FEATURES="
701
- )
702
- break
703
- file . close ()
704
-
705
- flavor = Parser . get_flavor_from_cname ( cname , get_arch = True )
706
-
718
+ with open (f"{ directory } /{ artifact ["file_name" ]} " , "r" ) as file :
719
+ for line in file :
720
+ line = line . strip ()
721
+ if line .startswith ("GARDENLINUX_FEATURES=" ):
722
+ features = line .removeprefix ("GARDENLINUX_FEATURES=" )
723
+ elif line . startswith ( "GARDENLINUX_COMMIT_ID=" ):
724
+ commit = line . removeprefix ( "GARDENLINUX_COMMIT_ID=" )
725
+ if features and commit : # Break if both values are found
726
+ break
727
+ break # Break after processing the release file
728
+
729
+ # Push the image manifest
707
730
digest = self .push_image_manifest (
708
731
architecture ,
709
732
cname ,
@@ -714,7 +737,103 @@ def push_from_dir(
714
737
manifest_file ,
715
738
commit = commit ,
716
739
)
740
+
741
+ # Process additional tags if provided
742
+ if additional_tags and len (additional_tags ) > 0 :
743
+ print (f"DEBUG: Processing { len (additional_tags )} additional tags" )
744
+ logger .info (f"Processing { len (additional_tags )} additional tags" )
745
+
746
+ self .push_additional_tags_manifest (
747
+ architecture ,
748
+ cname ,
749
+ version ,
750
+ additional_tags ,
751
+ container = self .container ,
752
+ )
753
+
754
+ return digest
717
755
except Exception as e :
718
756
print ("Error: " , e )
719
757
exit (1 )
720
- return digest
758
+
759
+ def push_additional_tags_manifest (
760
+ self , architecture , cname , version , additional_tags , container
761
+ ):
762
+ """
763
+ Push additional tags for an existing manifest using ORAS Registry methods
764
+
765
+ Args:
766
+ architecture: Target architecture of the image
767
+ cname: Canonical name of the image
768
+ version: Version tag for the image
769
+ additional_tags: List of additional tags to push
770
+ container: Container object
771
+ """
772
+ try :
773
+ # Source tag is the tag containing the version-cname-architecture combination
774
+ source_tag = f"{ version } -{ cname } -{ architecture } "
775
+ source_container = copy .deepcopy (container )
776
+ source_container .tag = source_tag
777
+
778
+ # Authentication credentials from environment
779
+ token = os .getenv ("GL_CLI_REGISTRY_TOKEN" )
780
+ username = os .getenv ("GL_CLI_REGISTRY_USERNAME" )
781
+ password = os .getenv ("GL_CLI_REGISTRY_PASSWORD" )
782
+
783
+ # Login to registry if credentials are provided
784
+ if username and password :
785
+ logger .debug (f"Logging in with username/password" )
786
+ try :
787
+ self .login (username , password )
788
+ except Exception as login_error :
789
+ logger .error (f"Login error: { str (login_error )} " )
790
+ elif token :
791
+ # If token is provided, set it directly on the Registry instance
792
+ logger .debug (f"Using token authentication" )
793
+ self .token = base64 .b64encode (token .encode ("utf-8" )).decode ("utf-8" )
794
+ self .auth .set_token_auth (self .token )
795
+
796
+ # Get the manifest from the source container
797
+ try :
798
+ logger .debug (f"Getting manifest from { source_container } " )
799
+ manifest = self .get_manifest (source_container )
800
+ if not manifest :
801
+ logger .error (f"Failed to get manifest for { source_container } " )
802
+ return
803
+ logger .info (
804
+ f"Successfully retrieved manifest: { manifest ['mediaType' ] if 'mediaType' in manifest else 'unknown' } "
805
+ )
806
+ except Exception as get_error :
807
+ logger .error (f"Error getting manifest: { str (get_error )} " )
808
+ return
809
+
810
+ # For each additional tag, push the manifest using Registry.upload_manifest
811
+ for tag in additional_tags :
812
+ try :
813
+ logger .debug (f"Pushing additional tag: { tag } " )
814
+
815
+ # Create a new container for this tag
816
+ tag_container = copy .deepcopy (container )
817
+ tag_container .tag = tag
818
+
819
+ logger .debug (f"Pushing to container: { tag_container } " )
820
+
821
+ # Upload the manifest to the new tag
822
+ response = self .upload_manifest (manifest , tag_container )
823
+
824
+ if response and response .status_code in [200 , 201 ]:
825
+ logger .info (f"Successfully pushed tag { tag } for manifest" )
826
+ else :
827
+ status_code = getattr (response , "status_code" , "unknown" )
828
+ response_text = getattr (response , "text" , "No response text" )
829
+ logger .error (
830
+ f"Failed to push tag { tag } for manifest: { status_code } "
831
+ )
832
+
833
+ except Exception as tag_error :
834
+ logger .error (
835
+ f"Error pushing tag { tag } for manifest: { str (tag_error )} "
836
+ )
837
+
838
+ except Exception as e :
839
+ logger .error (f"Error in push_additional_tags_manifest: { str (e )} " )
0 commit comments