mirror of https://github.com/kubernetes/kops.git
Merge pull request #4076 from justinsb/refactor_hosts
Automatic merge from submit-queue. Refactor protokube hosts file into its own package
This commit is contained in:
commit
576f3dc603
|
|
@ -102,6 +102,7 @@ k8s.io/kops/protokube/pkg/etcd
|
||||||
k8s.io/kops/protokube/pkg/gossip
|
k8s.io/kops/protokube/pkg/gossip
|
||||||
k8s.io/kops/protokube/pkg/gossip/aws
|
k8s.io/kops/protokube/pkg/gossip/aws
|
||||||
k8s.io/kops/protokube/pkg/gossip/dns
|
k8s.io/kops/protokube/pkg/gossip/dns
|
||||||
|
k8s.io/kops/protokube/pkg/gossip/dns/hosts
|
||||||
k8s.io/kops/protokube/pkg/gossip/dns/provider
|
k8s.io/kops/protokube/pkg/gossip/dns/provider
|
||||||
k8s.io/kops/protokube/pkg/gossip/gce
|
k8s.io/kops/protokube/pkg/gossip/gce
|
||||||
k8s.io/kops/protokube/pkg/gossip/mesh
|
k8s.io/kops/protokube/pkg/gossip/mesh
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ go_library(
|
||||||
visibility = ["//visibility:public"],
|
visibility = ["//visibility:public"],
|
||||||
deps = [
|
deps = [
|
||||||
"//protokube/pkg/gossip:go_default_library",
|
"//protokube/pkg/gossip:go_default_library",
|
||||||
|
"//protokube/pkg/gossip/dns/hosts:go_default_library",
|
||||||
"//vendor/github.com/golang/glog:go_default_library",
|
"//vendor/github.com/golang/glog:go_default_library",
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -17,19 +17,10 @@ limitations under the License.
|
||||||
package dns
|
package dns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"os"
|
|
||||||
"path/filepath"
|
|
||||||
"sort"
|
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
|
"k8s.io/kops/protokube/pkg/gossip/dns/hosts"
|
||||||
)
|
)
|
||||||
|
|
||||||
const GUARD_BEGIN = "# Begin host entries managed by kops - do not edit"
|
|
||||||
const GUARD_END = "# End host entries managed by kops"
|
|
||||||
|
|
||||||
// HostsFile stores DNS records into /etc/hosts
|
// HostsFile stores DNS records into /etc/hosts
|
||||||
type HostsFile struct {
|
type HostsFile struct {
|
||||||
Path string
|
Path string
|
||||||
|
|
@ -58,109 +49,5 @@ func (h *HostsFile) Update(snapshot *DNSViewSnapshot) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stat, err := os.Stat(h.Path)
|
return hosts.UpdateHostsFileWithRecords(h.Path, addrToHosts)
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error getting file status of %q: %v", h.Path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
data, err := ioutil.ReadFile(h.Path)
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error reading file %q: %v", h.Path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
var out []string
|
|
||||||
depth := 0
|
|
||||||
for _, line := range strings.Split(string(data), "\n") {
|
|
||||||
k := strings.TrimSpace(line)
|
|
||||||
if k == GUARD_BEGIN {
|
|
||||||
depth++
|
|
||||||
}
|
|
||||||
|
|
||||||
if depth <= 0 {
|
|
||||||
out = append(out, line)
|
|
||||||
}
|
|
||||||
|
|
||||||
if k == GUARD_END {
|
|
||||||
depth--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Ensure a single blank line
|
|
||||||
for {
|
|
||||||
if len(out) == 0 {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
if out[len(out)-1] != "" {
|
|
||||||
break
|
|
||||||
}
|
|
||||||
|
|
||||||
out = out[:len(out)-1]
|
|
||||||
}
|
|
||||||
out = append(out, "")
|
|
||||||
|
|
||||||
out = append(out, GUARD_BEGIN)
|
|
||||||
for addr, hosts := range addrToHosts {
|
|
||||||
sort.Strings(hosts)
|
|
||||||
out = append(out, addr+"\t"+strings.Join(hosts, " "))
|
|
||||||
}
|
|
||||||
out = append(out, GUARD_END)
|
|
||||||
out = append(out, "")
|
|
||||||
|
|
||||||
// Note that because we are bind mounting /etc/hosts, we can't do a normal atomic file write
|
|
||||||
// (where we write a temp file and rename it)
|
|
||||||
// TODO: We should just hold the file open while we read & write it
|
|
||||||
err = ioutil.WriteFile(h.Path, []byte(strings.Join(out, "\n")), stat.Mode().Perm())
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error writing file %q: %v", h.Path, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func atomicWriteFile(filename string, data []byte, perm os.FileMode) error {
|
|
||||||
dir := filepath.Dir(filename)
|
|
||||||
|
|
||||||
tempFile, err := ioutil.TempFile(dir, ".tmp"+filepath.Base(filename))
|
|
||||||
if err != nil {
|
|
||||||
return fmt.Errorf("error creating temp file in %q: %v", dir, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mustClose := true
|
|
||||||
mustRemove := true
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
if mustClose {
|
|
||||||
if err := tempFile.Close(); err != nil {
|
|
||||||
glog.Warningf("error closing temp file: %v", err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if mustRemove {
|
|
||||||
if err := os.Remove(tempFile.Name()); err != nil {
|
|
||||||
glog.Warningf("error removing temp file %q: %v", tempFile.Name(), err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}()
|
|
||||||
|
|
||||||
if _, err := tempFile.Write(data); err != nil {
|
|
||||||
return fmt.Errorf("error writing temp file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := tempFile.Close(); err != nil {
|
|
||||||
return fmt.Errorf("error closing temp file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mustClose = false
|
|
||||||
|
|
||||||
if err := os.Chmod(tempFile.Name(), perm); err != nil {
|
|
||||||
return fmt.Errorf("error changing mode of temp file: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := os.Rename(tempFile.Name(), filename); err != nil {
|
|
||||||
return fmt.Errorf("error moving temp file %q to %q: %v", tempFile.Name(), filename, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
mustRemove = false
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,9 @@
|
||||||
|
load("@io_bazel_rules_go//go:def.bzl", "go_library")
|
||||||
|
|
||||||
|
go_library(
|
||||||
|
name = "go_default_library",
|
||||||
|
srcs = ["hosts.go"],
|
||||||
|
importpath = "k8s.io/kops/protokube/pkg/gossip/dns/hosts",
|
||||||
|
visibility = ["//visibility:public"],
|
||||||
|
deps = ["//vendor/github.com/golang/glog:go_default_library"],
|
||||||
|
)
|
||||||
|
|
@ -0,0 +1,139 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 The Kubernetes Authors.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package hosts
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"sort"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"github.com/golang/glog"
|
||||||
|
)
|
||||||
|
|
||||||
|
const GUARD_BEGIN = "# Begin host entries managed by kops - do not edit"
|
||||||
|
const GUARD_END = "# End host entries managed by kops"
|
||||||
|
|
||||||
|
func UpdateHostsFileWithRecords(p string, addrToHosts map[string][]string) error {
|
||||||
|
stat, err := os.Stat(p)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error getting file status of %q: %v", p, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
data, err := ioutil.ReadFile(p)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error reading file %q: %v", p, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
var out []string
|
||||||
|
depth := 0
|
||||||
|
for _, line := range strings.Split(string(data), "\n") {
|
||||||
|
k := strings.TrimSpace(line)
|
||||||
|
if k == GUARD_BEGIN {
|
||||||
|
depth++
|
||||||
|
}
|
||||||
|
|
||||||
|
if depth <= 0 {
|
||||||
|
out = append(out, line)
|
||||||
|
}
|
||||||
|
|
||||||
|
if k == GUARD_END {
|
||||||
|
depth--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a single blank line
|
||||||
|
for {
|
||||||
|
if len(out) == 0 {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
if out[len(out)-1] != "" {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
out = out[:len(out)-1]
|
||||||
|
}
|
||||||
|
out = append(out, "")
|
||||||
|
|
||||||
|
out = append(out, GUARD_BEGIN)
|
||||||
|
for addr, hosts := range addrToHosts {
|
||||||
|
sort.Strings(hosts)
|
||||||
|
out = append(out, addr+"\t"+strings.Join(hosts, " "))
|
||||||
|
}
|
||||||
|
out = append(out, GUARD_END)
|
||||||
|
out = append(out, "")
|
||||||
|
|
||||||
|
// Note that because we are bind mounting /etc/hosts, we can't do a normal atomic file write
|
||||||
|
// (where we write a temp file and rename it)
|
||||||
|
// TODO: We should just hold the file open while we read & write it
|
||||||
|
err = ioutil.WriteFile(p, []byte(strings.Join(out, "\n")), stat.Mode().Perm())
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error writing file %q: %v", p, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func atomicWriteFile(filename string, data []byte, perm os.FileMode) error {
|
||||||
|
dir := filepath.Dir(filename)
|
||||||
|
|
||||||
|
tempFile, err := ioutil.TempFile(dir, ".tmp"+filepath.Base(filename))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("error creating temp file in %q: %v", dir, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mustClose := true
|
||||||
|
mustRemove := true
|
||||||
|
|
||||||
|
defer func() {
|
||||||
|
if mustClose {
|
||||||
|
if err := tempFile.Close(); err != nil {
|
||||||
|
glog.Warningf("error closing temp file: %v", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if mustRemove {
|
||||||
|
if err := os.Remove(tempFile.Name()); err != nil {
|
||||||
|
glog.Warningf("error removing temp file %q: %v", tempFile.Name(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
if _, err := tempFile.Write(data); err != nil {
|
||||||
|
return fmt.Errorf("error writing temp file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tempFile.Close(); err != nil {
|
||||||
|
return fmt.Errorf("error closing temp file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mustClose = false
|
||||||
|
|
||||||
|
if err := os.Chmod(tempFile.Name(), perm); err != nil {
|
||||||
|
return fmt.Errorf("error changing mode of temp file: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := os.Rename(tempFile.Name(), filename); err != nil {
|
||||||
|
return fmt.Errorf("error moving temp file %q to %q: %v", tempFile.Name(), filename, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
mustRemove = false
|
||||||
|
return nil
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue