Merge pull request #6202 from rainzm/feat/ansible_playbook

Feat/ansible playbook
This commit is contained in:
Zexi Li
2020-05-09 18:54:10 +08:00
committed by GitHub
8 changed files with 229 additions and 11 deletions
+1 -1
View File
@@ -7,7 +7,7 @@ ENV TZ Asia/Shanghai
RUN mkdir -p /opt/yunion/bin
RUN apk update && \
apk add --no-cache tzdata ansible ca-certificates && \
apk add --no-cache tzdata git ansible ca-certificates && \
rm -rf /var/cache/apk/*
RUN cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
@@ -49,4 +49,34 @@ func init() {
printList(apbs, modules.AnsiblePlaybooksV2.GetColumns(s))
return nil
})
R(&AnsiblePlaybookV2IdOptions{}, "ansibleplaybookv2-run", "Run ansible playbook",
func(s *mcclient.ClientSession, opts *AnsiblePlaybookV2IdOptions) error {
apb, err := modules.AnsiblePlaybooksV2.PerformAction(s, opts.ID, "run", nil)
if err != nil {
return err
}
printObject(apb)
return nil
},
)
R(&AnsiblePlaybookV2IdOptions{}, "ansibleplaybookv2-stop", "Stop ansible playbook",
func(s *mcclient.ClientSession, opts *AnsiblePlaybookV2IdOptions) error {
apb, err := modules.AnsiblePlaybooksV2.PerformAction(s, opts.ID, "stop", nil)
if err != nil {
return err
}
printObject(apb)
return nil
},
)
R(&AnsiblePlaybookV2IdOptions{}, "ansibleplaybookv2-delete", "Delete ansible playbook",
func(s *mcclient.ClientSession, opts *AnsiblePlaybookV2IdOptions) error {
apb, err := modules.AnsiblePlaybooksV2.Delete(s, opts.ID, nil)
if err != nil {
return err
}
printObject(apb)
return nil
},
)
}
@@ -39,12 +39,13 @@ import (
type SAnsiblePlaybookV2 struct {
db.SVirtualResourceBase
Playbook string `length:"text" nullable:"false" create:"required" get:"user"`
Inventory string `length:"text" nullable:"false" create:"required" get:"user"`
Files string `length:"text" nullable:"false" create:"optional" get:"user"`
Output string `length:"medium" get:"user"`
StartTime time.Time `list:"user"`
EndTime time.Time `list:"user"`
Playbook string `length:"text" nullable:"false" create:"required" get:"user"`
Inventory string `length:"text" nullable:"false" create:"required" get:"user"`
Requirements string `length:"test" nullable:"false" create:"required" get:"user"`
Files string `length:"text" nullable:"false" create:"optional" get:"user"`
Output string `length:"medium" get:"user"`
StartTime time.Time `list:"user"`
EndTime time.Time `list:"user"`
CreatorMark string `length:"32" nullable:"false" create:"optional" get:"user"`
}
@@ -196,6 +197,7 @@ func (apb *SAnsiblePlaybookV2) runPlaybook(ctx context.Context, userCred mcclien
Inventory(apb.Inventory).
Playbook(apb.Playbook).
PrivateKey(privateKey).
Requirements(apb.Requirements).
Files(files).
OutputWriter(&ansiblePlaybookOutputWriter{apb})
man.sessions.Add(apb.Id, sess)
+23
View File
@@ -104,6 +104,29 @@ func (t *ShellTask) MarshalYAML() (interface{}, error) {
return r, nil
}
type IncludeRole struct {
Name string
Tags []string
Vars map[string]interface{}
When string
}
func (r *IncludeRole) MarshalYAML() (interface{}, error) {
out := map[string]interface{}{
"include_role": map[string]interface{}{"name": r.Name},
}
if len(r.Tags) > 0 {
out["tags"] = r.Tags
}
if len(r.Vars) > 0 {
out["vars"] = r.Vars
}
if len(r.When) > 0 {
out["when"] = r.When
}
return out, nil
}
type Block struct {
Name string
WithPlugin string
+8
View File
@@ -59,6 +59,14 @@ func TestPlaybookString(t *testing.T) {
"group": "root",
},
},
&IncludeRole{
Name: "foo_app_instance",
Vars: map[string]interface{}{
"dir": "/opt/a",
},
Tags: []string{"bar", "baz"},
When: "ansible_facts['os_family'] == 'RedHat'",
},
)
play.Hosts = "all"
configureBlock := NewBlock(
+70
View File
@@ -0,0 +1,70 @@
// Copyright 2019 Yunion
//
// 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 ansiblev2
import "gopkg.in/yaml.v2"
type RoleSource struct {
Name string
Src string
Version string
}
func (rs *RoleSource) MarshalYAML() (interface{}, error) {
r := map[string]string{
"src": rs.Src,
}
if len(rs.Name) > 0 {
r["name"] = rs.Name
}
if len(rs.Version) > 0 {
r["version"] = rs.Version
}
return r, nil
}
type Requirements struct {
RoleSources []RoleSource
}
func NewRequirements(rss ...RoleSource) *Requirements {
return &Requirements{
RoleSources: rss,
}
}
func (rm *Requirements) AddRoleSource(rss ...RoleSource) {
rm.RoleSources = append(rm.RoleSources, rss...)
}
func (rm *Requirements) MarshalYAML() (interface{}, error) {
var err error
r := make([]interface{}, len(rm.RoleSources))
for i := range rm.RoleSources {
r[i], err = rm.RoleSources[i].MarshalYAML()
if err != nil {
return nil, err
}
}
return r, nil
}
func (rm *Requirements) String() string {
r, err := yaml.Marshal(rm)
if err != nil {
panic(err)
}
return string(r)
}
+45
View File
@@ -0,0 +1,45 @@
// Copyright 2019 Yunion
//
// 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 ansiblev2
import "testing"
func TestRequirementsString(t *testing.T) {
rss := []RoleSource{
{
Src: "zaiste.nginx",
},
{
Src: "geerlingguy.gitlab",
Version: "1.1.0",
},
{
Name: "essentials",
Src: "https://github.com/zaiste/ansible-essentials",
},
{
Name: "java",
Src: "https://github.com/geerlingguy/ansible-role-java",
Version: "origin/master",
},
{
Name: "jenkins",
Src: "https://github.com/geerlingguy/ansible-role-jenkins",
Version: "4.2.1",
},
}
rm := NewRequirements(rss...)
t.Logf("\n%s", rm.String())
}
+44 -4
View File
@@ -29,10 +29,11 @@ import (
)
type Session struct {
privateKey string
playbook string
inventory string
files map[string][]byte
privateKey string
playbook string
inventory string
requirements string
files map[string][]byte
outputWriter io.Writer
stateMux *sync.Mutex
@@ -63,6 +64,11 @@ func (sess *Session) Inventory(s string) *Session {
return sess
}
func (sess *Session) Requirements(s string) *Session {
sess.requirements = s
return sess
}
func (sess *Session) AddFile(path string, data []byte) *Session {
sess.files[path] = data
return sess
@@ -143,6 +149,17 @@ func (sess *Session) Run(ctx context.Context) (err error) {
}
}
// write out requirements
var requirements string
if len(sess.requirements) > 0 {
requirements = filepath.Join(tmpdir, "requirements.yml")
err = ioutil.WriteFile(requirements, []byte(sess.requirements), os.FileMode(0600))
if err != nil {
err = errors.WithMessagef(err, "writing requirements %s", requirements)
return
}
}
// write out files
for name, content := range sess.files {
path := filepath.Join(tmpdir, name)
@@ -167,6 +184,29 @@ func (sess *Session) Run(ctx context.Context) (err error) {
}
}()
// install required roles
if len(requirements) > 0 {
args := []string{
"install", "-r", requirements,
}
cmd := exec.CommandContext(ctx, "ansible-galaxy", args...)
stdout, _ := cmd.StdoutPipe()
stderr, _ := cmd.StderrPipe()
if err1 := cmd.Start(); err1 != nil {
errs = append(errs, errors.WithMessage(err1, "start ansible-galaxy install roles"))
return
}
// Mix stdout, stderr
if sess.outputWriter != nil {
go io.Copy(sess.outputWriter, stdout)
go io.Copy(sess.outputWriter, stderr)
}
if err1 := cmd.Wait(); err1 != nil {
errs = append(errs, errors.WithMessage(err1, "wait ansible-galaxy install roles"))
}
}
// run playbook
{
args := []string{
"--inventory", inventory,