func main() { config.Initialize() leverutil.UpdateLoggingSettings() as, err := store.NewAerospike() if err != nil { logger.WithFields("err", err).Fatal("Failed to get aerospike client") } err = store.InitServiceTable(as) if err != nil { logger.WithFields("err", err).Fatal("Failed to init service table") } err = store.NewEnv(as, core.AdminEnvFlag.Get(), "The admin environment") if err != nil { logger.WithFields("err", err).Warning("Failed to create admin env") } err = store.NewEnv(as, core.DefaultDevEnvFlag.Get(), "The default environment") if err != nil { logger.WithFields("err", err).Warning("Failed to create new env") } err = store.NewService( as, core.AdminEnvFlag.Get(), "admin", "The admin environment", true) if err != nil { logger.WithFields("err", err).Warning("Failed to create admin service") } err = store.SetServiceLiveCodeVersion( as, core.AdminEnvFlag.Get(), "admin", 1) if err != nil { logger.WithFields("err", err).Warning( "Failed to set admin live code version") } }
// DeployServiceChan deploys the service with provided name onto Lever. If the // service already exists, it is replaced. The method expects a code package // in the form of chunks over stream messages to be sent over. func (admin *Admin) DeployServiceChan( stream leverapi.Stream, envName string) error { // TODO: Auth layer. // Untar to a temp dir. tmpDir := tmpDir(envName) err := os.MkdirAll(tmpDir, 0777) if err != nil { logger.WithFields("err", err).Error( "Cannot create tmp dir for untar") return errInternal } success := false defer func() { if !success { remErr := os.RemoveAll(tmpDir) if remErr != nil { logger.WithFields("err", err).Error( "Error trying to remove tmp dir after failure to untar") } } }() pipeReader, pipeWriter := io.Pipe() bufReader := bufio.NewReader(pipeReader) doneCh := make(chan error, 1) go func() { untarErr := leverutil.Untar(bufReader, tmpDir) if untarErr != nil { doneCh <- untarErr } close(doneCh) }() totalSize := 0 for { var chunk []byte err = stream.Receive(&chunk) if err == io.EOF { break } if err != nil { logger.WithFields("err", err).Error("Error receiving chunks") return errInternal } var chunkSize int chunkSize, err = pipeWriter.Write(chunk) if err != nil { logger.WithFields("err", err).Error( "Error forwarding chunk to untar") return errInternal } // TODO: Also limit total size of decompressed files. totalSize += chunkSize if totalSize > maxUploadSize { logger.Error("File being uploaded is too large") return errTooLarge } // Check if there's been an untar error. select { case untarErr, hasErr := <-doneCh: if !hasErr { continue } logger.WithFields("err", untarErr).Error("Error trying to untar") return errUntar default: } } err = pipeWriter.Close() if err != nil { logger.WithFields("err", err).Error("Error closing pipe") return errInternal } // Wait for untar to finish. untarErr, hasErr := <-doneCh if hasErr && untarErr != nil { logger.WithFields("err", untarErr).Error("Error trying to untar") return errUntar } // Read lever.json. leverConfig, err := core.ReadLeverConfig(tmpDir) if err != nil { logger.WithFields("err", err).Error("Error trying to read lever.json") return errLeverJSON } // Init service table entry. createErr := store.NewService( admin.as, envName, leverConfig.Service, leverConfig.Description, !leverConfig.IsPrivate) // Ignore createErr here in case it already exists. codeVersion, err := store.NewServiceCodeVersion( admin.as, envName, leverConfig.Service) if err != nil { if createErr != nil { logger.WithFields("err", createErr).Error("Error creating service") return errInternal } logger.WithFields("err", err).Error("Error getting new service version") return errInternal } // Everything worked so far. Move the code to the right place. targetDir := codeDir(envName, leverConfig.Service, codeVersion) parentDir := filepath.Dir(targetDir) err = os.MkdirAll(parentDir, 0777) if err != nil { logger.WithFields("err", err).Error( "Cannot create target dir before move") return errInternal } err = os.Rename(tmpDir, targetDir) if err != nil { logger.WithFields("err", err).Error( "Error trying to move new service to its final destination") return errInternal } // Update entry in service table, making it point to the newly uploaded // version. err = store.UpdateService( admin.as, envName, leverConfig.Service, leverConfig.Description, !leverConfig.IsPrivate, codeVersion) if err != nil { logger.WithFields("err", err).Error("Error trying to update service") return errInternal } // TODO: Remove older versions of code to avoid having them pile up forever. success = true stream.Close() return nil }