feat/ansible_pb: Add support for requirements

You can declare the source info of the referenced role in requirements.
This commit is contained in:
Rain
2020-05-08 11:08:32 +08:00
parent 068b9ec200
commit 331ba9bb37
4 changed files with 167 additions and 10 deletions
@@ -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)
+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,