github.com/mitchellh/packer@v1.3.2/builder/azure/arm/artifact.go (about)

     1  package arm
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"net/url"
     7  	"path"
     8  	"strings"
     9  )
    10  
    11  const (
    12  	BuilderId = "Azure.ResourceManagement.VMImage"
    13  )
    14  
    15  type AdditionalDiskArtifact struct {
    16  	AdditionalDiskUri            string
    17  	AdditionalDiskUriReadOnlySas string
    18  }
    19  
    20  type Artifact struct {
    21  	// OS type: Linux, Windows
    22  	OSType string
    23  
    24  	// VHD
    25  	StorageAccountLocation string
    26  	OSDiskUri              string
    27  	TemplateUri            string
    28  	OSDiskUriReadOnlySas   string
    29  	TemplateUriReadOnlySas string
    30  
    31  	// Managed Image
    32  	ManagedImageResourceGroupName string
    33  	ManagedImageName              string
    34  	ManagedImageLocation          string
    35  	ManagedImageId                string
    36  
    37  	// Additional Disks
    38  	AdditionalDisks *[]AdditionalDiskArtifact
    39  }
    40  
    41  func NewManagedImageArtifact(osType, resourceGroup, name, location, id string) (*Artifact, error) {
    42  	return &Artifact{
    43  		ManagedImageResourceGroupName: resourceGroup,
    44  		ManagedImageName:              name,
    45  		ManagedImageLocation:          location,
    46  		ManagedImageId:                id,
    47  		OSType:                        osType,
    48  	}, nil
    49  }
    50  
    51  func NewArtifact(template *CaptureTemplate, getSasUrl func(name string) string, osType string) (*Artifact, error) {
    52  	if template == nil {
    53  		return nil, fmt.Errorf("nil capture template")
    54  	}
    55  
    56  	if len(template.Resources) != 1 {
    57  		return nil, fmt.Errorf("malformed capture template, expected one resource")
    58  	}
    59  
    60  	vhdUri, err := url.Parse(template.Resources[0].Properties.StorageProfile.OSDisk.Image.Uri)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	templateUri, err := storageUriToTemplateUri(vhdUri)
    66  	if err != nil {
    67  		return nil, err
    68  	}
    69  
    70  	var additional_disks *[]AdditionalDiskArtifact
    71  	if template.Resources[0].Properties.StorageProfile.DataDisks != nil {
    72  		data_disks := make([]AdditionalDiskArtifact, len(template.Resources[0].Properties.StorageProfile.DataDisks))
    73  		for i, additionaldisk := range template.Resources[0].Properties.StorageProfile.DataDisks {
    74  			additionalVhdUri, err := url.Parse(additionaldisk.Image.Uri)
    75  			if err != nil {
    76  				return nil, err
    77  			}
    78  			data_disks[i].AdditionalDiskUri = additionalVhdUri.String()
    79  			data_disks[i].AdditionalDiskUriReadOnlySas = getSasUrl(getStorageUrlPath(additionalVhdUri))
    80  		}
    81  		additional_disks = &data_disks
    82  	}
    83  
    84  	return &Artifact{
    85  		OSType:                 osType,
    86  		OSDiskUri:              vhdUri.String(),
    87  		OSDiskUriReadOnlySas:   getSasUrl(getStorageUrlPath(vhdUri)),
    88  		TemplateUri:            templateUri.String(),
    89  		TemplateUriReadOnlySas: getSasUrl(getStorageUrlPath(templateUri)),
    90  
    91  		AdditionalDisks: additional_disks,
    92  
    93  		StorageAccountLocation: template.Resources[0].Location,
    94  	}, nil
    95  }
    96  
    97  func getStorageUrlPath(u *url.URL) string {
    98  	parts := strings.Split(u.Path, "/")
    99  	return strings.Join(parts[3:], "/")
   100  }
   101  
   102  func storageUriToTemplateUri(su *url.URL) (*url.URL, error) {
   103  	// packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> 4085bb15-3644-4641-b9cd-f575918640b4
   104  	filename := path.Base(su.Path)
   105  	parts := strings.Split(filename, ".")
   106  
   107  	if len(parts) < 3 {
   108  		return nil, fmt.Errorf("malformed URL")
   109  	}
   110  
   111  	// packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd -> packer
   112  	prefixParts := strings.Split(parts[0], "-")
   113  	prefix := strings.Join(prefixParts[:len(prefixParts)-1], "-")
   114  
   115  	templateFilename := fmt.Sprintf("%s-vmTemplate.%s.json", prefix, parts[1])
   116  
   117  	// https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-osDisk.4085bb15-3644-4641-b9cd-f575918640b4.vhd"
   118  	//   ->
   119  	// https://storage.blob.core.windows.net/system/Microsoft.Compute/Images/images/packer-vmTemplate.4085bb15-3644-4641-b9cd-f575918640b4.json"
   120  	return url.Parse(strings.Replace(su.String(), filename, templateFilename, 1))
   121  }
   122  
   123  func (a *Artifact) isManagedImage() bool {
   124  	return a.ManagedImageResourceGroupName != ""
   125  }
   126  
   127  func (*Artifact) BuilderId() string {
   128  	return BuilderId
   129  }
   130  
   131  func (*Artifact) Files() []string {
   132  	return []string{}
   133  }
   134  
   135  func (a *Artifact) Id() string {
   136  	if a.OSDiskUri != "" {
   137  		return a.OSDiskUri
   138  	}
   139  	return a.ManagedImageId
   140  }
   141  
   142  func (a *Artifact) State(name string) interface{} {
   143  	switch name {
   144  	case "atlas.artifact.metadata":
   145  		return a.stateAtlasMetadata()
   146  	default:
   147  		return nil
   148  	}
   149  }
   150  
   151  func (a *Artifact) String() string {
   152  	var buf bytes.Buffer
   153  
   154  	buf.WriteString(fmt.Sprintf("%s:\n\n", a.BuilderId()))
   155  	buf.WriteString(fmt.Sprintf("OSType: %s\n", a.OSType))
   156  	if a.isManagedImage() {
   157  		buf.WriteString(fmt.Sprintf("ManagedImageResourceGroupName: %s\n", a.ManagedImageResourceGroupName))
   158  		buf.WriteString(fmt.Sprintf("ManagedImageName: %s\n", a.ManagedImageName))
   159  		buf.WriteString(fmt.Sprintf("ManagedImageId: %s\n", a.ManagedImageId))
   160  		buf.WriteString(fmt.Sprintf("ManagedImageLocation: %s\n", a.ManagedImageLocation))
   161  	} else {
   162  		buf.WriteString(fmt.Sprintf("StorageAccountLocation: %s\n", a.StorageAccountLocation))
   163  		buf.WriteString(fmt.Sprintf("OSDiskUri: %s\n", a.OSDiskUri))
   164  		buf.WriteString(fmt.Sprintf("OSDiskUriReadOnlySas: %s\n", a.OSDiskUriReadOnlySas))
   165  		buf.WriteString(fmt.Sprintf("TemplateUri: %s\n", a.TemplateUri))
   166  		buf.WriteString(fmt.Sprintf("TemplateUriReadOnlySas: %s\n", a.TemplateUriReadOnlySas))
   167  		if a.AdditionalDisks != nil {
   168  			for i, additionaldisk := range *a.AdditionalDisks {
   169  				buf.WriteString(fmt.Sprintf("AdditionalDiskUri (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUri))
   170  				buf.WriteString(fmt.Sprintf("AdditionalDiskUriReadOnlySas (datadisk-%d): %s\n", i+1, additionaldisk.AdditionalDiskUriReadOnlySas))
   171  			}
   172  		}
   173  	}
   174  
   175  	return buf.String()
   176  }
   177  
   178  func (*Artifact) Destroy() error {
   179  	return nil
   180  }
   181  
   182  func (a *Artifact) stateAtlasMetadata() interface{} {
   183  	metadata := make(map[string]string)
   184  	metadata["StorageAccountLocation"] = a.StorageAccountLocation
   185  	metadata["OSDiskUri"] = a.OSDiskUri
   186  	metadata["OSDiskUriReadOnlySas"] = a.OSDiskUriReadOnlySas
   187  	metadata["TemplateUri"] = a.TemplateUri
   188  	metadata["TemplateUriReadOnlySas"] = a.TemplateUriReadOnlySas
   189  
   190  	return metadata
   191  }