github.com/coreos/mantle@v0.13.0/sdk/omaha/generate.go (about)

     1  // Copyright 2015 CoreOS, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package omaha
    16  
    17  import (
    18  	"encoding/xml"
    19  	"fmt"
    20  	"os"
    21  	"os/exec"
    22  	"path/filepath"
    23  
    24  	"github.com/coreos/go-omaha/omaha"
    25  	"github.com/coreos/pkg/capnslog"
    26  
    27  	"github.com/coreos/mantle/sdk"
    28  )
    29  
    30  const (
    31  	privateKey = "/usr/share/update_engine/update-payload-key.key.pem"
    32  	publicKey  = "/usr/share/update_engine/update-payload-key.pub.pem"
    33  )
    34  
    35  var plog = capnslog.NewPackageLogger("github.com/coreos/mantle", "sdk/omaha")
    36  
    37  func run(name string, arg ...string) error {
    38  	cmd := exec.Command(name, arg...)
    39  	cmd.Stdout = os.Stdout
    40  	cmd.Stderr = os.Stderr
    41  	return cmd.Run()
    42  }
    43  
    44  func xmlMarshalFile(path string, v interface{}) error {
    45  	f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
    46  	if err != nil {
    47  		return err
    48  	}
    49  	defer f.Close()
    50  
    51  	if _, err := f.WriteString(xml.Header); err != nil {
    52  		return err
    53  	}
    54  
    55  	enc := xml.NewEncoder(f)
    56  	enc.Indent("", "  ")
    57  	return enc.Encode(v)
    58  }
    59  
    60  func xmlUnmarshalFile(path string, v interface{}) error {
    61  	f, err := os.Open(path)
    62  	if err != nil {
    63  		return err
    64  	}
    65  	defer f.Close()
    66  
    67  	return xml.NewDecoder(f).Decode(v)
    68  }
    69  
    70  func checkUpdate(dir, update_xml string) error {
    71  	u := omaha.Update{}
    72  	if err := xmlUnmarshalFile(update_xml, &u); err != nil {
    73  		return err
    74  	}
    75  
    76  	if len(u.Packages) != 1 {
    77  		return fmt.Errorf("%s contains %d packages, expected 1",
    78  			update_xml, len(u.Packages))
    79  	}
    80  
    81  	pkgdir := filepath.Join(dir, u.URL.CodeBase)
    82  	return u.Packages[0].Verify(pkgdir)
    83  }
    84  
    85  func GenerateFullUpdate(dir string) error {
    86  	var (
    87  		update_prefix = filepath.Join(dir, "coreos_production_update")
    88  		update_bin    = update_prefix + ".bin"
    89  		update_gz     = update_prefix + ".gz"
    90  		update_xml    = update_prefix + ".xml"
    91  		vmlinuz       = filepath.Join(dir, "coreos_production_image.vmlinuz")
    92  	)
    93  
    94  	if err := checkUpdate(dir, update_xml); err == nil {
    95  		plog.Infof("Using update manifest: %s", update_xml)
    96  		return nil
    97  	}
    98  
    99  	plog.Noticef("Generating update payload: %s", update_gz)
   100  	if err := run("delta_generator",
   101  		"-new_image", update_bin,
   102  		"-new_kernel", vmlinuz,
   103  		"-out_file", update_gz,
   104  		"-private_key", privateKey); err != nil {
   105  		return err
   106  	}
   107  
   108  	plog.Infof("Writing update manifest: %s", update_xml)
   109  	update := omaha.Update{ID: sdk.GetDefaultAppId()}
   110  	pkg, err := update.AddPackageFromPath(update_gz)
   111  	if err != nil {
   112  		return err
   113  	}
   114  
   115  	// update engine needs the payload hash here in the action element
   116  	postinstall := update.AddAction("postinstall")
   117  	postinstall.SHA256 = pkg.SHA256
   118  
   119  	if ver, err := sdk.VersionsFromDir(dir); err != nil {
   120  		return err
   121  	} else {
   122  		update.Version = ver.Version
   123  	}
   124  
   125  	return xmlMarshalFile(update_xml, &update)
   126  }