Skip to content
This repository has been archived by the owner on Aug 9, 2024. It is now read-only.

Commit

Permalink
Auto generate sail playbook file
Browse files Browse the repository at this point in the history
  • Loading branch information
bougou committed Oct 9, 2021
1 parent 083635d commit e082137
Show file tree
Hide file tree
Showing 10 changed files with 85 additions and 27 deletions.
16 changes: 8 additions & 8 deletions docs/en/component.md
Original file line number Diff line number Diff line change
Expand Up @@ -171,7 +171,7 @@ Sail currently supports using Ansible Role to deploy normal components and using

In your operation code of the component, you can make both the ansible role and the helm chart be prepared.
Thus, the operator can choose which method is used to deploy the component for a specific environment.
But still you can ONLY provide ansible role OR helm chart for the component as your wish.
But still you can provide ONLY ansible role OR helm chart for the component as your wish.

When running sail commands like `sail upgrade -c <componentName>`, `sail`
will automatically runs `ansible-playbook` or `helm` for the component according to the `form` field.
Expand All @@ -192,11 +192,11 @@ When deploying the product, there are different choices for "mysql" component fo
- You may want to deploy a mysql cluster using some plain servers.
- You may want to use the mysql instance served and maintained by other specical DBA teams from your company.

Anyway, when you want to use external services for the component, you have to set `external` to `true` in the `vars.yaml` of the environment `targets/<target_name>/<zone_name>/vars.yaml`.
Anyway, when you want to use external services for the component, you have to set `external` to `true` for the component in `targets/<target_name>/<zone_name>/vars.yaml`.

When you want to deploy the component yourself, you have to set `enabled` to `true`
When you want to deploy the component yourself, you have to set `enabled` to `true`.

For some cases, the component may even not used, you have to set both `external` and `enabled` to `false`
For some cases, the component may even not used, you have to set both `external` and `enabled` to `false`.

In short, there are 3 combination usage cases for `enabled` and `external`:

Expand All @@ -220,8 +220,8 @@ mysql:

### Component Services

- one component can provides 0, 1, or multiple services to other components
- one service for one port
- one component can provide 0, 1, or multiple services for other components
- one service maps to one port

`services` field is a dict with port name (service name) as keys.

Expand Down Expand Up @@ -336,9 +336,9 @@ The keys of Computed is one-to-one mapping to Services.
Sail will apply a computation prodedure for each service under `services`,
and set the computed object to `computed`.

Never directly to edit or change the values under `computed`, it will be computed and overrite every time sail runs.
Never directly to edit or change the values of the fields under `computed`, it will be computed and overwrite every time sail runs.

The computation procedure is different according to value of `external`.
The computation procedure is different according to the value of `external`.

#### For `external: true`

