Пример #1
0
// IsSameConfig reports whether src and dest config files are equal.
// Two config files are equal when they have the same file contents and
// Unix permissions. The owner, group, and mode must match.
// It return false in other cases.
func isSameConfig(src, dest string) (bool, error) {
	if !isFileExist(dest) {
		return false, nil
	}
	dfi, err := getFileInfo(dest)
	if err != nil {
		return false, err
	}
	sfi, err := getFileInfo(src)
	if err != nil {
		return false, err
	}
	if dfi.Uid != sfi.Uid {
		log.Infof("%s has UID %d should be %d", dest, dfi.Uid, sfi.Uid)
	}
	if dfi.Gid != sfi.Gid {
		log.Infof("%s has GID %d should be %d", dest, dfi.Gid, sfi.Gid)
	}
	if dfi.Mode != sfi.Mode {
		log.Infof("%s has mode %s should be %s", dest, os.FileMode(dfi.Mode), os.FileMode(sfi.Mode))
	}
	if dfi.Md5 != sfi.Md5 {
		log.Infof("%s has md5sum %s should be %s", dest, dfi.Md5, sfi.Md5)
	}
	if dfi.Uid != sfi.Uid || dfi.Gid != sfi.Gid || dfi.Mode != sfi.Mode || dfi.Md5 != sfi.Md5 {
		return false, nil
	}
	return true, nil
}
Пример #2
0
func (k2n *KubeToNginx) Run() {
	if k2n.config.IngressesData == "" {
		log.Fatal("no ingresses, no way")
	}

	id, err := base64.StdEncoding.DecodeString(k2n.config.IngressesData)
	if err != nil {
		log.Fatal(err)
	}

	k2n.ingressesData = make(map[string]string)
	if err := json.Unmarshal(id, &k2n.ingressesData); err != nil {
		log.Fatal(err)
	}

	// Get service account token
	serviceAccountToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
	if err != nil {
		log.Fatal(err)
	}

	// Get CA certificate data
	caCertificate, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
	if err != nil {
		log.Fatal(err)
	}

	// Create new k8s client
	kubeConfig := &kclient.ClientConfig{
		MasterURL:     k2n.config.KubeMasterURL,
		Auth:          &kclient.TokenAuth{string(serviceAccountToken)},
		CaCertificate: caCertificate,
	}
	kubeClient, err := kclient.NewClient(kubeConfig)
	if err != nil {
		log.Fatal(err)
	}

	// Flow control channels
	recvChan := make(chan interface{}, 100)
	stopChan := make(<-chan struct{})
	doneChan := make(chan bool)
	errChan := make(chan error, 10)

	// Create informer from client
	informerConfig := &kclient.InformerConfig{
		Namespace:      k2n.config.Namespace,
		Resource:       "services",
		Selector:       k2n.config.Selector,
		ResyncInterval: k2n.config.ResyncInterval,
	}
	i, err := kubeClient.NewInformer(
		informerConfig, recvChan,
		stopChan, doneChan, errChan,
	)
	if err != nil {
		log.Fatal(err)
	}

	tmplCfg := &core.TemplateConfig{
		SrcData:   core.NginxConf,
		Dest:      k2n.config.NginxDest,
		Uid:       k2n.config.NginxDestUid,
		Gid:       k2n.config.NginxDestGid,
		Mode:      k2n.config.NginxDestMode,
		Prefix:    "/lb",
		CheckCmd:  k2n.config.NginxCheckCmd,
		ReloadCmd: k2n.config.NginxReloadCmd,
	}

	if k2n.config.NginxSrc != "" {
		tmplCfg.Src = k2n.config.NginxSrc
	}

	k2n.tmpl = core.NewTemplate(tmplCfg, false, false, false)

	go i.Run()

	// Wait for signal
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	for {
		select {
		case v := <-recvChan:
			k2n.process(v)
		case err := <-errChan:
			log.Error(err)
		case s := <-signalChan:
			log.Infof("Captured %v. Exiting...", s)
			close(doneChan)
		case <-doneChan:
			os.Exit(0)
		}
	}
}
Пример #3
0
// sync compares the staged and dest config files and attempts to sync them
// if they differ. sync will run a config check command if set before
// overwriting the target config file. Finally, sync will run a reload command
// if set to have the application or service pick up the changes.
// It returns an error if any.
func (t *Template) sync(stageFile *os.File, fileMode os.FileMode, doNoOp bool) error {
	stageFileName := stageFile.Name()
	if !t.keepStageFile {
		defer os.Remove(stageFileName)
	}

	log.Debugf("Comparing candidate config to %s", t.config.Dest)
	ok, err := isSameConfig(stageFileName, t.config.Dest)
	if err != nil {
		log.Error(err)
		return err
	}

	if doNoOp {
		log.Warnf("Noop mode enabled. %s will not be modified", t.config.Dest)
		return nil
	}

	if !ok {
		log.Infof("Target config %s out of sync", t.config.Dest)

		if t.config.CheckCmd != "" {
			if err := t.check(stageFileName); err != nil {
				return errors.New("Config check failed: " + err.Error())
			}
		}

		log.Debugf("Overwriting target config %s", t.config.Dest)

		err := os.Rename(stageFileName, t.config.Dest)
		if err != nil {
			if strings.Contains(err.Error(), "device or resource busy") {
				log.Debugf("Rename failed - target is likely a mount.config. Trying to write instead")
				// try to open the file and write to it
				var contents []byte
				var rerr error
				contents, rerr = ioutil.ReadFile(stageFileName)
				if rerr != nil {
					return rerr
				}
				err := ioutil.WriteFile(t.config.Dest, contents, fileMode)
				// make sure owner and group match the temp file, in case the file was created with WriteFile
				os.Chown(t.config.Dest, t.config.Uid, t.config.Gid)
				if err != nil {
					return err
				}
			} else {
				return err
			}
		}

		if t.config.ReloadCmd != "" {
			if err := t.reload(); err != nil {
				return err
			}
		}

		log.Infof("Target config %s has been updated", t.config.Dest)
	} else {
		log.Debugf("Target config %s in sync", t.config.Dest)
	}

	return nil
}
Пример #4
0
func (kl *KubeListener) Run() {
	// Get service account token
	serviceAccountToken, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/token")
	if err != nil {
		log.Fatal(err)
	}

	// Get CA certificate data
	caCertificate, err := ioutil.ReadFile("/var/run/secrets/kubernetes.io/serviceaccount/ca.crt")
	if err != nil {
		log.Fatal(err)
	}

	// Create new k8s client
	kubeConfig := &kclient.ClientConfig{
		MasterURL:     kl.config.KubeMasterURL,
		Auth:          &kclient.TokenAuth{string(serviceAccountToken)},
		CaCertificate: caCertificate,
	}
	kubeClient, err := kclient.NewClient(kubeConfig)
	if err != nil {
		log.Fatal(err)
	}

	// Flow control channels
	recvChan := make(chan interface{}, 100)
	stopChan := make(<-chan struct{})
	doneChan := make(chan bool)
	errChan := make(chan error, 10)

	// Create informer from client
	informerConfig := &kclient.InformerConfig{
		Namespace:      kl.config.Namespace,
		Resource:       kl.config.Resource,
		Selector:       kl.config.Selector,
		ResyncInterval: kl.config.ResyncInterval,
	}
	i, err := kubeClient.NewInformer(
		informerConfig, recvChan,
		stopChan, doneChan, errChan,
	)
	if err != nil {
		log.Fatal(err)
	}

	go i.Run()

	// Wait for signal
	signalChan := make(chan os.Signal, 1)
	signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM)
	for {
		select {
		case v := <-recvChan:
			log.Infof("%v", v)
		case err := <-errChan:
			log.Error(err)
		case s := <-signalChan:
			log.Infof("Captured %v. Exiting...", s)
			close(doneChan)
		case <-doneChan:
			os.Exit(0)
		}
	}

	/*
		// create kubelistener instance
		kl := kubelistener{config: config}

		// open add events files
		if config.AddEventsFile == "" {
			glog.Warningf("Ignoring 'add' events because --add-events-file wasn't provided.")
		} else {
			if w, err := newWriter(config.AddEventsFile); err != nil {
				glog.Fatalf("Unable to open '%s' for writing due to: %s", config.AddEventsFile, err.Error())
			} else {
				kl.addWriter = w
			}
		}

		// open update events files
		if config.UpdateEventsFile == "" {
			glog.Warningf("Ignoring 'update' events because --update-events-file wasn't provided.")
		} else {
			if w, err := newWriter(config.UpdateEventsFile); err != nil {
				glog.Fatalf("Unable to open '%s' for writing due to: %s", config.UpdateEventsFile, err.Error())
			} else {
				kl.updateWriter = w
			}
		}

		// open delete events files
		if config.DeleteEventsFile == "" {
			glog.Warningf("Ignoring 'delete' events because --delete-events-file wasn't provided.")
		} else {
			if w, err := newWriter(config.DeleteEventsFile); err != nil {
				glog.Fatalf("Unable to open '%s' for writing due to: %s", config.DeleteEventsFile, err.Error())
			} else {
				kl.deleteWriter = w
			}
		}

		// choose which resources to watch
		if config.Resource == "" {
			glog.Fatalf("Unable to start kubelistener because --resources to watch wasn't provided.")
		}

		var resource = strings.ToLower(config.Resource)
		if resource == "all" {
			for _, watchFunc := range resources {
				watchFunc(&kl)
			}
		} else if watchFunc, ok := resources[resource]; ok {
			watchFunc(&kl)
		} else {
			glog.Fatal("Unknown resource to watch '%s':", resource)
		}
	*/
}