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 }