github.com/Cloud-Foundations/Dominator@v0.3.4/cmd/imagetool/addReplaceImage.go (about)

     1  package main
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"os"
     7  	"strconv"
     8  	"strings"
     9  
    10  	"github.com/Cloud-Foundations/Dominator/imageserver/client"
    11  	"github.com/Cloud-Foundations/Dominator/lib/filesystem"
    12  	"github.com/Cloud-Foundations/Dominator/lib/log"
    13  	objectclient "github.com/Cloud-Foundations/Dominator/lib/objectserver/client"
    14  	"github.com/Cloud-Foundations/Dominator/lib/srpc"
    15  )
    16  
    17  func addReplaceImageSubcommand(args []string, logger log.DebugLogger) error {
    18  	imageSClient, objectClient := getClients()
    19  	err := addReplaceImage(imageSClient, objectClient, args[0], args[1],
    20  		args[2:], logger)
    21  	if err != nil {
    22  		return fmt.Errorf("error adding image: \"%s\": %s", args[0], err)
    23  	}
    24  	return nil
    25  }
    26  
    27  func bulkAddReplaceImagesSubcommand(args []string,
    28  	logger log.DebugLogger) error {
    29  	imageSClient, objectClient := getClients()
    30  	err := bulkAddReplaceImages(imageSClient, objectClient, args, logger)
    31  	if err != nil {
    32  		return fmt.Errorf("error adding image: \"%s\": %s", args[0], err)
    33  	}
    34  	return nil
    35  }
    36  
    37  func addReplaceImage(imageSClient *srpc.Client,
    38  	objectClient *objectclient.ObjectClient,
    39  	name, baseImageName string, layerImageNames []string,
    40  	logger log.DebugLogger) error {
    41  	imageExists, err := client.CheckImage(imageSClient, name)
    42  	if err != nil {
    43  		return errors.New("error checking for image existence: " + err.Error())
    44  	}
    45  	if imageExists {
    46  		return errors.New("image exists")
    47  	}
    48  	newImage, err := getTypedImage(baseImageName)
    49  	if err != nil {
    50  		return err
    51  	}
    52  	if !newImage.ExpiresAt.IsZero() {
    53  		fmt.Fprintf(os.Stderr, "Skipping expiring image: %s\n", baseImageName)
    54  		return nil
    55  	}
    56  	for _, layerImageName := range layerImageNames {
    57  		fs, err := buildImage(imageSClient, newImage.Filter, layerImageName,
    58  			logger)
    59  		if err != nil {
    60  			return err
    61  		}
    62  		if err := layerImages(newImage.FileSystem, fs); err != nil {
    63  			return err
    64  		}
    65  	}
    66  	if err := spliceComputedFiles(newImage.FileSystem); err != nil {
    67  		return err
    68  	}
    69  	return addImage(imageSClient, name, newImage, logger)
    70  }
    71  
    72  func bulkAddReplaceImages(imageSClient *srpc.Client,
    73  	objectClient *objectclient.ObjectClient, layerImageNames []string,
    74  	logger log.DebugLogger) error {
    75  	imageNames, err := client.ListImages(imageSClient)
    76  	if err != nil {
    77  		return err
    78  	}
    79  	err = bulkAddReplaceImagesSep(imageSClient, objectClient, layerImageNames,
    80  		imageNames, "/", logger)
    81  	if err != nil {
    82  		return err
    83  	}
    84  	return bulkAddReplaceImagesSep(imageSClient, objectClient, layerImageNames,
    85  		imageNames, ".", logger)
    86  }
    87  
    88  func bulkAddReplaceImagesSep(imageSClient *srpc.Client,
    89  	objectClient *objectclient.ObjectClient, layerImageNames []string,
    90  	imageNames []string, separator string, logger log.DebugLogger) error {
    91  	baseNames := make(map[string]uint64)
    92  	for _, name := range imageNames {
    93  		fields := strings.Split(name, separator)
    94  		nFields := len(fields)
    95  		if nFields < 2 {
    96  			continue
    97  		}
    98  		lastField := fields[nFields-1]
    99  		if version, err := strconv.ParseUint(lastField, 10, 64); err != nil {
   100  			continue
   101  		} else {
   102  			name := strings.Join(fields[:nFields-1], separator)
   103  			if oldVersion := baseNames[name]; version >= oldVersion {
   104  				baseNames[name] = version
   105  			}
   106  		}
   107  	}
   108  	for baseName, version := range baseNames {
   109  		oldName := fmt.Sprintf("%s%s%d", baseName, separator, version)
   110  		newName := fmt.Sprintf("%s%s%d", baseName, separator, version+1)
   111  		err := addReplaceImage(imageSClient, objectClient, newName, oldName,
   112  			layerImageNames, logger)
   113  		if err != nil {
   114  			return err
   115  		}
   116  	}
   117  	return nil
   118  }
   119  
   120  func layerImages(baseFS *filesystem.FileSystem,
   121  	layerFS *filesystem.FileSystem) error {
   122  	for filename, layerInum := range layerFS.FilenameToInodeTable() {
   123  		layerInode := layerFS.InodeTable[layerInum]
   124  		if _, ok := layerInode.(*filesystem.DirectoryInode); ok {
   125  			continue
   126  		}
   127  		baseInum, ok := baseFS.FilenameToInodeTable()[filename]
   128  		if !ok {
   129  			return errors.New(filename + " missing in base image")
   130  		}
   131  		baseInode := baseFS.InodeTable[baseInum]
   132  		sameType, sameMetadata, sameData := filesystem.CompareInodes(baseInode,
   133  			layerInode, nil)
   134  		if !sameType {
   135  			return errors.New(filename + " changed type")
   136  		}
   137  		if sameMetadata && sameData {
   138  			continue
   139  		}
   140  		baseFS.InodeTable[baseInum] = layerInode
   141  	}
   142  	return nil
   143  }