File: imageSource.py

package info (click to toggle)
subuser 0.6.2-3
  • links: PTS
  • area: main
  • in suites: bookworm, bullseye, buster, forky, sid, trixie
  • size: 4,208 kB
  • sloc: python: 5,201; sh: 380; makefile: 73
file content (206 lines) | stat: -rwxr-xr-x 8,356 bytes parent folder | download
1
2
3
4
5
6
7
8
9
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
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
# -*- coding: utf-8 -*-

"""
Images in subuser are built from ImageSource objects.
"""

#external imports
import os
import uuid
from collections import OrderedDict
#internal imports
from subuserlib.classes.userOwnedObject import UserOwnedObject
from subuserlib.classes.describable import Describable
import subuserlib.permissions
import subuserlib.docker
import subuserlib.classes.docker.dockerDaemon as dockerDaemon
import subuserlib.classes.exceptions as exceptions
import subuserlib.print

class ImageSource(UserOwnedObject,Describable):
  def __init__(self,user,repo,name,explicitConfig=None):
    self.name = name
    self.repo = repo
    self.__permissions = None
    self.__explicitConfig = explicitConfig
    UserOwnedObject.__init__(self,user)

  def __hash__(self):
    return hash(self.getIdentifier())

  def getIdentifier(self):
    """
    Return a standard human readable identifier for an ImageSource.
    """
    return self.name + "@" + self.repo.displayName

  def serializeToDict(self):
    return OrderedDict(
        [("name", self.name)
        ,("repo", self.repo.displayName)
        ,("identifier",self.getIdentifier())
        ,("permissions",self.permissions)
        ,("installed-images",self.installedImagesDict)
        ,("latest-installed-image",self.getLatestInstalledImage().imageId)])

  def getDockerImageTag(self):
    longTag = "subuser-" + self.user.endUser.name + "-" + self.getIdentifier()
    return subuserlib.docker.buildImageTag(longTag,self.getHash())

  def getSubusers(self):
    """
     Get a list of subusers that were built from this ImageSource.
    """
    subusers = []
    for subuser in self.user.registry.subusers:
      if subuser.imageSource==self:
        subusers.append(subuser)
    return subusers

  def getImageDir(self):
    if self.__explicitConfig:
      return self.__explicitConfig["build-context"]
    imageDir = os.path.join(self.getRelativeSourceDir(),"image")
    # If the image dir does not exist,
    # Look for the old, deprecated, docker-image dir
    if not self.repo.fileStructure.exists(imageDir):
      imageDir = os.path.join(self.getRelativeSourceDir(),"docker-image")
      if not self.repo.fileStructure.exists(imageDir):
        raise exceptions.ImageBuildException("Image source "+self.getIdentifier()+ " does not have an image dir with sources from which to build.")
    return imageDir

  def getSourceDir(self):
    return os.path.join(self.repo.imageSourcesDir,self.name)

  def getRelativeSourceDir(self):
    return os.path.join(self.repo.relativeImageSourcesDir,self.name)

  def getLatestInstalledImage(self):
    """
    Get the most up-to-date InstalledImage based on this ImageSource.
    Returns None if no images have been installed from this ImageSource.
    """
    imageCreationDateTimeBestSoFar=''
    mostUpToDateImage = None
    for installedImage in self.installedImages:
      thisImagesCreationDateTime = installedImage.getCreationDateTime()
      if thisImagesCreationDateTime > imageCreationDateTimeBestSoFar:
        mostUpToDateImage = installedImage
        imageCreationDateTimeBestSoFar = thisImagesCreationDateTime
    return mostUpToDateImage

  @property
  def installedImages(self):
    """
    Return the installed images which are based on this image.
    """
    installedImagesBasedOnThisImageSource = []
    for _,installedImage in self.user.installedImages.items():
      if installedImage.imageSourceName == self.name and installedImage.sourceRepoId == self.repo.name:
        installedImagesBasedOnThisImageSource.append(installedImage)
    return installedImagesBasedOnThisImageSource

  @property
  def installedImagesDict(self):
    dict = OrderedDict()
    for image in self.installedImages:
      dict[image.imageId] = image.serializeToDict()
    return dict

  def getPermissionsFilePath(self):
    relativePath = self.getRelativePermissionsFilePath()
    return os.path.join(self.repo.repoPath,relativePath)

  def getRelativePermissionsFilePath(self):
    if self.__explicitConfig is not None:
      return self.__explicitConfig["permissions-file"]
    if "dependent" in self.getRelativeSourceDir():
      raise Exception(str(self.__explicitConfig)+"\n"+self.name+str(self.repo.keys()))
    return os.path.join(self.getRelativeSourceDir(),"permissions.json")

  @property
  def permissions(self):
    if not self.__permissions:
      permissionsString = self.repo.fileStructure.read(self.getRelativePermissionsFilePath())
      initialPermissions = subuserlib.permissions.load(permissionsString=permissionsString,logger=self.user.registry)
      self.__permissions = subuserlib.classes.permissions.Permissions(self.user,initialPermissions,writePath=self.getPermissionsFilePath())
    return self.__permissions

  def description(self,rst=False):
    if rst:
      description = self.getIdentifier().replace("@","\\@") + "\n"
      description += "-"*len(self.getIdentifier()) + "\n\n"
    else:
      description = self.getIdentifier() + "\n"
    description += "To install this image run:" + (":\n\n" if rst else "\n")
    description += "   subuser subuser add <subuser-name> "+self.getIdentifier()+"\n\n"
    return description

  def describe(self,rst=False):
    """
    Describe this ImageSource including it's default permissions.

    Prints to standard output.
    """
    subuserlib.print.printWithoutCrashing(self.description(rst=rst))
    self.permissions.describe(rst=rst)

  def build(self,parent,useCache=False):
    imageFileType = self.getImageFileType()
    if imageFileType == "Dockerfile":
      dockerfileContents = self.getImageFileContents()
    elif imageFileType == "SubuserImagefile":
      subuserImagefileContents = self.getImageFileContents()
      dockerfileContents = ""
      for line in subuserImagefileContents.split("\n"):
        if line.startswith("FROM-SUBUSER-IMAGE"):
          dockerfileContents = "FROM " + parent + "\n"
        else:
          dockerfileContents += line + "\n"
    imageId = self.user.dockerDaemon.build(relativeBuildContextPath=self.getImageDir(),repositoryFileStructure=self.repo.fileStructure,rm=True,dockerfile=dockerfileContents,useCache=useCache)
    subuserSetupDockerFile = ""
    subuserSetupDockerFile += "FROM "+imageId+"\n"
    subuserSetupDockerFile += "RUN mkdir -p /subuser ; echo "+str(uuid.uuid4())+" > /subuser/uuid\n" # This ensures that all images have unique Ids.  Even images that are otherwise the same.
    return self.user.dockerDaemon.build(dockerfile=subuserSetupDockerFile,tag=self.getDockerImageTag(),useCache=False)

  def getImageFile(self):
    if self.__explicitConfig:
      return self.__explicitConfig["image-file"]
    dockerfilePath = os.path.join(self.getImageDir(),"Dockerfile")
    if self.repo.fileStructure.exists(dockerfilePath):
      return dockerfilePath
    subuserImagefilePath = os.path.join(self.getImageDir(),"SubuserImagefile")
    if self.repo.fileStructure.exists(subuserImagefilePath):
      return subuserImagefilePath

  def getImageFileType(self):
    return os.path.basename(self.getImageFile())

  def getImageFileContents(self):
    return self.repo.fileStructure.read(self.getImageFile())

  def getDependency(self):
    """
     Returns the dependency of this ImageSource as a ImageSource.
     Or None if there is no dependency.
    """
    if not self.getImageFileType() == "SubuserImagefile":
      return None
    subuserImagefileContents = self.getImageFileContents()
    lineNumber=0
    for line in subuserImagefileContents.split("\n"):
      if line.startswith("FROM-SUBUSER-IMAGE"):
        try:
          import subuserlib.resolve
          imageURI = line.split(" ")[1]
          return subuserlib.resolve.resolveImageSource(self.user,imageURI,contextRepository=self.repo,allowLocalRepositories=False) #TODO, ImageSource names with spaces or other funny characters...
        except IndexError:
          raise exceptions.ImageBuildException("Syntax error in SubuserImagefile one line "+str(lineNumber)+":\n"+line)
        except KeyError:
          raise exceptions.ImageBuildException("Error in "+self.name+"'s SubuserImagefile on line "+str(lineNumber)+"\n Subuser image does not exist: \""+imageURI+"\"")
      lineNumber+=1
    return None

  def getHash(self):
    """ Return the hash of the ``image`` directory. """
    return self.repo.fileStructure.hash(self.getImageDir())