// Create is the wrapper method which covers all of the boilerplate around // actually creating, provisioning, and persisting an instance in the store. func (api *Client) Create(h *host.Host) error { if err := cert.BootstrapCertificates(h.AuthOptions()); err != nil { return fmt.Errorf("Error generating certificates: %s", err) } log.Info("Running pre-create checks...") if err := h.Driver.PreCreateCheck(); err != nil { return mcnerror.ErrDuringPreCreate{ Cause: err, } } if err := api.Save(h); err != nil { return fmt.Errorf("Error saving host to store before attempting creation: %s", err) } log.Info("Creating machine...") if err := api.performCreate(h); err != nil { return fmt.Errorf("Error creating machine: %s", err) } log.Debug("Reticulating splines...") return nil }
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { currentState, err := h.Driver.GetState() if err != nil { log.Errorf("error getting state for host %s: %s", h.Name, err) } url, err := h.GetURL() if err != nil { if err == drivers.ErrHostIsNotRunning { url = "" } else { log.Errorf("error getting URL for host %s: %s", h.Name, err) } } active, err := isActive(h) if err != nil { log.Errorf("error determining if host is active for host %s: %s", h.Name, err) } stateQueryChan <- HostListItem{ Name: h.Name, Active: active, DriverName: h.Driver.DriverName(), State: currentState, URL: url, SwarmOptions: h.HostOptions.SwarmOptions, } }
func engineExecute(h *host.Host, line string) error { p := shellwords.NewParser() args, err := p.Parse(line) if err != nil { return err } url, err := h.GetURL() if err != nil { return err } args = append([]string{ "-H", url, "--tlscacert=" + h.HostOptions.AuthOptions.CaCertPath, "--tlscert=" + h.HostOptions.AuthOptions.ClientCertPath, "--tlskey=" + h.HostOptions.AuthOptions.ClientKeyPath, "--tlsverify=true"}, args...) cmd := exec.Command(os.Args[0], args...) log.Debugf("[engineExecute] Executing: %s", cmd) b, err := cmd.CombinedOutput() if err != nil { fmt.Print(string(b)) return err } return nil }
func (s Filestore) Save(host *host.Host) error { if serialDriver, ok := host.Driver.(*drivers.SerialDriver); ok { // Unwrap Driver host.Driver = serialDriver.Driver // Re-wrap Driver when done defer func() { host.Driver = serialDriver }() } // TODO: Does this belong here? if rpcClientDriver, ok := host.Driver.(*rpcdriver.RPCClientDriver); ok { data, err := rpcClientDriver.GetConfigRaw() if err != nil { return fmt.Errorf("Error getting raw config for driver: %s", err) } host.RawDriver = data } data, err := json.MarshalIndent(host, "", " ") if err != nil { return err } hostPath := filepath.Join(s.getMachinesDir(), host.Name) // Ensure that the directory we want to save to exists. if err := os.MkdirAll(hostPath, 0700); err != nil { return err } return s.saveToFile(data, filepath.Join(hostPath, "config.json")) }
// IsActive provides a single function for determining if a host is active // based on both the url and if the host is stopped. func isActive(h *host.Host) (bool, error) { currentState, err := h.Driver.GetState() if err != nil { log.Errorf("error getting state for host %s: %s", h.Name, err) return false, err } url, err := h.GetURL() if err != nil { if err == drivers.ErrHostIsNotRunning { url = "" } else { log.Errorf("error getting URL for host %s: %s", h.Name, err) return false, err } } dockerHost := os.Getenv("DOCKER_HOST") notStopped := currentState != state.Stopped correctURL := url == dockerHost isActive := notStopped && correctURL return isActive, nil }
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { url := "" hostError := "" currentState, err := h.Driver.GetState() if err == nil { url, err = h.GetURL() } if err != nil { hostError = err.Error() } if hostError == drivers.ErrHostIsNotRunning.Error() { hostError = "" } var swarmOptions *swarm.Options if h.HostOptions != nil { swarmOptions = h.HostOptions.SwarmOptions } stateQueryChan <- HostListItem{ Name: h.Name, Active: isActive(currentState, url), DriverName: h.Driver.DriverName(), State: currentState, URL: url, SwarmOptions: swarmOptions, Error: hostError, } }
func (s Filestore) loadConfig(h *host.Host) error { data, err := ioutil.ReadFile(filepath.Join(s.GetMachinesDir(), h.Name, "config.json")) if err != nil { return err } // Remember the machine name so we don't have to pass it through each // struct in the migration. name := h.Name migratedHost, migrationPerformed, err := host.MigrateHost(h, data) if err != nil { return fmt.Errorf("Error getting migrated host: %s", err) } *h = *migratedHost h.Name = name // If we end up performing a migration, we should save afterwards so we don't have to do it again on subsequent invocations. if migrationPerformed { if err := s.saveToFile(data, filepath.Join(s.GetMachinesDir(), h.Name, "config.json.bak")); err != nil { return fmt.Errorf("Error attempting to save backup after migration: %s", err) } if err := s.Save(h); err != nil { return fmt.Errorf("Error saving config after migration was performed: %s", err) } } return nil }
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { stateCh := make(chan state.State) urlCh := make(chan string) go func() { currentState, err := h.Driver.GetState() if err != nil { log.Errorf("error getting state for host %s: %s", h.Name, err) } stateCh <- currentState }() go func() { url, err := h.GetURL() if err != nil { if err.Error() == drivers.ErrHostIsNotRunning.Error() { url = "" } else { log.Errorf("error getting URL for host %s: %s", h.Name, err) } } urlCh <- url }() currentState := <-stateCh url := <-urlCh close(stateCh) close(urlCh) active, err := isActive(h, currentState, url) if err != nil { log.Errorf("error determining if host is active for host %s: %s", h.Name, err) } stateQueryChan <- HostListItem{ Name: h.Name, Active: active, DriverName: h.Driver.DriverName(), State: currentState, URL: url, SwarmOptions: h.HostOptions.SwarmOptions, } }
func attemptGetHostState(h *host.Host, stateQueryChan chan<- HostListItem) { url := "" hostError := "" dockerVersion := "Unknown" currentState, err := h.Driver.GetState() if err == nil { url, err = h.URL() } if err == nil { dockerVersion, err = h.DockerVersion() if err != nil { dockerVersion = "Unknown" } else { dockerVersion = fmt.Sprintf("v%s", dockerVersion) } } if err != nil { hostError = err.Error() } if hostError == drivers.ErrHostIsNotRunning.Error() { hostError = "" } var swarmOptions *swarm.Options var engineOptions *engine.Options if h.HostOptions != nil { swarmOptions = h.HostOptions.SwarmOptions engineOptions = h.HostOptions.EngineOptions } stateQueryChan <- HostListItem{ Name: h.Name, Active: isActive(currentState, url), DriverName: h.Driver.DriverName(), State: currentState, URL: url, SwarmOptions: swarmOptions, EngineOptions: engineOptions, DockerVersion: dockerVersion, Error: hostError, } }
func (f *fakeLibMachineAPI) Create(h *host.Host) error { if f.driverName == "amazonec2" { f.ec2Driver = h.Driver.(*amazonec2.Driver) } h.Driver = &fakedriver.Driver{ MockName: h.Name, MockState: state.Running, MockIP: "192.168.10.3", } f.Save(h) return nil }
// Create is the wrapper method which covers all of the boilerplate around // actually creating, provisioning, and persisting an instance in the store. func (api *Client) Create(h *host.Host) error { if err := cert.BootstrapCertificates(h.AuthOptions()); err != nil { return fmt.Errorf("Error generating certificates: %s", err) } log.Info("Running pre-create checks...") if err := h.Driver.PreCreateCheck(); err != nil { return mcnerror.ErrDuringPreCreate{err} } if err := api.Save(h); err != nil { return fmt.Errorf("Error saving host to store before attempting creation: %s", err) } log.Info("Creating machine...") if err := api.performCreate(h); err != nil { // Wait for all the logs to reach the client time.Sleep(2 * time.Second) vBoxLog := "" if h.DriverName == "virtualbox" { vBoxLog = filepath.Join(api.GetMachinesDir(), h.Name, h.Name, "Logs", "VBox.log") } return crashreport.CrashError{ Cause: err, Command: "Create", Context: "api.performCreate", DriverName: h.DriverName, LogFilePath: vBoxLog, } } log.Debug("Reticulating splines...") return nil }
func (ps PluginStore) Save(host *host.Host) error { if serialDriver, ok := host.Driver.(*drivers.SerialDriver); ok { // Unwrap Driver host.Driver = serialDriver.Driver // Re-wrap Driver when done defer func() { host.Driver = serialDriver }() } // TODO: Does this belong here? if rpcClientDriver, ok := host.Driver.(*rpcdriver.RPCClientDriver); ok { data, err := rpcClientDriver.GetConfigRaw() if err != nil { return fmt.Errorf("Error getting raw config for driver: %s", err) } host.RawDriver = data } return ps.Filestore.Save(host) }
func (mcc *MachineConnChecker) Check(h *host.Host, swarm bool) (string, *auth.Options, error) { dockerHost, err := h.Driver.GetURL() if err != nil { return "", &auth.Options{}, err } dockerURL := dockerHost if swarm { dockerURL, err = parseSwarm(dockerHost, h) if err != nil { return "", &auth.Options{}, err } } u, err := url.Parse(dockerURL) if err != nil { return "", &auth.Options{}, fmt.Errorf("Error parsing URL: %s", err) } authOptions := h.AuthOptions() if err := checkCert(u.Host, authOptions); err != nil { if swarm { // Connection to the swarm port cannot be checked. Maybe it's just the swarm containers that are down // TODO: check the containers and restart them // Let's check the non-swarm connection to give a better error message to the user. if _, _, err := mcc.Check(h, false); err == nil { return "", &auth.Options{}, ErrSwarmNotStarted } } return "", &auth.Options{}, fmt.Errorf("Error checking and/or regenerating the certs: %s", err) } return dockerURL, authOptions, nil }
func newMachine(h *host.Host) (*Machine, error) { rawDriver, err := json.Marshal(h.Driver) if err != nil { return nil, errors.Wrap(err, "failed to marshal host driver") } var driverData map[string]interface{} err = json.Unmarshal(rawDriver, &driverData) if err != nil { return nil, errors.Wrap(err, "failed to unmarshal host driver") } m := &Machine{ Base: &iaas.Machine{ Id: h.Name, Port: engine.DefaultPort, Protocol: "https", CustomData: driverData, CreationParams: map[string]string{ "driver": h.DriverName, }, }, Host: h, } address, err := h.Driver.GetIP() if err != nil { return m, errors.Wrap(err, "failed to retrive host ip") } m.Base.Address = address if h.AuthOptions() != nil { m.Base.CaCert, err = ioutil.ReadFile(h.AuthOptions().CaCertPath) if err != nil { return m, errors.Wrap(err, "failed to read host ca cert") } m.Base.ClientCert, err = ioutil.ReadFile(h.AuthOptions().ClientCertPath) if err != nil { return m, errors.Wrap(err, "failed to read host client cert") } m.Base.ClientKey, err = ioutil.ReadFile(h.AuthOptions().ClientKeyPath) if err != nil { return m, errors.Wrap(err, "failed to read host client key") } } return m, nil }
// PERFORMANCE: The code of this function is complicated because we try // to call the underlying drivers as less as possible to get the information // we need. func attemptGetHostItem(h *host.Host, stateQueryChan chan<- commands.HostListItem) { url := "" currentState := state.None dockerVersion := "Unknown" hostError := "" url, err := h.URL() // PERFORMANCE: if we have the url, it's ok to assume the host is running // This reduces the number of calls to the drivers if err == nil { if url != "" { currentState = state.Running } else { currentState, err = h.Driver.GetState() } } else { currentState, _ = h.Driver.GetState() } if err == nil && url != "" { // PERFORMANCE: Reuse the url instead of asking the host again. // This reduces the number of calls to the drivers dockerHost := &mcndockerclient.RemoteDocker{ HostURL: url, AuthOption: h.AuthOptions(), } dockerVersion, err = mcndockerclient.DockerVersion(dockerHost) if err != nil { dockerVersion = "Unknown" } else { dockerVersion = fmt.Sprintf("v%s", dockerVersion) } } if err != nil { hostError = err.Error() } if hostError == drivers.ErrHostIsNotRunning.Error() { hostError = "" } var swarmOptions *swarm.Options var engineOptions *engine.Options if h.HostOptions != nil { swarmOptions = h.HostOptions.SwarmOptions engineOptions = h.HostOptions.EngineOptions } isMaster := false swarmHost := "" if swarmOptions != nil { isMaster = swarmOptions.Master swarmHost = swarmOptions.Host } activeHost := isActive(currentState, url) activeSwarm := isSwarmActive(currentState, url, isMaster, swarmHost) active := "-" if activeHost { active = "*" } if activeSwarm { active = "* (swarm)" } stateQueryChan <- commands.HostListItem{ Name: h.Name, Active: active, ActiveHost: activeHost, ActiveSwarm: activeSwarm, DriverName: h.Driver.DriverName(), State: currentState, URL: url, SwarmOptions: swarmOptions, EngineOptions: engineOptions, DockerVersion: dockerVersion, Error: hostError, } }
func swarmManage(h *host.Host, image string, token string) error { provisioner, err := provision.DetectProvisioner(h.Driver) dockerDir := provisioner.GetDockerOptionsDir() authOptions := setRemoteAuthOptions(provisioner) url, err := h.GetURL() if err != nil { return err } retryCount := 0 retry: exec.Command(os.Args[0], []string{ "-H", url, "--tlscacert=" + h.HostOptions.AuthOptions.CaCertPath, "--tlscert=" + h.HostOptions.AuthOptions.ClientCertPath, "--tlskey=" + h.HostOptions.AuthOptions.ClientKeyPath, "--tlsverify=true", "rm", "-f", "swarm-manager"}...).Output() cmd := exec.Command(os.Args[0], []string{ "-H", url, "--tlscacert=" + h.HostOptions.AuthOptions.CaCertPath, "--tlscert=" + h.HostOptions.AuthOptions.ClientCertPath, "--tlskey=" + h.HostOptions.AuthOptions.ClientKeyPath, "--tlsverify=true", "run", "-d", "--restart=always", "--net=bridge", "--name", "swarm-manager", "-p", "3376:3376", "-v", dockerDir + ":" + dockerDir, image, "manage", "--tlsverify", "--tlscacert=" + authOptions.CaCertRemotePath, "--tlscert=" + authOptions.ServerCertRemotePath, "--tlskey=" + authOptions.ServerKeyRemotePath, "-H", "0.0.0.0:3376", token}...) err = cmd.Run() if err == nil { fmt.Printf("Manager '%s' started successfully...\n", h.Name) return nil } if _, ok := err.(*exec.ExitError); ok { retryCount++ if retryCount <= 5 { fmt.Printf("Failed to start manager. Retry: %d\n", retryCount) goto retry } // if s, ok := exiterr.Sys().(syscall.WaitStatus); ok { // if s.ExitCode == 8 { // goto retry // } // } } return err }