Make munger begin/end less generic

Just force the beginMungeTag() endMungeTag() macros on users, by hiding
it under the covers. It really simplies things for users.
This commit is contained in:
Eric Paris 2015-07-20 12:45:12 -05:00
parent 22fd8ac32d
commit 4cbca2e63c
19 changed files with 105 additions and 78 deletions

View File

@ -39,7 +39,7 @@ func updateTOC(filePath string, markdown []byte) ([]byte, error) {
return nil, err
}
lines := splitLines(markdown)
updatedMarkdown, err := updateMacroBlock(lines, beginMungeTag(tocMungeTag), endMungeTag(tocMungeTag), string(toc))
updatedMarkdown, err := updateMacroBlock(lines, tocMungeTag, string(toc))
if err != nil {
return nil, err
}

View File

@ -20,9 +20,6 @@ import "fmt"
const unversionedWarningTag = "UNVERSIONED_WARNING"
var beginUnversionedWarning = beginMungeTag(unversionedWarningTag)
var endUnversionedWarning = endMungeTag(unversionedWarningTag)
const unversionedWarningFmt = `
<!-- BEGIN STRIP_FOR_RELEASE -->
@ -65,8 +62,8 @@ func updateUnversionedWarning(file string, markdown []byte) ([]byte, error) {
// No warnings on release branches
return markdown, nil
}
if !hasMacroBlock(lines, beginUnversionedWarning, endUnversionedWarning) {
lines = append([]string{beginUnversionedWarning, endUnversionedWarning}, lines...)
if !hasMacroBlock(lines, unversionedWarningTag) {
lines = prependMacroBlock(unversionedWarningTag, lines)
}
return updateMacroBlock(lines, beginUnversionedWarning, endUnversionedWarning, makeUnversionedWarning(file))
return updateMacroBlock(lines, unversionedWarningTag, makeUnversionedWarning(file))
}

View File

@ -23,7 +23,10 @@ import (
)
func TestUnversionedWarning(t *testing.T) {
warningBlock := beginUnversionedWarning + "\n" + makeUnversionedWarning("filename.md") + "\n" + endUnversionedWarning + "\n"
beginMark := beginMungeTag(unversionedWarningTag)
endMark := endMungeTag(unversionedWarningTag)
warningBlock := beginMark + "\n" + makeUnversionedWarning("filename.md") + "\n" + endMark + "\n"
var cases = []struct {
in string
out string
@ -38,15 +41,15 @@ func TestUnversionedWarning(t *testing.T) {
"Foo\n<!-- TAG IS_VERSIONED -->\nBar",
},
{
beginUnversionedWarning + "\n" + endUnversionedWarning + "\n",
beginMark + "\n" + endMark + "\n",
warningBlock,
},
{
beginUnversionedWarning + "\n" + "something\n" + endUnversionedWarning + "\n",
beginMark + "\n" + "something\n" + endMark + "\n",
warningBlock,
},
{
"Foo\n" + beginUnversionedWarning + "\n" + endUnversionedWarning + "\nBar\n",
"Foo\n" + beginMark + "\n" + endMark + "\nBar\n",
"Foo\n" + warningBlock + "Bar\n",
},
{

View File

@ -38,7 +38,9 @@ func splitLines(document []byte) []string {
//
// Delimiters should occupy own line.
// Returns copy of document with modifications.
func updateMacroBlock(lines []string, beginMark, endMark, insertThis string) ([]byte, error) {
func updateMacroBlock(lines []string, token, insertThis string) ([]byte, error) {
beginMark := beginMungeTag(token)
endMark := endMungeTag(token)
var buffer bytes.Buffer
betweenBeginAndEnd := false
for _, line := range lines {
@ -85,15 +87,32 @@ func hasLine(lines []string, needle string) bool {
return false
}
// Add a macro block to the beginning of a set of lines
func prependMacroBlock(token string, lines []string) []string {
beginMark := beginMungeTag(token)
endMark := endMungeTag(token)
return append([]string{beginMark, endMark}, lines...)
}
// Add a macro block to the end of a set of lines
func appendMacroBlock(token string, lines []string) []string {
beginMark := beginMungeTag(token)
endMark := endMungeTag(token)
return append(lines, beginMark, endMark)
}
// Tests that a document, represented as a slice of lines, has a macro block.
func hasMacroBlock(lines []string, begin string, end string) bool {
func hasMacroBlock(lines []string, token string) bool {
beginMark := beginMungeTag(token)
endMark := endMungeTag(token)
foundBegin := false
for _, line := range lines {
trimmedLine := strings.Trim(line, " \n")
switch {
case !foundBegin && trimmedLine == begin:
case !foundBegin && trimmedLine == beginMark:
foundBegin = true
case foundBegin && trimmedLine == end:
case foundBegin && trimmedLine == endMark:
return true
}
}

View File

@ -24,6 +24,10 @@ import (
)
func Test_updateMacroBlock(t *testing.T) {
token := "TOKEN"
BEGIN := beginMungeTag(token)
END := endMungeTag(token)
var cases = []struct {
in string
out string
@ -31,11 +35,11 @@ func Test_updateMacroBlock(t *testing.T) {
{"", ""},
{"Lorem ipsum\ndolor sit amet\n",
"Lorem ipsum\ndolor sit amet\n"},
{"Lorem ipsum \n BEGIN\ndolor\nEND\nsit amet\n",
"Lorem ipsum \n BEGIN\nfoo\n\nEND\nsit amet\n"},
{"Lorem ipsum \n " + BEGIN + "\ndolor\n" + END + "\nsit amet\n",
"Lorem ipsum \n " + BEGIN + "\nfoo\n\n" + END + "\nsit amet\n"},
}
for _, c := range cases {
actual, err := updateMacroBlock(splitLines([]byte(c.in)), "BEGIN", "END", "foo\n")
actual, err := updateMacroBlock(splitLines([]byte(c.in)), "TOKEN", "foo\n")
assert.NoError(t, err)
if c.out != string(actual) {
t.Errorf("Expected '%v' but got '%v'", c.out, string(actual))
@ -44,20 +48,23 @@ func Test_updateMacroBlock(t *testing.T) {
}
func Test_updateMacroBlock_errors(t *testing.T) {
b := beginMungeTag("TOKEN")
e := endMungeTag("TOKEN")
var cases = []struct {
in string
}{
{"BEGIN\n"},
{"blah\nBEGIN\nblah"},
{"END\n"},
{"blah\nEND\nblah\n"},
{"END\nBEGIN"},
{"BEGIN\nEND\nEND"},
{"BEGIN\nBEGIN\nEND"},
{"BEGIN\nBEGIN\nEND\nEND"},
{b + "\n"},
{"blah\n" + b + "\nblah"},
{e + "\n"},
{"blah\n" + e + "\nblah\n"},
{e + "\n" + b},
{b + "\n" + e + "\n" + e},
{b + "\n" + b + "\n" + e},
{b + "\n" + b + "\n" + e + "\n" + e},
}
for _, c := range cases {
_, err := updateMacroBlock(splitLines([]byte(c.in)), "BEGIN", "END", "foo")
_, err := updateMacroBlock(splitLines([]byte(c.in)), "TOKEN", "foo")
assert.Error(t, err)
}
}
@ -86,26 +93,27 @@ func TestHasLine(t *testing.T) {
}
func TestHasMacroBlock(t *testing.T) {
token := "<<<"
b := beginMungeTag(token)
e := endMungeTag(token)
cases := []struct {
lines []string
begin string
end string
expected bool
}{
{[]string{"<<<", ">>>"}, "<<<", ">>>", true},
{[]string{"<<<", "abc", ">>>"}, "<<<", ">>>", true},
{[]string{"<<<", "<<<", "abc", ">>>"}, "<<<", ">>>", true},
{[]string{"<<<", "abc", ">>>", ">>>"}, "<<<", ">>>", true},
{[]string{"<<<", ">>>", "<<<", ">>>"}, "<<<", ">>>", true},
{[]string{"<<<"}, "<<<", ">>>", false},
{[]string{">>>"}, "<<<", ">>>", false},
{[]string{"<<<", "abc"}, "<<<", ">>>", false},
{[]string{"abc", ">>>"}, "<<<", ">>>", false},
{[]string{b, e}, true},
{[]string{b, "abc", e}, true},
{[]string{b, b, "abc", e}, true},
{[]string{b, "abc", e, e}, true},
{[]string{b, e, b, e}, true},
{[]string{b}, false},
{[]string{e}, false},
{[]string{b, "abc"}, false},
{[]string{"abc", e}, false},
}
for i, c := range cases {
if hasMacroBlock(c.lines, c.begin, c.end) != c.expected {
t.Errorf("case[%d]: %q,%q, expected %t, got %t", i, c.begin, c.end, c.expected, !c.expected)
if hasMacroBlock(c.lines, token) != c.expected {
t.Errorf("case[%d]: expected %t, got %t", i, c.expected, !c.expected)
}
}
}

View File

@ -99,7 +99,7 @@ Use the file [`namespace-dev.json`](namespace-dev.json) which describes a develo
```
[Download example](namespace-dev.json)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE namespace-dev.json -->
Create the development namespace using kubectl.

