예제 #1
0
func newPemFromBytes(conf Config, pem []byte) (*KeyStore, error) {
	ca, err := buildWholeCAsBy(conf, pem)
	if err != nil {
		return nil, errors.New("Could not build ca for keyStore config.").CausedBy(err)
	}
	certs, err := loadCertificatesFrom(pem)
	if err != nil {
		return nil, errors.New("Could not load certs from PEM.").CausedBy(err)
	}
	if len(certs) <= 0 {
		return nil, errors.New("The provieded PEM does not contain a certificate.")
	}
	privateKey, err := loadPrivateKeyFrom(pem)
	if err != nil {
		return nil, err
	}
	return &KeyStore{
		enabled:    true,
		config:     conf,
		pem:        pem,
		ca:         ca,
		cert:       certs[0],
		privateKey: privateKey,
	}, nil
}
예제 #2
0
// Run runs this execution.
// This method is a blocking method and could only be executed at this instance once.
func (instance *Execution) Run() (values.ExitCode, error) {
	err := instance.handleBeforeRun()
	if err != nil {
		return values.ExitCode(1), err
	}
	exitCode, err := instance.preExecution()
	if err != nil || exitCode != 0 {
		return exitCode, err
	}
	instance.logger.Log(logger.Debug, "Start service '%s' with command: %s", instance.Name(), instance.commandLineOf(instance.cmd))
	exitCode, lastState, err := instance.runBare()
	if lastState == Killed {
		err = StoppedOrKilledError{error: errors.New("Process was killed.")}
		instance.logger.Log(logger.Debug, "Service '%s' ended after kill: %d", instance.Name(), exitCode)
	} else if lastState == Stopped {
		err = StoppedOrKilledError{error: errors.New("Process was stopped.")}
		instance.logger.Log(logger.Debug, "Service '%s' ended successful after stop: %d", instance.Name(), exitCode)
	} else if err != nil {
		instance.logger.Log(logger.Fatal, err)
	} else if instance.service.config.SuccessExitCodes.Contains(exitCode) {
		instance.logger.Log(logger.Debug, "Service '%s' ended successful: %d", instance.Name(), exitCode)
	} else {
		instance.logger.Log(logger.Error, "Service '%s' ended with unexpected code: %d", instance.Name(), exitCode)
		err = errors.New("Unexpected error code %d generated by service '%s'", exitCode, instance.Name())
	}
	instance.postExecution()
	return exitCode, err
}
예제 #3
0
파일: mutex.go 프로젝트: echocat/caretakerd
// Lock locks the current thread to this mutex.
// If this is not possible an error will be returned.
// This method is blocking until locking is possible.
func (instance *Mutex) Lock() error {
	var err error
	defer func() {
		p := recover()
		if p != nil {
			if s, ok := p.(string); ok {
				if s != "send on closed channel" {
					panic(p)
				} else {
					err = errors.New("Lock interrupted.")
				}
			} else {
				panic(p)
			}
		}
	}()
	select {
	case instance.channel <- true:
		return nil
	default:
		if err != nil {
			return err
		}
		return errors.New("Lock interrupted.")
	}
}
예제 #4
0
func enrichWithElementAndItsChildren(pd *PickedDefinitions, elementID IDType) error {
	if pd.IDToDefinition[elementID.String()] != nil {
		return nil
	}
	element, err := pd.GetSourceElementBy(elementID)
	if err != nil {
		return err
	}
	if element == nil {
		return nil
	}
	pd.IDToDefinition[elementID.String()] = element
	if valueType, ok := element.(WithValueType); ok {
		for _, idType := range ExtractAllIDTypesFrom(valueType.ValueType()) {
			err := enrichWithElementAndItsChildren(pd, idType)
			if err != nil {
				return errors.New("Could not extract valueType '%v' of type '%s'.", idType, elementID).CausedBy(err)
			}
		}
	}
	if children, ok := element.(WithChildren); ok {
		for _, child := range children.Children() {
			err := enrichWithElementAndItsChildren(pd, child.ID())
			if err != nil {
				return errors.New("Could not extract child '%v' of type '%s'.", child.ID(), elementID).CausedBy(err)
			}
		}
	}

	return nil
}
예제 #5
0
func (instance *Execution) sendSignal(s values.Signal) error {
	if instance.isKillSignal(s) {
		if !instance.setStateTo(Killed) {
			if s == values.KILL || instance.service.config.StopSignal == s {
				return nil
			} else {
				return errors.New("Service '%v' is not running.", instance)
			}
		}
	} else if instance.isStopSignal(s) {
		if !instance.setStateTo(Stopped) {
			if s == values.KILL || instance.service.config.StopSignal == s {
				return nil
			} else {
				return errors.New("Service '%v' is not running.", instance)
			}
		}
	}
	cmd := (*instance).cmd
	process := cmd.Process
	ps := cmd.ProcessState
	if process == nil || ps != nil {
		instance.setStateTo(Down)
		return nil
	}
	if s != values.NOOP {
		return sendSignalToService((*instance).service, process, s, instance.service.config.StopSignalTarget)
	}
	return nil
}
예제 #6
0
파일: level.go 프로젝트: echocat/caretakerd
// Set the given string to the current object from a string.
// Returns an error object if there are any problems while transforming the string.
func (instance *Level) Set(value string) error {
	if valueAsInt, err := strconv.Atoi(value); err == nil {
		for _, candidate := range AllLevels {
			if int(candidate) == valueAsInt {
				(*instance) = candidate
				return nil
			}
		}
		return errors.New("Illegal level: " + value)
	}
	lowerValue := strings.ToLower(value)
	switch lowerValue {
	case "warn":
		*instance = Warning
		return nil
	case "err":
		*instance = Error
		return nil
	}
	for _, candidate := range AllLevels {
		if candidate.String() == lowerValue {
			(*instance) = candidate
			return nil
		}
	}
	return errors.New("Illegal level: " + value)
}
예제 #7
0
// GeneratePem generates a new PEM with the config of the current KeyStore instance and returns it.
// This PEM will be stored in the KeyStore instance.
func (instance KeyStore) GeneratePem(name string) ([]byte, *x509.Certificate, error) {
	if !instance.enabled {
		return []byte{}, nil, errors.New("KeyStore is not enabled.")
	}
	privateKey, privateKeyBytes, publicKey, err := generatePrivateKey(instance.Config())
	if err != nil {
		return []byte{}, nil, errors.New("Could not generate pem for '%v'.", name).CausedBy(err)
	}
	certificateDerBytes, err := instance.generateClientCertificate(name, publicKey, privateKey)
	if err != nil {
		return []byte{}, nil, err
	}

	cert, err := x509.ParseCertificate(certificateDerBytes)
	if err != nil || cert == nil {
		return []byte{}, nil, errors.New("Wow! Could not parse right now created certificate for '%v'?", name).CausedBy(err)
	}

	pemBytes := []byte{}
	pemBytes = append(pemBytes, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: certificateDerBytes})...)
	pemBytes = append(pemBytes, pem.EncodeToMemory(&pem.Block{Type: "CERTIFICATE", Bytes: instance.cert.Raw})...)
	pemBytes = append(pemBytes, pem.EncodeToMemory(&pem.Block{Type: "RSA PRIVATE KEY", Bytes: privateKeyBytes})...)

	return pemBytes, cert, nil
}
예제 #8
0
func (instance *parsedPackage) fileFor(object posEnabled) (*ast.File, error) {
	tokenFile := instance.fileSet.File(object.Pos())
	if tokenFile == nil {
		return nil, errors.New("Package %v does not contain object %v.", instance.pkg.Path(), object)
	}
	if file, ok := instance.sourceFiles[tokenFile.Name()]; ok {
		return file, nil
	}
	return nil, errors.New("Package %v does not contain file %v.", instance.pkg.Path(), tokenFile.Name())
}
예제 #9
0
// WriteToYamlFile writes the config of the current instance to the given yaml file.
func (instance Config) WriteToYamlFile(fileName values.String) error {
	content, err := yaml.Marshal(instance)
	if err != nil {
		return errors.New("Could not write config to '%v'.", fileName).CausedBy(err)
	}
	if err := ioutil.WriteFile(fileName.String(), content, 0744); err != nil {
		return errors.New("Could not write marshalled config to '%v'.", fileName).CausedBy(err)
	}
	return nil
}
예제 #10
0
func (instance Config) validateRequireStringOrNotValue(value values.String, fieldName string, isAllowedMethod func() bool) error {
	if isAllowedMethod() {
		if value.IsEmpty() {
			return errors.New("There is no %s set for type %v.", fieldName, instance.Type)
		}
	} else {
		if !value.IsEmpty() {
			return errors.New("There is no %s allowed for type %v.", fieldName, instance.Type)
		}
	}
	return nil
}
예제 #11
0
// LoadCertificateFromFile loads a certificate from the given filename and returns it.
func LoadCertificateFromFile(filename string) (*x509.Certificate, error) {
	fileContent, err := ioutil.ReadFile(filename)
	if err != nil {
		return nil, errors.New("Could not read certificate from %v.", filename).CausedBy(err)
	}
	certificates, err := loadCertificatesFrom(fileContent)
	if err != nil {
		return nil, errors.New("Could not read certificate from %v.", filename).CausedBy(err)
	}
	if len(certificates) <= 0 {
		return nil, errors.New("File %v does not contain a valid certificate.", filename)
	}
	return certificates[0], nil
}
예제 #12
0
// LoadFromYamlFile loads the caretakerd config from the given yaml file.
func LoadFromYamlFile(fileName values.String) (Config, error) {
	result := NewConfig()
	content, err := ioutil.ReadFile(fileName.String())
	if err != nil {
		if os.IsNotExist(err) {
			return Config{}, ConfigDoesNotExistError{fileName: fileName.String()}
		}
		return Config{}, errors.New("Could not read config from '%v'.", fileName).CausedBy(err)
	}
	if err := yaml.Unmarshal(content, &result); err != nil {
		return Config{}, errors.New("Could not unmarshal config from '%v'.", fileName).CausedBy(err)
	}
	return result, nil
}
예제 #13
0
// ValidateMaster validates whether there is exactly one service defined as master. Returns an error object if there are more services defined as masters.
func (instance Configs) ValidateMaster() error {
	masters := []string{}
	for name, service := range instance {
		if service.Type == Master {
			masters = append(masters, name)
		}
	}
	if len(masters) == 0 {
		return errors.New("There is no service of type master defined.")
	}
	if len(masters) > 1 {
		return errors.New("There are more then 0 service of type master defined: %s", strings.Join(masters, ", "))
	}
	return nil
}
예제 #14
0
// NewCaretakerd creates a new Caretakerd instance from the given config
func NewCaretakerd(conf Config, syncGroup *usync.Group) (*Caretakerd, error) {
	err := conf.Validate()
	if err != nil {
		return nil, err
	}
	log, err := logger.NewLogger(conf.Logger, "caretakerd", syncGroup)
	if err != nil {
		return nil, errors.New("Could not create logger for caretakerd.").CausedBy(err)
	}
	ks, err := keyStore.NewKeyStore(bool(conf.RPC.Enabled), conf.KeyStore)
	if err != nil {
		return nil, err
	}
	ctl, err := control.NewControl(conf.Control, ks)
	if err != nil {
		return nil, err
	}
	services, err := service.NewServices(conf.Services, syncGroup, ks)
	if err != nil {
		return nil, err
	}
	result := Caretakerd{
		open:          true,
		config:        conf,
		logger:        log,
		control:       ctl,
		keyStore:      ks,
		services:      services,
		lock:          new(sync.Mutex),
		syncGroup:     syncGroup,
		signalChannel: nil,
	}
	runtime.SetFinalizer(&result, finalize)
	return &result, nil
}
예제 #15
0
// Run starts the caretakerd execution, every service and required resource.
// This is a blocking method.
func (instance *Execution) Run() (values.ExitCode, error) {
	autoStartableServices := instance.executable.Services().GetAllAutoStartable()
	// Start all non-master services first to start the master properly.
	for _, target := range autoStartableServices {
		if target.Config().Type != service.Master {
			instance.startAndLogProblemsIfNeeded(target)
		}
	}
	// Now start the master.
	masterStarted := false
	for _, target := range autoStartableServices {
		if target.Config().Type == service.Master {
			err := instance.Start(target)
			if err != nil {
				(*instance).masterError = err
			}
			masterStarted = true
		}
	}
	if !masterStarted {
		(*instance).masterError = errors.New("No master was started. There are no master configured?")
	}
	if (*instance).masterError != nil {
		instance.stopOthers()
	}
	instance.wg.Wait()
	exitCode := values.ExitCode(-1)
	if (*instance).masterExitCode != nil {
		exitCode = *(*instance).masterExitCode
	}
	return exitCode, (*instance).masterError
}
예제 #16
0
func newFromEnvironment(conf Config) (*KeyStore, error) {
	pem := os.Getenv("CTD_PEM")
	if len(strings.TrimSpace(pem)) <= 0 {
		return nil, errors.New("There is an %v keyStore confgiured but the CTD_PEM environment varaible is empty.", conf.Type)
	}
	return newPemFromBytes(conf, []byte(pem))
}
예제 #17
0
func newFomFile(conf Config) (*KeyStore, error) {
	pem, err := ioutil.ReadFile(conf.PemFile.String())
	if err != nil {
		return nil, errors.New("Could not read pem from '%v'.", conf.PemFile).CausedBy(err)
	}
	return newPemFromBytes(conf, pem)
}
예제 #18
0
func (instance Configs) validateService(service Config, name string) error {
	err := service.Validate()
	if err != nil {
		return errors.New("Config of '%v' service is not valid.", name).CausedBy(err)
	}
	return nil
}
예제 #19
0
func (instance *Config) handleServiceMapEnv(full string, serviceName string, key string, subKey string, value string) error {
	targetKey := strings.ToUpper(key)
	if handler, ok := serviceSubEnvKeyToFunction[targetKey]; ok {
		return instance.Services.ConfigureSub(serviceName, subKey, value, handler)
	}
	return errors.New("Unknown configuration type '%s' for service '%s'.", key, serviceName)
}
예제 #20
0
func checkForIsCa(name string, sec *keyStore.KeyStore) error {
	if !sec.IsCA() {
		return errors.New("It is not possible to generate a new certificate for service '%v' with a caretakerd certificate that is not a CA. "+
			"Use trusted access for service '%v', configure caretakerd to generate its own certificate or provide a CA enabled certificate for caretakerd.", name, name)
	}
	return nil
}
예제 #21
0
// SetFromInt tries to set the given int value to this instance.
// Returns an error object if there are any problems while transforming the plain int.
func (i *NonNegativeInteger) SetFromInt(value int) error {
	if value < 0 {
		return errors.New("This intger value should not be negative. But got: %v", value)
	}
	(*i) = NonNegativeInteger(value)
	return nil
}
예제 #22
0
// Set sets the given string to current object from a string.
// Returns an error object if there are any problems while transforming the string.
func (instance *Integer) Set(value string) error {
	valueAsInt, err := strconv.Atoi(value)
	if err != nil {
		return errors.New("Illegal integer value: " + value)
	}
	return instance.SetFromInt(valueAsInt)
}
예제 #23
0
func loadPrivateKeyFrom(p []byte) (interface{}, error) {
	if len(p) > 0 {
		rp := p
		block := new(pem.Block)
		for block != nil && len(rp) > 0 {
			block, rp = pem.Decode(rp)
			if block != nil && block.Type == "RSA PRIVATE KEY" {
				privateKey, err := x509.ParsePKCS1PrivateKey(block.Bytes)
				if err != nil {
					return nil, errors.New("Could not parse privateKey.").CausedBy(err)
				}
				return privateKey, nil
			}
		}
	}
	return nil, errors.New("The PEM does not contain a valid private key.")
}
예제 #24
0
// Set sets the given string to current object from a string.
// Returns an error object if there are any problems while transforming the string.
func (i *ExitCode) Set(value string) error {
	valueAsInt, err := strconv.Atoi(value)
	if err != nil {
		return errors.New("Illegal exit Code value: " + value)
	}
	(*i) = ExitCode(valueAsInt)
	return nil
}
예제 #25
0
func newGenerated(conf Config) (*KeyStore, error) {
	pem, cert, privateKey, err := generatePem(conf)
	if err != nil {
		return nil, errors.New("Could not generate pem for keyStore config.").CausedBy(err)
	}
	ca, err := buildWholeCAsBy(conf, pem)
	if err != nil {
		return nil, errors.New("Could not build CA bundle for keyStore config.").CausedBy(err)
	}
	return &KeyStore{
		enabled:    true,
		config:     conf,
		pem:        pem,
		ca:         ca,
		cert:       cert,
		privateKey: privateKey,
	}, nil
}
예제 #26
0
// ConfigureSub executes a configuring action for a service with the given name.
func (s *Configs) ConfigureSub(serviceName string, key string, value string, with func(conf *Config, key string, value string) error) error {
	conf, ok := (*s)[serviceName]
	if !ok {
		return errors.New("There does no service with name '%s' exist.", serviceName)
	}
	err := with(&conf, key, value)
	(*s)[serviceName] = conf
	return err
}
예제 #27
0
func generateFileForPem(conf Config, pem []byte) (string, error) {
	permission := conf.PemFilePermission.ThisOrDefault().AsFileMode()
	f, err := os.OpenFile(conf.PemFile.String(), os.O_WRONLY|os.O_CREATE|os.O_TRUNC, permission)
	if err != nil {
		return "", errors.New("Could not create pemFile '%s'.", conf.PemFile).CausedBy(err)
	}
	defer f.Close()
	if !conf.PemFileUser.IsEmpty() {
		_, lerr := user.Lookup(conf.PemFileUser.String())
		if lerr != nil {
			return "", errors.New("Could not set ownership of pemFile '%s' to '%s'.", conf.PemFile, conf.PemFileUser).CausedBy(err)
		}
		//f.Chown(kfu.Uid, kfu.Gid) TODO!
	}
	f.Write(pem)
	f.Sync()
	return conf.PemFile.String(), nil
}
예제 #28
0
// CheckedString is like String but also returns an optional error if there are any
// validation errors.
func (instance Protocol) CheckedString() (string, error) {
	switch instance {
	case TCP:
		return "tcp", nil
	case Unix:
		return "unix", nil
	}
	return "", errors.New("Illegal protocol: %d", instance)
}
예제 #29
0
// CheckedString is like String but also returns an optional error if there are any
// validation errors.
func (instance SignalTarget) CheckedString() (string, error) {
	switch instance {
	case Process:
		return "process", nil
	case ProcessGroup:
		return "processGroup", nil
	}
	return "", errors.New("Illegal signal target: %d", instance)
}
예제 #30
0
// Set sets the given string to current object from a string.
// Returns an error object if there are any problems while transforming the string.
func (instance *SocketAddress) Set(value string) error {
	match := uriPattern.FindStringSubmatch(value)
	if match != nil && len(match) == 3 {
		var protocol Protocol
		err := protocol.Set(match[1])
		if err != nil {
			return err
		}
		switch protocol {
		case TCP:
			return instance.SetTCP(match[2])
		case Unix:
			return instance.SetUnix(match[2])
		}
		return errors.New("Unknown protocol %v in address '%v'.", protocol, value)
	}
	return errors.New("Illegal socket address: %s", value)
}