Merge pull request #55152 from fabriziopandini/kubeadm-doc-preflight

Automatic merge from submit-queue (batch tested with PRs 55868, 55393, 55152, 55849). If you want to cherry-pick this change to another branch, please follow the instructions <a href="https://github.com/kubernetes/community/blob/master/contributors/devel/cherry-picks.md">here</a>.

Improve documentation for kubeadm preflight command

**What this PR does / why we need it**:
This PR is part of the effort for improving kubeadm reference doc (CLI, website, manpages), and more specifically improves documentation for `kubeadm alpha phase preflight`

**Which issue(s) this PR fixes**:
part of the effort for [#265](https://github.com/kubernetes/kubeadm/issues/265)

**Special notes for your reviewer**:
The PR has two commits:
- `Clone documentation utility from //pkg/kubectl/cmd/templates`, that re-implements in kubeadm some kubectl utilities for handling description and examples for cobra.commands; more PR will follow re-using those utilities. NB. I was forced to add an exception to golint because `blackfriday.Renderer` requires to implement an interface that is not compliant
- `kubeadm-doc-preflight` that implements improvement to `kubeadm alpha phase preflight`

**Release note**:
```release-note
NONE
```
This commit is contained in:
Kubernetes Submit Queue 2017-11-16 06:32:21 -08:00 committed by GitHub
commit c5e543308b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 347 additions and 16 deletions

View File

@ -40,7 +40,7 @@ func NewKubeadmCommand(_ io.Reader, out, err io.Writer) *cobra.Command {
kubeadm: easily bootstrap a secure Kubernetes cluster.
KUBEADM IS BETA, DO NOT USE IT FOR PRODUCTION CLUSTERS!
KUBEADM IS CURRENTLY IN BETA
But please, try it out and give us feedback at:
https://github.com/kubernetes/kubeadm/issues │

View File

@ -218,7 +218,7 @@ func AddInitOtherFlags(flagSet *flag.FlagSet, cfgPath *string, skipPreFlight, sk
// NewInit validates given arguments and instantiates Init struct with provided information.
func NewInit(cfgPath string, cfg *kubeadmapi.MasterConfiguration, skipPreFlight, skipTokenPrint, dryRun bool, criSocket string) (*Init, error) {
fmt.Println("[kubeadm] WARNING: kubeadm is in beta. Please do not use it for production clusters!")
fmt.Println("[kubeadm] WARNING: kubeadm is currently in beta")
if cfgPath != "" {
b, err := ioutil.ReadFile(cfgPath)

View File

@ -176,7 +176,7 @@ type Join struct {
// NewJoin instantiates Join struct with given arguments
func NewJoin(cfgPath string, args []string, cfg *kubeadmapi.NodeConfiguration, skipPreFlight bool, criSocket string) (*Join, error) {
fmt.Println("[kubeadm] WARNING: kubeadm is in beta. Please do not use it for production clusters!")
fmt.Println("[kubeadm] WARNING: kubeadm is currently in beta")
if cfg.NodeName == "" {
cfg.NodeName = nodeutil.GetHostname("")

View File

@ -47,6 +47,7 @@ go_library(
"//cmd/kubeadm/app/util/config:go_default_library",
"//cmd/kubeadm/app/util/kubeconfig:go_default_library",
"//pkg/api/legacyscheme:go_default_library",
"//pkg/util/normalizer:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/k8s.io/client-go/kubernetes:go_default_library",
"//vendor/k8s.io/utils/exec:go_default_library",

View File

@ -22,15 +22,37 @@ import (
kubeadmapi "k8s.io/kubernetes/cmd/kubeadm/app/apis/kubeadm"
cmdutil "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util"
"k8s.io/kubernetes/cmd/kubeadm/app/preflight"
kubeadmutil "k8s.io/kubernetes/cmd/kubeadm/app/util"
"k8s.io/kubernetes/pkg/util/normalizer"
utilsexec "k8s.io/utils/exec"
)
var (
masterPreflightLongDesc = normalizer.LongDesc(`
Run master pre-flight checks, functionally equivalent to what implemented by kubeadm init.
` + cmdutil.AlphaDisclaimer)
masterPreflightExample = normalizer.Examples(`
# Run master pre-flight checks.
kubeadm alpha phase preflight master
`)
nodePreflightLongDesc = normalizer.LongDesc(`
Run node pre-flight checks, functionally equivalent to what implemented by kubeadm join.
` + cmdutil.AlphaDisclaimer)
nodePreflightExample = normalizer.Examples(`
# Run node pre-flight checks.
kubeadm alpha phase preflight node
`)
)
// NewCmdPreFlight calls cobra.Command for preflight checks
func NewCmdPreFlight() *cobra.Command {
cmd := &cobra.Command{
Use: "preflight",
Short: "Run pre-flight checks",
RunE: cmdutil.SubCmdRunE("preflight"),
Long: cmdutil.MacroCommandLongDescription,
}
cmd.AddCommand(NewCmdPreFlightMaster())
@ -41,12 +63,15 @@ func NewCmdPreFlight() *cobra.Command {
// NewCmdPreFlightMaster calls cobra.Command for master preflight checks
func NewCmdPreFlightMaster() *cobra.Command {
cmd := &cobra.Command{
Use: "master",
Short: "Run master pre-flight checks.",
RunE: func(cmd *cobra.Command, args []string) error {
Use: "master",
Short: "Run master pre-flight checks",
Long: masterPreflightLongDesc,
Example: masterPreflightExample,
Run: func(cmd *cobra.Command, args []string) {
cfg := &kubeadmapi.MasterConfiguration{}
criSocket := ""
return preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket)
err := preflight.RunInitMasterChecks(utilsexec.New(), cfg, criSocket)
kubeadmutil.CheckErr(err)
},
}
@ -56,12 +81,15 @@ func NewCmdPreFlightMaster() *cobra.Command {
// NewCmdPreFlightNode calls cobra.Command for node preflight checks
func NewCmdPreFlightNode() *cobra.Command {
cmd := &cobra.Command{
Use: "node",
Short: "Run node pre-flight checks.",
RunE: func(cmd *cobra.Command, args []string) error {
Use: "node",
Short: "Run node pre-flight checks",
Long: nodePreflightLongDesc,
Example: nodePreflightExample,
Run: func(cmd *cobra.Command, args []string) {
cfg := &kubeadmapi.NodeConfiguration{}
criSocket := ""
return preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket)
err := preflight.RunJoinNodeChecks(utilsexec.New(), cfg, criSocket)
kubeadmutil.CheckErr(err)
},
}

View File

@ -2,10 +2,16 @@ load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = ["cmdutil.go"],
srcs = [
"cmdutil.go",
"documentation.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/util",
visibility = ["//visibility:public"],
deps = ["//vendor/github.com/spf13/cobra:go_default_library"],
deps = [
"//pkg/util/normalizer:go_default_library",
"//vendor/github.com/spf13/cobra:go_default_library",
],
)
go_test(

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package phases
package util
import (
"fmt"

View File

@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
limitations under the License.
*/
package phases
package util
import (
"testing"

View File

@ -0,0 +1,33 @@
/*
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 util
import (
"k8s.io/kubernetes/pkg/util/normalizer"
)
var (
// AlphaDisclaimer to be places at the end of description of commands in alpha release
AlphaDisclaimer = `
Alpha Disclaimer: this command is currently alpha but, please try it out and give us feedback!
`
// MacroCommandLongDescription provide a standard description for "macro" commands
MacroCommandLongDescription = normalizer.LongDesc(`
This command is not meant to be run on its own. See list of available subcommands.
`)
)

View File

@ -28,6 +28,7 @@ import (
// Run creates and executes new kubeadm command
func Run() error {
// We do not want these flags to show up in --help
pflag.CommandLine.MarkHidden("version")
pflag.CommandLine.MarkHidden("google-json-key")
pflag.CommandLine.MarkHidden("log-flush-frequency")

View File

@ -354,6 +354,7 @@ pkg/util/labels
pkg/util/mount
pkg/util/netsh/testing
pkg/util/node
pkg/util/normalizer
pkg/util/oom
pkg/util/parsers
pkg/util/procfs

View File

@ -38,6 +38,7 @@ filegroup(
"//pkg/util/net:all-srcs",
"//pkg/util/netsh:all-srcs",
"//pkg/util/node:all-srcs",
"//pkg/util/normalizer:all-srcs",
"//pkg/util/nsenter:all-srcs",
"//pkg/util/oom:all-srcs",
"//pkg/util/parsers:all-srcs",

29
pkg/util/normalizer/BUILD Normal file
View File

@ -0,0 +1,29 @@
load("@io_bazel_rules_go//go:def.bzl", "go_library")
go_library(
name = "go_default_library",
srcs = [
"markdown.go",
"normalizer.go",
],
importpath = "k8s.io/kubernetes/pkg/util/normalizer",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/MakeNowJust/heredoc:go_default_library",
"//vendor/github.com/russross/blackfriday:go_default_library",
],
)
filegroup(
name = "package-srcs",
srcs = glob(["**"]),
tags = ["automanaged"],
visibility = ["//visibility:private"],
)
filegroup(
name = "all-srcs",
srcs = [":package-srcs"],
tags = ["automanaged"],
visibility = ["//visibility:public"],
)

View File

@ -0,0 +1,151 @@
/*
Copyright 2016 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.
*/
/*
This file is copied from /pkg/kubectl/cmd/templates/markdown.go
In a future PR we should remove the original copy and use
/pkg/util/normalizer everywhere.
*/
package normalizer
import (
"bytes"
"fmt"
"strings"
"github.com/russross/blackfriday"
)
const linebreak = "\n"
// ASCIIRenderer implements blackfriday.Renderer
var _ blackfriday.Renderer = &ASCIIRenderer{}
// ASCIIRenderer is a blackfriday.Renderer intended for rendering markdown
// documents as plain text, well suited for human reading on terminals.
type ASCIIRenderer struct {
Indentation string
listItemCount uint
listLevel uint
}
// NormalText gets a text chunk *after* the markdown syntax was already
// processed and does a final cleanup on things we don't expect here, like
// removing linebreaks on things that are not a paragraph break (auto unwrap).
func (r *ASCIIRenderer) NormalText(out *bytes.Buffer, text []byte) {
raw := string(text)
lines := strings.Split(raw, linebreak)
for _, line := range lines {
trimmed := strings.Trim(line, " \n\t")
out.WriteString(trimmed)
out.WriteString(" ")
}
}
// List renders the start and end of a list.
func (r *ASCIIRenderer) List(out *bytes.Buffer, text func() bool, flags int) {
r.listLevel++
out.WriteString(linebreak)
text()
r.listLevel--
}
// ListItem renders list items and supports both ordered and unordered lists.
func (r *ASCIIRenderer) ListItem(out *bytes.Buffer, text []byte, flags int) {
if flags&blackfriday.LIST_ITEM_BEGINNING_OF_LIST != 0 {
r.listItemCount = 1
} else {
r.listItemCount++
}
indent := strings.Repeat(r.Indentation, int(r.listLevel))
var bullet string
if flags&blackfriday.LIST_TYPE_ORDERED != 0 {
bullet += fmt.Sprintf("%d.", r.listItemCount)
} else {
bullet += "*"
}
out.WriteString(indent + bullet + " ")
r.fw(out, text)
out.WriteString(linebreak)
}
// Paragraph renders the start and end of a paragraph.
func (r *ASCIIRenderer) Paragraph(out *bytes.Buffer, text func() bool) {
out.WriteString(linebreak)
text()
out.WriteString(linebreak)
}
// BlockCode renders a chunk of text that represents source code.
func (r *ASCIIRenderer) BlockCode(out *bytes.Buffer, text []byte, lang string) {
out.WriteString(linebreak)
lines := []string{}
for _, line := range strings.Split(string(text), linebreak) {
indented := r.Indentation + line
lines = append(lines, indented)
}
out.WriteString(strings.Join(lines, linebreak))
}
func (r *ASCIIRenderer) GetFlags() int { return 0 }
func (r *ASCIIRenderer) HRule(out *bytes.Buffer) {
out.WriteString(linebreak + "----------" + linebreak)
}
func (r *ASCIIRenderer) LineBreak(out *bytes.Buffer) { out.WriteString(linebreak) }
func (r *ASCIIRenderer) TitleBlock(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) Header(out *bytes.Buffer, text func() bool, level int, id string) { text() }
func (r *ASCIIRenderer) BlockHtml(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) BlockQuote(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) TableRow(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) TableHeaderCell(out *bytes.Buffer, text []byte, align int) { r.fw(out, text) }
func (r *ASCIIRenderer) TableCell(out *bytes.Buffer, text []byte, align int) { r.fw(out, text) }
func (r *ASCIIRenderer) Footnotes(out *bytes.Buffer, text func() bool) { text() }
func (r *ASCIIRenderer) FootnoteItem(out *bytes.Buffer, name, text []byte, flags int) { r.fw(out, text) }
func (r *ASCIIRenderer) AutoLink(out *bytes.Buffer, link []byte, kind int) { r.fw(out, link) }
func (r *ASCIIRenderer) CodeSpan(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) DoubleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) Emphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) RawHtmlTag(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) TripleEmphasis(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) StrikeThrough(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) FootnoteRef(out *bytes.Buffer, ref []byte, id int) { r.fw(out, ref) }
func (r *ASCIIRenderer) Entity(out *bytes.Buffer, entity []byte) { r.fw(out, entity) }
func (r *ASCIIRenderer) Smartypants(out *bytes.Buffer, text []byte) { r.fw(out, text) }
func (r *ASCIIRenderer) DocumentHeader(out *bytes.Buffer) {}
func (r *ASCIIRenderer) DocumentFooter(out *bytes.Buffer) {}
func (r *ASCIIRenderer) TocHeaderWithAnchor(text []byte, level int, anchor string) {}
func (r *ASCIIRenderer) TocHeader(text []byte, level int) {}
func (r *ASCIIRenderer) TocFinalize() {}
func (r *ASCIIRenderer) Table(out *bytes.Buffer, header []byte, body []byte, columnData []int) {
r.fw(out, header, body)
}
func (r *ASCIIRenderer) Link(out *bytes.Buffer, link []byte, title []byte, content []byte) {
r.fw(out, link)
}
func (r *ASCIIRenderer) Image(out *bytes.Buffer, link []byte, title []byte, alt []byte) {
r.fw(out, link)
}
func (r *ASCIIRenderer) fw(out *bytes.Buffer, text ...[]byte) {
for _, t := range text {
out.Write(t)
}
}

View File

@ -0,0 +1,80 @@
/*
Copyright 2016 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.
*/
/*
This file is copied from /pkg/kubectl/cmd/templates/normalizer.go
In a future PR we should remove the original copy and use
/pkg/util/normalizer everywhere.
*/
package normalizer
import (
"strings"
"github.com/MakeNowJust/heredoc"
"github.com/russross/blackfriday"
)
const indentation = ` `
// LongDesc normalizes a command's long description to follow the conventions.
func LongDesc(s string) string {
if len(s) == 0 {
return s
}
return normalizer{s}.Heredoc().Markdown().Trim().string
}
// Examples normalizes a command's examples to follow the conventions.
func Examples(s string) string {
if len(s) == 0 {
return s
}
return normalizer{s}.Trim().Indent().string
}
type normalizer struct {
string
}
func (s normalizer) Markdown() normalizer {
bytes := []byte(s.string)
formatted := blackfriday.Markdown(bytes, &ASCIIRenderer{Indentation: indentation}, 0)
s.string = string(formatted)
return s
}
func (s normalizer) Heredoc() normalizer {
s.string = heredoc.Doc(s.string)
return s
}
func (s normalizer) Trim() normalizer {
s.string = strings.TrimSpace(s.string)
return s
}
func (s normalizer) Indent() normalizer {
indentedLines := []string{}
for _, line := range strings.Split(s.string, "\n") {
trimmed := strings.TrimSpace(line)
indented := indentation + trimmed
indentedLines = append(indentedLines, indented)
}
s.string = strings.Join(indentedLines, "\n")
return s
}