View File

@ -74,7 +74,7 @@ spec:
```
[Download example](../../examples/blog-logging/counter-pod.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE ../../examples/blog-logging/counter-pod.yaml -->
This pod specification has one container which runs a bash script when the container is born. This script simply writes out the value of a counter and the date once per second and runs indefinitely. Lets create the pod in the default
namespace.
@ -192,7 +192,7 @@ spec:
```
[Download example](../../cluster/saltbase/salt/fluentd-gcp/fluentd-gcp.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE ../../cluster/saltbase/salt/fluentd-gcp/fluentd-gcp.yaml -->
This pod specification maps the directory on the host containing the Docker log files, `/var/lib/docker/containers`, to a directory inside the container which has the same path. The pod runs one image, `gcr.io/google_containers/fluentd-gcp:1.6`, which is configured to collect the Docker log files from the logs directory and ingest them into Google Cloud Logging. One instance of this pod runs on each node of the cluster. Kubernetes will notice if this pod fails and automatically restart it.

View File

@ -105,7 +105,7 @@ spec:
```
[Download example](downward-api/dapi-pod.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE downward-api/dapi-pod.yaml -->
Some more thorough examples:
* [environment variables](environment-guide/)

View File

@ -59,7 +59,7 @@ spec:
```
[Download example](../../examples/blog-logging/counter-pod.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE ../../examples/blog-logging/counter-pod.yaml -->
we can run the pod:

View File

@ -65,7 +65,7 @@ spec:
```
[Download example](pod.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE pod.yaml -->
You can see your cluster's pods:
@ -117,7 +117,7 @@ spec:
```
[Download example](replication.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE replication.yaml -->
To delete the replication controller (and the pods it created):

View File

@ -166,7 +166,7 @@ spec:
```
[Download example](pod-redis.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE pod-redis.yaml -->
Notes:
- The volume mount name is a reference to a specific empty dir volume.

View File

@ -87,7 +87,7 @@ spec:
```
[Download example](pod-nginx-with-label.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE pod-nginx-with-label.yaml -->
Create the labeled pod ([pod-nginx-with-label.yaml](pod-nginx-with-label.yaml)):
@ -143,7 +143,7 @@ spec:
```
[Download example](replication-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE replication-controller.yaml -->
#### Replication Controller Management
@ -196,7 +196,7 @@ spec:
```
[Download example](service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE service.yaml -->
#### Service Management
@ -312,7 +312,7 @@ spec:
```
[Download example](pod-with-http-healthcheck.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE pod-with-http-healthcheck.yaml -->
For more information about health checking, see [Container Probes](../pod-states.md#container-probes).

View File

@ -101,7 +101,7 @@ spec:
```
[Download example](cassandra-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE cassandra-controller.yaml -->
There are a few things to note in this description. First is that we are running the ```kubernetes/cassandra``` image. This is a standard Cassandra installation on top of Debian. However it also adds a custom [```SeedProvider```](https://svn.apache.org/repos/asf/cassandra/trunk/src/java/org/apache/cassandra/locator/SeedProvider.java) to Cassandra. In Cassandra, a ```SeedProvider``` bootstraps the gossip protocol that Cassandra uses to find other nodes. The ```KubernetesSeedProvider``` discovers the Kubernetes API Server using the built in Kubernetes discovery service, and then uses the Kubernetes API to find new nodes (more on this later)
@ -132,7 +132,7 @@ spec:
```
[Download example](cassandra-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE cassandra-service.yaml -->
The important thing to note here is the ```selector```. It is a query over labels, that identifies the set of _Pods_ contained by the _Service_. In this case the selector is ```name=cassandra```. If you look back at the Pod specification above, you'll see that the pod has the corresponding label, so it will be selected for membership in this Service.
@ -242,7 +242,7 @@ spec:
```
[Download example](cassandra-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE cassandra-controller.yaml -->
Most of this replication controller definition is identical to the Cassandra pod definition above, it simply gives the resplication controller a recipe to use when it creates new Cassandra pods. The other differentiating parts are the ```selector``` attribute which contains the controller's selector query, and the ```replicas``` attribute which specifies the desired number of replicas, in this case 1.

View File

@ -82,7 +82,7 @@ spec:
```
[Download example](rabbitmq-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE rabbitmq-service.yaml -->
To start the service, run:
@ -127,7 +127,7 @@ spec:
```
[Download example](rabbitmq-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE rabbitmq-controller.yaml -->
Running `$ kubectl create -f examples/celery-rabbitmq/rabbitmq-controller.yaml` brings up a replication controller that ensures one pod exists which is running a RabbitMQ instance.
@ -168,7 +168,7 @@ spec:
```
[Download example](celery-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE celery-controller.yaml -->
There are several things to point out here...
@ -239,7 +239,7 @@ spec:
```
[Download example](flower-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE flower-service.yaml -->
It is marked as external (LoadBalanced). However on many platforms you will have to add an explicit firewall rule to open port 5555.
On GCE this can be done with:
@ -280,7 +280,7 @@ spec:
```
[Download example](flower-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE flower-controller.yaml -->
This will bring up a new pod with Flower installed and port 5555 (Flower's default port) exposed through the service endpoint. This image uses the following command to start Flower:

View File

@ -93,7 +93,7 @@ spec:
```
[Download example](music-rc.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE music-rc.yaml -->
The `CLUSTER_NAME` variable gives a name to the cluster and allows multiple separate clusters to
exist in the same namespace.
@ -120,7 +120,7 @@ data:
```
[Download example](apiserver-secret.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE apiserver-secret.yaml -->
Replace `NAMESPACE` with the actual namespace to be used and `TOKEN` with the basic64 encoded
versions of the bearer token reported by `kubectl config view` e.g.
@ -186,7 +186,7 @@ spec:
```
[Download example](music-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE music-service.yaml -->
Let's create the service with an external load balancer:

View File

@ -101,7 +101,7 @@ spec:
```
[Download example](redis-master-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE redis-master-controller.yaml -->
Change to the `<kubernetes>/examples/guestbook` directory if you're not already there. Create the redis master pod in your Kubernetes cluster by running:
@ -222,7 +222,7 @@ spec:
```
[Download example](redis-master-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE redis-master-service.yaml -->
Create the service by running:
@ -296,7 +296,7 @@ spec:
```
[Download example](redis-slave-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE redis-slave-controller.yaml -->
and create the replication controller by running:
@ -347,7 +347,7 @@ spec:
```
[Download example](redis-slave-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE redis-slave-service.yaml -->
This time the selector for the service is `name=redis-slave`, because that identifies the pods running redis slaves. It may also be helpful to set labels on your service itself as we've done here to make it easy to locate them with the `kubectl get services -l "label=value"` command.
@ -398,7 +398,7 @@ spec:
```
[Download example](frontend-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE frontend-controller.yaml -->
Using this file, you can turn up your frontend with:
@ -501,7 +501,7 @@ spec:
```
[Download example](frontend-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE frontend-service.yaml -->
#### Using 'type: LoadBalancer' for the frontend service (cloud-provider-specific)

View File

@ -84,7 +84,7 @@ spec:
```
[Download example](hazelcast-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE hazelcast-service.yaml -->
The important thing to note here is the `selector`. It is a query over labels, that identifies the set of _Pods_ contained by the _Service_. In this case the selector is `name: hazelcast`. If you look at the Replication Controller specification below, you'll see that the pod has the corresponding label, so it will be selected for membership in this Service.
@ -139,7 +139,7 @@ spec:
```
[Download example](hazelcast-controller.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE hazelcast-controller.yaml -->
There are a few things to note in this description. First is that we are running the `quay.io/pires/hazelcast-kubernetes` image, tag `0.5`. This is a `busybox` installation with JRE 8 Update 45. However it also adds a custom [`application`](https://github.com/pires/hazelcast-kubernetes-bootstrapper) that finds any Hazelcast nodes in the cluster and bootstraps an Hazelcast instance accordingle. The `HazelcastDiscoveryController` discovers the Kubernetes API Server using the built in Kubernetes discovery service, and then uses the Kubernetes API to find new nodes (more on this later).

View File

@ -132,7 +132,7 @@ spec:
```
[Download example](mysql.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE mysql.yaml -->
Note that we've defined a volume mount for `/var/lib/mysql`, and specified a volume that uses the persistent disk (`mysql-disk`) that you created.
Once you've edited the file to set your database password, create the pod as follows, where `<kubernetes>` is the path to your Kubernetes installation:
@ -187,7 +187,7 @@ spec:
```
[Download example](mysql-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE mysql-service.yaml -->
Start the service like this:
@ -242,7 +242,7 @@ spec:
```
[Download example](wordpress.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE wordpress.yaml -->
Create the pod:
@ -283,7 +283,7 @@ spec:
```
[Download example](wordpress-service.yaml)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE wordpress-service.yaml -->
Note the `type: LoadBalancer` setting. This will set up the wordpress service behind an external IP.
Note also that we've set the service port to 80. We'll return to that shortly.

View File

@ -99,7 +99,7 @@ To start Phabricator server use the file [`examples/phabricator/phabricator-cont
```
[Download example](phabricator-controller.json)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE phabricator-controller.json -->
Create the phabricator pod in your Kubernetes cluster by running:
@ -189,7 +189,7 @@ To automate this process and make sure that a proper host is authorized even if
```
[Download example](authenticator-controller.json)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE authenticator-controller.json -->
To create the pod run:
@ -238,7 +238,7 @@ Use the file [`examples/phabricator/phabricator-service.json`](phabricator-servi
```
[Download example](phabricator-service.json)
<!-- END MUNGE: EXAMPLE -->
<!-- END MUNGE: EXAMPLE phabricator-service.json -->
To create the service run: