github.com/coreos/mantle@v0.13.0/platform/machine/packet/cluster.go (about) 1 // Copyright 2017 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 packet 16 17 import ( 18 "crypto/rand" 19 "fmt" 20 "os" 21 "path/filepath" 22 23 "github.com/coreos/mantle/platform" 24 "github.com/coreos/mantle/platform/api/packet" 25 "github.com/coreos/mantle/platform/conf" 26 ) 27 28 type cluster struct { 29 *platform.BaseCluster 30 flight *flight 31 sshKeyID string 32 } 33 34 func (pc *cluster) NewMachine(userdata *conf.UserData) (platform.Machine, error) { 35 conf, err := pc.RenderUserData(userdata, map[string]string{ 36 "$public_ipv4": "${COREOS_PACKET_IPV4_PUBLIC_0}", 37 "$private_ipv4": "${COREOS_PACKET_IPV4_PRIVATE_0}", 38 }) 39 if err != nil { 40 return nil, err 41 } 42 43 vmname := pc.vmname() 44 // Stream the console somewhere temporary until we have a machine ID 45 consolePath := filepath.Join(pc.RuntimeConf().OutputDir, "console-"+vmname+".txt") 46 var cons *console 47 var pcons packet.Console // need a nil interface value if unused 48 if pc.sshKeyID != "" { 49 // We can only read the console if Packet has our SSH key 50 f, err := os.OpenFile(consolePath, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0666) 51 if err != nil { 52 return nil, err 53 } 54 cons = &console{ 55 pc: pc, 56 f: f, 57 done: make(chan interface{}), 58 } 59 pcons = cons 60 } 61 62 // CreateDevice unconditionally closes console when done with it 63 device, err := pc.flight.api.CreateDevice(vmname, conf, pcons) 64 if err != nil { 65 return nil, err 66 } 67 68 mach := &machine{ 69 cluster: pc, 70 device: device, 71 console: cons, 72 } 73 mach.publicIP = pc.flight.api.GetDeviceAddress(device, 4, true) 74 mach.privateIP = pc.flight.api.GetDeviceAddress(device, 4, false) 75 if mach.publicIP == "" || mach.privateIP == "" { 76 mach.Destroy() 77 return nil, fmt.Errorf("couldn't find IP addresses for device") 78 } 79 80 dir := filepath.Join(pc.RuntimeConf().OutputDir, mach.ID()) 81 if err := os.Mkdir(dir, 0777); err != nil { 82 mach.Destroy() 83 return nil, err 84 } 85 86 if cons != nil { 87 if err := os.Rename(consolePath, filepath.Join(dir, "console.txt")); err != nil { 88 mach.Destroy() 89 return nil, err 90 } 91 } 92 93 confPath := filepath.Join(dir, "user-data") 94 if err := conf.WriteFile(confPath); err != nil { 95 mach.Destroy() 96 return nil, err 97 } 98 99 if mach.journal, err = platform.NewJournal(dir); err != nil { 100 mach.Destroy() 101 return nil, err 102 } 103 104 if err := platform.StartMachine(mach, mach.journal); err != nil { 105 mach.Destroy() 106 return nil, err 107 } 108 109 pc.AddMach(mach) 110 111 return mach, nil 112 } 113 114 func (pc *cluster) vmname() string { 115 b := make([]byte, 5) 116 rand.Read(b) 117 return fmt.Sprintf("%s-%x", pc.Name()[0:13], b) 118 } 119 120 func (pc *cluster) Destroy() { 121 pc.BaseCluster.Destroy() 122 pc.flight.DelCluster(pc) 123 }