mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #6202 from rainzm/feat/ansible_playbook
Feat/ansible playbook
This commit is contained in:
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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())
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user