Expand Down
2 changes: 1 addition & 1 deletion pkg/commands/apply/apply.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func NewCmdApply(sailOption *models.SailOption) *cobra.Command {

cmd.Flags().StringVarP(&o.TargetName, "target", "t", o.TargetName, "target name")
cmd.Flags().StringVarP(&o.ZoneName, "zone", "z", o.ZoneName, "zone name")
cmd.Flags().StringVarP(&o.Playbook, "playbook", "p", "run", "optional playbook name")
cmd.Flags().StringVarP(&o.Playbook, "playbook", "p", "", "optional playbook name")
cmd.Flags().StringVarP(&o.StartAtPlay, "start-at-play", "", "", "start the playbook from the play with this tag name")
cmd.Flags().StringArrayVarP(&o.Components, "component", "c", o.Components, "the component")
cmd.Flags().BoolVarP(&o.Ansible, "ansible", "", o.Ansible, "choose components deployed as server")
Expand Down
20 changes: 17 additions & 3 deletions pkg/models/product/component.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ type Component struct {
Name string `yaml:"-"`
Version string `yaml:"version"`

// Group can be used to group by components.
Group string `yaml:"group"`

// If RoleName is empty, it will be set to component Name.
RoleName string `yaml:"roleName"`

Expand Down Expand Up @@ -155,6 +158,7 @@ func (c *Component) Compute(cm *cmdb.CMDB) error {
return nil
}

// GetRoles return the ansible roles which will be applied to this component.
func (c *Component) GetRoles() []string {
roles := []string{}
if len(c.Roles) == 0 {
Expand All @@ -171,15 +175,25 @@ func (c *Component) GetRoles() []string {

// GenAnsiblePlay generatea a ansible play for this component.
func (c *Component) GenAnsiblePlay() (*ansible.Play, error) {
// Note, we use the component name as the default ansible group name.
hostsPattern := fmt.Sprintf("{{ _ansiblepattern_%s | default('%s') }}", strings.ReplaceAll(c.Name, "-", "_"), c.Name)
play := ansible.NewPlay(c.Name, hostsPattern)
play.WithTags("play-" + c.Name)
if c.Group != "" {
play.WithTags(c.Group)
}

for _, r := range c.GetRoles() {
for _, roleName := range c.GetRoles() {
role := ansible.Role{
Role: r,
Tags: []string{r},
Role: roleName,
Tags: []string{roleName},
}
if roleName == c.RoleName && roleName != c.Name {
role.Tags = append(role.Tags, c.Name)
} else {
role.Tags = append(role.Tags, roleName+"-"+c.Name)
}

play.Roles = append(play.Roles, role)
}

Expand Down
19 changes: 10 additions & 9 deletions pkg/models/product/product.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import (
)

const DefaultPlaybook string = "sail"
const DefaultPlaybookFile string = "sail.yaml"
const DefaultPlaybookFile string = ".sail.yaml"

type Product struct {
Name string `json:"Name,omitempty" yaml:"Name,omitempty"`
Expand Down Expand Up @@ -230,14 +230,15 @@ func (p *Product) ComponentListWithFilterOptionsAnd(filterOptions ...FilterOptio
func (p *Product) GenSail() (ansible.Playbook, error) {
out := ansible.Playbook(make([]ansible.Play, 0))

gatherFactsPlay := ansible.NewPlay("gather facts", "all")
gatherFactsPlay.GatherFacts = true
gatherFactsPlay.AnyErrorsFatal = false
gatherFactsPlay.Become = false
role := ansible.Role{Role: "always"}
gatherFactsPlay.WithRoles(role)
gatherFactsPlay.WithTags("gather-facts")
out = append(out, *gatherFactsPlay)
// Todo, add pre and post plays
// gatherFactsPlay := ansible.NewPlay("gather facts", "all")
// gatherFactsPlay.GatherFacts = true
// gatherFactsPlay.AnyErrorsFatal = false
// gatherFactsPlay.Become = false
// role := ansible.Role{Role: "always"}
// gatherFactsPlay.WithRoles(role)
// gatherFactsPlay.WithTags("gather-facts")
// out = append(out, *gatherFactsPlay)

for _, compName := range p.order {
c, exists := p.DefaultComponents[compName]
Expand Down
6 changes: 3 additions & 3 deletions pkg/models/product/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -108,8 +108,8 @@ func (s *Service) Compute(external bool, cm *cmdb.CMDB) (*ServiceComputed, error
return s.computeNonExternal(cm)
}

// computeNonExternal returns ServiceComputed.
// It should be used for component with external set to false.
// computeNonExternal returns ServiceComputed for service.
// It should be used for component with `external` set to false.
func (s *Service) computeNonExternal(cm *cmdb.CMDB) (*ServiceComputed, error) {
svcComputed := NewServiceComputed()

Expand Down Expand Up @@ -234,7 +234,7 @@ SETHOST:
}

// computeExternal returns ServiceComputed.
// It should be used for component with external set to true.
// It should be used for component with `external` set to true.
func (s *Service) computeExternal() (*ServiceComputed, error) {
svcComputed := NewServiceComputed()

Expand Down
5 changes: 4 additions & 1 deletion pkg/models/target/ansible.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,12 @@ gather_subset=!hardware
command_warnings = False

# ansible-playbook will automatically insert `${playbook-yaml-dir}/roles` at the begining and `${playbook-yaml-dir}` at the end
# {playbook-yaml-dir}/roles
# {playbook-yaml-dir}/roles, So we need to put all playbook file under <sailProductsDir>/<productName>/ directory.
# {playbook-yaml-dir}
roles_path = shared_roles
# relative to the directory holding ansible.cfg
# the above configuration will make ansible to search roles under the following directories and ober the order.
# <sailProductsDir>/<productName>/roles:<sailProductsDir>/shared_roles:<sailProductsDir>/<productName>

#roles_path = shared_roles:~/.ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
[privilege_escalation]
Expand Down
2 changes: 2 additions & 0 deletions pkg/models/target/helm.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,8 @@ func (zone *Zone) PrepareHelm() error {
return zone.PrepareHelmCharts()
case "product":
return zone.PrepareHelmChart()
case "":
return nil
default:
return fmt.Errorf("not supported helm mode: (%s)", zone.SailHelmMode)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/models/target/runningzone.go
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,9 @@ func (rz *RunningZone) RunHelm(args []string) error {

return rz.helmCmd(helmRelease, helmChartDir, k8s, valuesFiles, args...)

case "":
return nil

default:
return fmt.Errorf("not supported helm mode: (%s)", rz.zone.SailHelmMode)
}
Expand Down
3 changes: 3 additions & 0 deletions pkg/models/target/target.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,9 @@ func (t *Target) LoadZone(zoneName string) error {
for k, v := range zone.Product.Vars {
zoneV[k] = v
}
for k, v := range zone.Product.Components {
zoneV[k] = v
}
zoneV["platforms"] = zone.CMDB.Platforms
zoneV["inventory"] = zone.CMDB.Inventory

Expand Down
36 changes: 34 additions & 2 deletions pkg/models/target/zone.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const (

SailHelmModeComponent = "component"
SailHelmModeProduct = "product"

SailPlaybookFile = ".sail.yaml"
)

type ZoneMeta struct {
Expand Down Expand Up @@ -213,6 +215,9 @@ func (zone *Zone) Dump() error {
}

errs := []string{}
if err := zone.RenderSailPlaybook(); err != nil {
errs = append(errs, err.Error())
}
if err := zone.RenderVars(); err != nil {
errs = append(errs, err.Error())
}
Expand All @@ -232,6 +237,27 @@ func (zone *Zone) Dump() error {
return nil
}

// RenderSailPlaybook renders the default temporary ansible playbook file for the product of the zone.
func (zone *Zone) RenderSailPlaybook() error {
product := zone.Product
playbook, err := product.GenSail()
if err != nil {
msg := fmt.Sprintf("gen sail playbook failed, err: %s", err)
return errors.New(msg)
}

b, err := common.Encode("yaml", playbook)
if err != nil {
fmt.Println("encode vars failed", err)
}

if err := os.WriteFile(zone.Product.SailPlaybookFile(), b, 0644); err != nil {
fmt.Println("write product sail playbook file failed", err)
}

return nil
}

func (zone *Zone) RenderVars() error {
m := make(map[string]interface{})

Expand Down Expand Up @@ -353,7 +379,8 @@ func (zone *Zone) BuildInventory(hostsMap map[string][]string) error {

func (zone *Zone) PlaybookFile(playbookName string) string {
if playbookName == "" {
playbookName = product.DefaultPlaybook
// auto generated when sail runs
return path.Join(zone.Product.Dir, product.DefaultPlaybookFile)
}

if strings.HasSuffix(playbookName, ".yaml") {
Expand Down Expand Up @@ -392,12 +419,17 @@ func (zone *Zone) LoadHosts() error {
}

func (zone *Zone) LoadPlatforms() error {
i := map[string]cmdb.Platform{}

b, err := os.ReadFile(zone.PlatformsFile)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
zone.CMDB.Platforms = i
return nil
}
return fmt.Errorf("read file (%s) failed, err: %s", zone.PlatformsFile, err)
}

i := map[string]cmdb.Platform{}
if err := yaml.Unmarshal(b, &i); err != nil {
return fmt.Errorf("unmarshal platforms failed, err: %s", err)
}
Expand Down

0 comments on commit e082137

Please sign in to comment.