func (k2n *KubeToNginx) process(v interface{}) { switch vv := v.(type) { case *kapi.ServiceList: k2n.upstreamsData = make(map[string]string) for _, s := range vv.Items { k2n.addService(s) } case *kapi.WatchEvent: s, ok := vv.Object.(*kapi.Service) if !ok { log.Warnf("unknown k8s api object in a watch event was received: %v", vv.Object) return } switch vv.Type { case kapi.Added: k2n.addService(*s) case kapi.Deleted: k2n.deleteService(*s) case kapi.Modified: k2n.updateService(*s) } default: log.Warnf("unknown k8s api object was received: %v", v) return } // mixup everything kvs := make(map[string]string) for k, v := range k2n.ingressesData { kvs[k] = v } for k, v := range k2n.upstreamsData { kvs[k] = v } // render template err := k2n.tmpl.Render(kvs) if err != nil { log.Error(err) } }
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) } } }
// 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 }
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) } */ }