Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
K
k3s
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Registry
Registry
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Jacklull
k3s
Commits
6a8ace5c
Commit
6a8ace5c
authored
Oct 12, 2018
by
fabriziopandini
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
add phase runner
parent
8012b958
Expand all
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
532 additions
and
0 deletions
+532
-0
BUILD
cmd/kubeadm/app/cmd/phases/BUILD
+1
-0
BUILD
cmd/kubeadm/app/cmd/phases/workflow/BUILD
+39
-0
doc.go
cmd/kubeadm/app/cmd/phases/workflow/doc.go
+47
-0
doc_test.go
cmd/kubeadm/app/cmd/phases/workflow/doc_test.go
+109
-0
phase.go
cmd/kubeadm/app/cmd/phases/workflow/phase.go
+57
-0
runner.go
cmd/kubeadm/app/cmd/phases/workflow/runner.go
+0
-0
runner_test.go
cmd/kubeadm/app/cmd/phases/workflow/runner_test.go
+279
-0
No files found.
cmd/kubeadm/app/cmd/phases/BUILD
View file @
6a8ace5c
...
...
@@ -97,6 +97,7 @@ filegroup(
srcs = [
":package-srcs",
"//cmd/kubeadm/app/cmd/phases/certs:all-srcs",
"//cmd/kubeadm/app/cmd/phases/workflow:all-srcs",
],
tags = ["automanaged"],
visibility = ["//visibility:public"],
...
...
cmd/kubeadm/app/cmd/phases/workflow/BUILD
0 → 100644
View file @
6a8ace5c
load("@io_bazel_rules_go//go:def.bzl", "go_library", "go_test")
go_library(
name = "go_default_library",
srcs = [
"doc.go",
"phase.go",
"runner.go",
],
importpath = "k8s.io/kubernetes/cmd/kubeadm/app/cmd/phases/workflow",
visibility = ["//visibility:public"],
deps = [
"//vendor/github.com/spf13/cobra:go_default_library",
"//vendor/github.com/spf13/pflag:go_default_library",
],
)
go_test(
name = "go_default_test",
srcs = [
"doc_test.go",
"runner_test.go",
],
embed = [":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"],
)
cmd/kubeadm/app/cmd/phases/workflow/doc.go
0 → 100644
View file @
6a8ace5c
/*
Copyright 2018 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 workflow implements a workflow manager to be used for
implementing composable kubeadm workflows.
Composable kubeadm workflows are built by an ordered sequence of phases;
each phase can have it's own, nested, ordered sequence of sub phases.
For instance
preflight Run master pre-flight checks
certs Generates all PKI assets necessary to establish the control plane
/ca Generates a self-signed kubernetes CA to provision identities for Kubernetes components
/apiserver Generates an API server serving certificate and key
...
kubeconfig Generates all kubeconfig files necessary to establish the control plane
/admin Generates a kubeconfig file for the admin to use and for kubeadm itself
/kubelet Generates a kubeconfig file for the kubelet to use.
...
...
Phases are designed to be reusable across different kubeadm workflows thus allowing
e.g. reuse of phase certs in both kubeadm init and kubeadm join --control-plane workflows.
Each workflow can be defined and managed using a Runner, that will run all
the phases according to the given order; nested phases will be executed immediately
after their parent phase.
The Runner behavior can be changed by setting the RunnerOptions, typically
exposed as kubeadm command line flags, thus allowing to filter the list of phases
to be executed.
*/
package
workflow
cmd/kubeadm/app/cmd/phases/workflow/doc_test.go
0 → 100644
View file @
6a8ace5c
/*
Copyright 2018 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
workflow
import
(
"errors"
"fmt"
)
var
myWorkflowRunner
=
NewRunner
()
type
myWorkflowData
struct
{
data
string
}
func
(
c
*
myWorkflowData
)
Data
()
string
{
return
c
.
data
}
type
myPhaseData
interface
{
Data
()
string
}
func
ExamplePhase
()
{
// Create a phase
var
myPhase1
=
Phase
{
Name
:
"myPhase1"
,
Short
:
"A phase of a kubeadm composable workflow..."
,
Run
:
func
(
data
RunData
)
error
{
// transform data into a typed data struct
d
,
ok
:=
data
.
(
myPhaseData
)
if
!
ok
{
return
errors
.
New
(
"invalid RunData type"
)
}
// implement your phase logic...
fmt
.
Printf
(
"%v"
,
d
.
Data
())
return
nil
},
}
// Create another phase
var
myPhase2
=
Phase
{
Name
:
"myPhase2"
,
Short
:
"Another phase of a kubeadm composable workflow..."
,
Run
:
func
(
data
RunData
)
error
{
// transform data into a typed data struct
d
,
ok
:=
data
.
(
myPhaseData
)
if
!
ok
{
return
errors
.
New
(
"invalid RunData type"
)
}
// implement your phase logic...
fmt
.
Printf
(
"%v"
,
d
.
Data
())
return
nil
},
}
// Adds the new phases to the workflow
// Phases will be executed the same order they are added to the workflow
myWorkflowRunner
.
AppendPhase
(
myPhase1
)
myWorkflowRunner
.
AppendPhase
(
myPhase2
)
}
func
ExampleRunner_Run
()
{
// Create a phase
var
myPhase
=
Phase
{
Name
:
"myPhase"
,
Short
:
"A phase of a kubeadm composable workflow..."
,
Run
:
func
(
data
RunData
)
error
{
// transform data into a typed data struct
d
,
ok
:=
data
.
(
myPhaseData
)
if
!
ok
{
return
errors
.
New
(
"invalid RunData type"
)
}
// implement your phase logic...
fmt
.
Printf
(
"%v"
,
d
.
Data
())
return
nil
},
}
// Adds the new phase to the workflow
var
myWorkflowRunner
=
NewRunner
()
myWorkflowRunner
.
AppendPhase
(
myPhase
)
// Defines the method that creates the runtime data shared
// among all the phases included in the workflow
myWorkflowRunner
.
SetDataInitializer
(
func
()
(
RunData
,
error
)
{
return
myWorkflowData
{
data
:
"some data"
},
nil
})
// Runs the workflow
myWorkflowRunner
.
Run
()
}
cmd/kubeadm/app/cmd/phases/workflow/phase.go
0 → 100644
View file @
6a8ace5c
/*
Copyright 2018 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
workflow
// Phase provides an implementation of a workflow phase that allows
// creation of new phases by simply instantiating a variable of this type.
type
Phase
struct
{
// name of the phase.
// Phase name should be unique among peer phases (phases belonging to
// the same workflow or phases belonging to the same parent phase).
Name
string
// Short description of the phase.
Short
string
// Long returns the long description of the phase.
Long
string
// Example returns the example for the phase.
Example
string
// Hidden define if the phase should be hidden in the workflow help.
// e.g. PrintFilesIfDryRunning phase in the kubeadm init workflow is candidate for being hidden to the users
Hidden
bool
// Phases defines a nested, ordered sequence of phases.
Phases
[]
Phase
// Run defines a function implementing the phase action.
// It is recommended to implent type assertion, e.g. using golang type switch,
// for validating the RunData type.
Run
func
(
data
RunData
)
error
// RunIf define a function that implements a condition that should be checked
// before executing the phase action.
// If this function return nil, the phase action is always executed.
RunIf
func
(
data
RunData
)
(
bool
,
error
)
}
// AppendPhase adds the given phase to the nested, ordered sequence of phases.
func
(
t
*
Phase
)
AppendPhase
(
phase
Phase
)
{
t
.
Phases
=
append
(
t
.
Phases
,
phase
)
}
cmd/kubeadm/app/cmd/phases/workflow/runner.go
0 → 100644
View file @
6a8ace5c
This diff is collapsed.
Click to expand it.
cmd/kubeadm/app/cmd/phases/workflow/runner_test.go
0 → 100644
View file @
6a8ace5c
/*
Copyright 2018 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
workflow
import
(
"errors"
"fmt"
"reflect"
"testing"
)
func
phaseBuilder
(
name
string
,
phases
...
Phase
)
Phase
{
return
Phase
{
Name
:
name
,
Short
:
fmt
.
Sprintf
(
"long description for %s ..."
,
name
),
Phases
:
phases
,
}
}
func
TestComputePhaseRunFlags
(
t
*
testing
.
T
)
{
var
usecases
=
[]
struct
{
name
string
options
RunnerOptions
expected
map
[
string
]
bool
expectedError
bool
}{
{
name
:
"no options > all phases"
,
options
:
RunnerOptions
{},
expected
:
map
[
string
]
bool
{
"foo"
:
true
,
"foo/bar"
:
true
,
"foo/baz"
:
true
,
"qux"
:
true
},
},
{
name
:
"options can filter phases"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"foo/baz"
,
"qux"
}},
expected
:
map
[
string
]
bool
{
"foo"
:
false
,
"foo/bar"
:
false
,
"foo/baz"
:
true
,
"qux"
:
true
},
},
{
name
:
"options can filter phases - hierarchy is considered"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"foo"
}},
expected
:
map
[
string
]
bool
{
"foo"
:
true
,
"foo/bar"
:
true
,
"foo/baz"
:
true
,
"qux"
:
false
},
},
{
name
:
"options can skip phases"
,
options
:
RunnerOptions
{
SkipPhases
:
[]
string
{
"foo/bar"
,
"qux"
}},
expected
:
map
[
string
]
bool
{
"foo"
:
true
,
"foo/bar"
:
false
,
"foo/baz"
:
true
,
"qux"
:
false
},
},
{
name
:
"options can skip phases - hierarchy is considered"
,
options
:
RunnerOptions
{
SkipPhases
:
[]
string
{
"foo"
}},
expected
:
map
[
string
]
bool
{
"foo"
:
false
,
"foo/bar"
:
false
,
"foo/baz"
:
false
,
"qux"
:
true
},
},
{
name
:
"skip options have higher precedence than filter options"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"foo"
},
// "foo", "foo/bar", "foo/baz" true
SkipPhases
:
[]
string
{
"foo/bar"
},
// "foo/bar" false
},
expected
:
map
[
string
]
bool
{
"foo"
:
true
,
"foo/bar"
:
false
,
"foo/baz"
:
true
,
"qux"
:
false
},
},
{
name
:
"invalid filter option"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"invalid"
}},
expectedError
:
true
,
},
{
name
:
"invalid skip option"
,
options
:
RunnerOptions
{
SkipPhases
:
[]
string
{
"invalid"
}},
expectedError
:
true
,
},
}
for
_
,
u
:=
range
usecases
{
t
.
Run
(
u
.
name
,
func
(
t
*
testing
.
T
)
{
var
w
=
Runner
{
Phases
:
[]
Phase
{
phaseBuilder
(
"foo"
,
phaseBuilder
(
"bar"
),
phaseBuilder
(
"baz"
),
),
phaseBuilder
(
"qux"
),
},
}
w
.
prepareForExecution
()
w
.
Options
=
u
.
options
actual
,
err
:=
w
.
computePhaseRunFlags
()
if
(
err
!=
nil
)
!=
u
.
expectedError
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
}
if
err
!=
nil
{
return
}
if
!
reflect
.
DeepEqual
(
actual
,
u
.
expected
)
{
t
.
Errorf
(
"
\n
actual:
\n\t
%v
\n
expected:
\n\t
%v
\n
"
,
actual
,
u
.
expected
)
}
})
}
}
func
phaseBuilder1
(
name
string
,
runIf
func
(
data
RunData
)
(
bool
,
error
),
phases
...
Phase
)
Phase
{
return
Phase
{
Name
:
name
,
Short
:
fmt
.
Sprintf
(
"long description for %s ..."
,
name
),
Phases
:
phases
,
Run
:
runBuilder
(
name
),
RunIf
:
runIf
,
}
}
var
callstack
[]
string
func
runBuilder
(
name
string
)
func
(
data
RunData
)
error
{
return
func
(
data
RunData
)
error
{
callstack
=
append
(
callstack
,
name
)
return
nil
}
}
func
runConditionTrue
(
data
RunData
)
(
bool
,
error
)
{
return
true
,
nil
}
func
runConditionFalse
(
data
RunData
)
(
bool
,
error
)
{
return
false
,
nil
}
func
TestRunOrderAndConditions
(
t
*
testing
.
T
)
{
var
w
=
Runner
{
Phases
:
[]
Phase
{
phaseBuilder1
(
"foo"
,
nil
,
phaseBuilder1
(
"bar"
,
runConditionTrue
),
phaseBuilder1
(
"baz"
,
runConditionFalse
),
),
phaseBuilder1
(
"qux"
,
runConditionTrue
),
},
}
var
usecases
=
[]
struct
{
name
string
options
RunnerOptions
expectedOrder
[]
string
}{
{
name
:
"Run respect runCondition"
,
expectedOrder
:
[]
string
{
"foo"
,
"bar"
,
"qux"
},
},
{
name
:
"Run takes options into account"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"foo"
},
SkipPhases
:
[]
string
{
"foo/baz"
}},
expectedOrder
:
[]
string
{
"foo"
,
"bar"
},
},
}
for
_
,
u
:=
range
usecases
{
t
.
Run
(
u
.
name
,
func
(
t
*
testing
.
T
)
{
callstack
=
[]
string
{}
w
.
Options
=
u
.
options
err
:=
w
.
Run
()
if
err
!=
nil
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
}
if
!
reflect
.
DeepEqual
(
callstack
,
u
.
expectedOrder
)
{
t
.
Errorf
(
"
\n
callstack:
\n\t
%v
\n
expected:
\n\t
%v
\n
"
,
callstack
,
u
.
expectedOrder
)
}
})
}
}
func
phaseBuilder2
(
name
string
,
runIf
func
(
data
RunData
)
(
bool
,
error
),
run
func
(
data
RunData
)
error
,
phases
...
Phase
)
Phase
{
return
Phase
{
Name
:
name
,
Short
:
fmt
.
Sprintf
(
"long description for %s ..."
,
name
),
Phases
:
phases
,
Run
:
run
,
RunIf
:
runIf
,
}
}
func
runPass
(
data
RunData
)
error
{
return
nil
}
func
runFails
(
data
RunData
)
error
{
return
errors
.
New
(
"run fails"
)
}
func
runConditionPass
(
data
RunData
)
(
bool
,
error
)
{
return
true
,
nil
}
func
runConditionFails
(
data
RunData
)
(
bool
,
error
)
{
return
false
,
errors
.
New
(
"run condition fails"
)
}
func
TestRunHandleErrors
(
t
*
testing
.
T
)
{
var
w
=
Runner
{
Phases
:
[]
Phase
{
phaseBuilder2
(
"foo"
,
runConditionPass
,
runPass
),
phaseBuilder2
(
"bar"
,
runConditionPass
,
runFails
),
phaseBuilder2
(
"baz"
,
runConditionFails
,
runPass
),
},
}
var
usecases
=
[]
struct
{
name
string
options
RunnerOptions
expectedError
bool
}{
{
name
:
"no errors"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"foo"
}},
},
{
name
:
"run fails"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"bar"
}},
expectedError
:
true
,
},
{
name
:
"run condition fails"
,
options
:
RunnerOptions
{
FilterPhases
:
[]
string
{
"baz"
}},
expectedError
:
true
,
},
}
for
_
,
u
:=
range
usecases
{
t
.
Run
(
u
.
name
,
func
(
t
*
testing
.
T
)
{
w
.
Options
=
u
.
options
err
:=
w
.
Run
()
if
(
err
!=
nil
)
!=
u
.
expectedError
{
t
.
Errorf
(
"Unexpected error: %v"
,
err
)
}
})
}
}
func
phaseBuilder3
(
name
string
,
hidden
bool
,
phases
...
Phase
)
Phase
{
return
Phase
{
Name
:
name
,
Short
:
fmt
.
Sprintf
(
"long description for %s ..."
,
name
),
Phases
:
phases
,
Hidden
:
hidden
,
}
}
func
TestHelp
(
t
*
testing
.
T
)
{
var
w
=
Runner
{
Phases
:
[]
Phase
{
phaseBuilder3
(
"foo"
,
false
,
phaseBuilder3
(
"bar"
,
false
),
phaseBuilder3
(
"baz"
,
true
),
),
phaseBuilder3
(
"qux"
,
false
),
},
}
expected
:=
"The
\"
myCommand
\"
command executes the following internal workflow:
\n
"
+
"```
\n
"
+
"foo long description for foo ...
\n
"
+
" /bar long description for bar ...
\n
"
+
"qux long description for qux ...
\n
"
+
"```"
actual
:=
w
.
Help
(
"myCommand"
)
if
!
reflect
.
DeepEqual
(
actual
,
expected
)
{
t
.
Errorf
(
"
\n
actual:
\n\t
%v
\n
expected:
\n\t
%v
\n
"
,
actual
,
expected
)
}
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment