Skip to content

Commit

Permalink
fixes
Browse files Browse the repository at this point in the history
Signed-off-by: Fahed DORGAA <fahed.dorgaa@gmail.com>
  • Loading branch information
fahedouch committed May 10, 2022
1 parent ac817ac commit c2ffc92
Show file tree
Hide file tree
Showing 7 changed files with 312 additions and 198 deletions.
5 changes: 3 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ require (
sigs.k8s.io/controller-tools v0.8.0
)

require k8s.io/api v0.23.5

require (
cloud.google.com/go v0.81.0 // indirect
cloud.google.com/go/storage v1.14.0 // indirect
Expand Down Expand Up @@ -88,7 +90,6 @@ require (
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
k8s.io/api v0.23.5 // indirect
k8s.io/apiextensions-apiserver v0.23.5 // indirect
k8s.io/component-base v0.23.5 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
Expand All @@ -100,4 +101,4 @@ require (
)

// Temporary fork crossplane-runtime to support PolicyRun meta
replace github.com/crossplane/crossplane-runtime => github.com/fahedouch/crossplane-runtime v0.15.1-0.20220509161019-b9dee8676ccc
replace github.com/crossplane/crossplane-runtime => github.com/fahedouch/crossplane-runtime v0.15.2-0.20220510100729-93336f6af258
291 changes: 224 additions & 67 deletions go.sum

Large diffs are not rendered by default.

52 changes: 27 additions & 25 deletions internal/ansible/ansible.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ import (
"strings"

"github.com/crossplane/crossplane-runtime/pkg/meta"
"github.com/crossplane/crossplane-runtime/pkg/resource"

"github.com/crossplane/provider-ansible/apis/v1alpha1"
"github.com/crossplane/provider-ansible/pkg/galaxyutil"
"github.com/crossplane/provider-ansible/pkg/runnerutil"
Expand All @@ -50,29 +50,29 @@ type Parameters struct {
RolesPath string
}

// policy represents the run policies of Ansible.
type policy struct {
name string
// RunPolicy represents the run policies of Ansible.
type RunPolicy struct {
Name string
}

// newPolicy creates a runPolicy with the specified name.
// newRunPolicy creates a run Policy with the specified Name.
// supports the following run policies:
// - ObserveAndDelete
// - CheckWhenObserve
// For more details about RunPolicy : https://github.com/multicloudlab/crossplane-provider-ansible/blob/main/docs/design.md#ansible-run-policy
func newPolicy(policy string) *policy {
switch policy {
func newRunPolicy(rPolicy string) (*RunPolicy, error) {
switch rPolicy {
case "", "ObserveAndDelete":
if policy == "" {
policy = "ObserveAndDelete"
if rPolicy == "" {
rPolicy = "ObserveAndDelete"
}
case "CheckWhenObserve":
default:
return nil, fmt.Errorf("run policy %q not supported", policy)
}
return &Policy{
name: policy,
return nil, fmt.Errorf("run policy %q not supported", rPolicy)
}
return &RunPolicy{
Name: rPolicy,
}, nil
}

// A runnerOption configures a Runner.
Expand Down Expand Up @@ -114,9 +114,9 @@ func withAnsibleHosts(hosts string) runnerOption {
}

// withAnsibleRunPolicy set the runner Policy to execute against.
func withAnsibleRunPolicy(policy string) runnerOption {
func withAnsibleRunPolicy(p *RunPolicy) runnerOption {
return func(r *Runner) {
r.ansibleRunPolicy = policy
r.AnsibleRunPolicy = p
}
}

Expand Down Expand Up @@ -237,15 +237,18 @@ func (p Parameters) Init(ctx context.Context, cr *v1alpha1.AnsibleRun, pc *v1alp
}
}

policy := meta.GetPolicyRun(cr)
rPolicy, err := newRunPolicy(meta.GetPolicyRun(cr))
if err != nil {
return nil, err
}
return new(withPath(path),
withCmdFunc(cmdFunc),
// TODO add verbosity filed to the API, now it is ignored by (0) value
withAnsibleVerbosity(0),
withAnsibleGathering(behaviorVars["ANSIBLE_GATHERING"]),
// TODO hosts should be handled via configuration vars e.g: vars["hosts"]
withAnsibleHosts(""),
withAnsibleRunPolicy(policy),
withAnsibleRunPolicy(rPolicy),
), nil
}

Expand All @@ -257,7 +260,7 @@ type Runner struct {
ansibleVerbosity int
ansibleGathering string
ansibleHosts string
ansibleRunPolicy policy
AnsibleRunPolicy *RunPolicy
}

// new returns a runner that will be used as ansible-runner client
Expand All @@ -273,7 +276,7 @@ func new(o ...runnerOption) *Runner {
}

// addRolePlaybookPaths will add the full path based on absolute path of cloning dir
// Func from operator SDK
// addRolePlaybookPaths mimics https://github.com/operator-framework/operator-sdk/blob/master/internal/ansible/watches/watches.go#L179-L206
func addRolePlaybookPaths(p Parameters, behaviorVars map[string]string, cr *v1alpha1.AnsibleRun) {
if len(cr.Spec.ForProvider.Playbook) > 0 {
cr.Spec.ForProvider.Playbook = runnerutil.GetFullPath(p.WorkingDirPath, cr.Spec.ForProvider.Playbook)
Expand All @@ -300,7 +303,7 @@ func addRolePlaybookPaths(p Parameters, behaviorVars map[string]string, cr *v1al
}

// getPossibleRolePaths returns list of possible absolute paths derived from a user provided value.
func getPossibleRolePaths(WorkingDirPath, path, ansibleRolesPath, ansibleCollectionsPath string) []string {
func getPossibleRolePaths(workingDirPath, path, ansibleRolesPath, ansibleCollectionsPath string) []string {
possibleRolePaths := []string{}
if filepath.IsAbs(path) || len(path) == 0 {
return append(possibleRolePaths, path)
Expand Down Expand Up @@ -330,11 +333,10 @@ func getPossibleRolePaths(WorkingDirPath, path, ansibleRolesPath, ansibleCollect
}
}
// Roles can also live in the working directory.
return append(possibleRolePaths, runnerutil.GetFullPath(WorkingDirPath, filepath.Join("roles", path)))
return append(possibleRolePaths, runnerutil.GetFullPath(workingDirPath, filepath.Join("roles", path)))
}

// From sdk operator
// addFile adds a file to the given relative path within the working directory.
// AddFile from https://github.com/operator-framework/operator-sdk/blob/master/internal/ansible/runner/internal/inputdir/inputdir.go#L55-L63
func (p Parameters) AddFile(path string, content []byte) error {
fullPath := filepath.Join(p.WorkingDirPath, path)
if err := os.WriteFile(fullPath, content, 0644); err != nil {
Expand Down Expand Up @@ -377,7 +379,7 @@ func (p Parameters) AddFile(path string, content []byte) error {

// runWithCheckMode plays `ansible-runner` with check mode
// then parse JSON stream results
func (r *runner) runWithCheckMode(ctx context.Context, mg resource.Managed) (bool, bool, error) {
/*func (r *Runner) runWithCheckMode(ctx context.Context, mg resource.Managed) (bool, bool, error) {
// Enable the check flag
// Check don't make any changes; instead, try to predict some of the changes that may occur
pbCmd.Playbook.Options.Check = true
Expand All @@ -387,7 +389,7 @@ func (r *runner) runWithCheckMode(ctx context.Context, mg resource.Managed) (boo
}
changes, re := diff(result)
return changes, re, nil
}
}*/

// CreateOrUpdate run playbook during update or create
/*func (pbCmd *PbCmd) CreateOrUpdate(ctx context.Context, mg resource.Managed) error {
Expand Down
2 changes: 1 addition & 1 deletion internal/ansible/ansible_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ func TestInit(t *testing.T) {
firstCr.Spec.ForProvider.Role = filepath.Join(filepath.Join(ansibleCtx, "roles"), tc.role)

ps := Parameters{
WorkingDir: ansibleCtx,
WorkingDirPath: ansibleCtx,
}

secondCr := v1alpha1.AnsibleRun{ObjectMeta: objectMeta}
Expand Down
92 changes: 42 additions & 50 deletions internal/controller/ansibleRun/ansibleRun.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import (
getter "github.com/hashicorp/go-getter"
"github.com/pkg/errors"
"github.com/spf13/afero"
v1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/equality"
kerrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/util/workqueue"
Expand All @@ -58,6 +60,7 @@ const (
errInit = "cannot initialize Ansible client"
gitCredentialsFilename = ".git-credentials"

errGetAnsibleRun = "cannot get AnsibleRun"
errGetLastApplied = "cannot get last applied"
errUnmarshalTemplate = "cannot unmarshal template"
)
Expand All @@ -68,6 +71,7 @@ const (

type params interface {
Init(ctx context.Context, cr *v1alpha1.AnsibleRun, pc *v1alpha1.ProviderConfig) (*ansible.Runner, error)
AddFile(path string, content []byte) error
GalaxyInstall() error
}

Expand Down Expand Up @@ -96,7 +100,7 @@ func Setup(mgr ctrl.Manager, l logging.Logger, rl workqueue.RateLimiter, ansible
fs: fs,
ansible: func(dir string) params {
return ansible.Parameters{
WorkingDir: dir,
WorkingDirPath: dir,
GalaxyBinary: galaxyBinary,
RunnerBinary: runnerBinary,
CollectionsPath: ansibleCollectionsPath,
Expand Down Expand Up @@ -218,20 +222,19 @@ func (c *connector) Connect(ctx context.Context, mg resource.Managed) (managed.E
// Committing the AnsibleRun's desired state (contentVars) to the filesystem at p.WorkingDirPath.
contentVars := map[string]interface{}{}
if len(cr.Spec.ForProvider.Vars) != 0 {
for k, v := range cr.Spec.ForProvider.Vars {
contentVars[k] = v
for _, v := range cr.Spec.ForProvider.Vars {
contentVars[v.Key] = v.Value
}
}
contentVarsBytes, err := json.Marshal(contentVars)
if err != nil {
return nil, err
}

if err := p.AddFile("env/envvars", contentVarsBytes); err != nil {
ps := c.ansible(dir)
if err := ps.AddFile("env/envvars", contentVarsBytes); err != nil {
return nil, err
}

ps := c.ansible(dir)
// install ansible requirements using ansible-galaxy
if err := ps.GalaxyInstall(); err != nil {
return nil, err
Expand All @@ -254,50 +257,39 @@ func (c *external) Observe(ctx context.Context, mg resource.Managed) (managed.Ex
if !ok {
return managed.ExternalObservation{}, errors.New(errNotAnsibleRun)
}
switch c.runner.ansibleRunPolicy {
case "ObserveAndDelete":
switch c.runner.AnsibleRunPolicy.Name {
case "ObserveAndDelete", "":
if c.runner.AnsibleRunPolicy.Name == "" {
meta.SetPolicyRun(mg, "ObserveAndDelete")
}
if meta.WasDeleted(cr) {
return managed.ExternalObservation{ResourceExists: true}, nil
}

desired, err := getDesired(cr)
if err != nil {
return err
}
observed := desired.DeepCopy()

if err = c.kube.Get(ctx, types.NamespacedName{
observed := cr.DeepCopy()
if err := c.kube.Get(ctx, types.NamespacedName{
Namespace: observed.GetNamespace(),
Name: observed.GetName(),
}, observed); err != nil {
if kerrors.IsNotFound(err) {
return managed.ExternalObservation{ResourceExists: false}, nil
}
return managed.ExternalObservation{}, errors.Wrap(err, errGetObject)
return managed.ExternalObservation{}, errors.Wrap(err, errGetAnsibleRun)
}
var last *unstructured.Unstructured
if last, err = getLastApplied(cr, observed); err != nil {
var last *v1alpha1.AnsibleRun
var err error
last, err = getLastApplied(observed)
if err != nil {
return managed.ExternalObservation{}, errors.Wrap(err, errGetLastApplied)
}

return c.handleLastApplied(cr, last, desired)
return c.handleLastApplied(last, cr)
case "CheckWhenObserve":
//TODO
case "":
meta.SetPolicyRun(mg, "ObserveAndDelete")
err := c.runner.ObserveAndDelete(ctx, cr)
if err != nil {
return managed.ExternalObservation{}, err
}
// TODO
default:
return managed.ExternalObservation{}, errors.New("Policy not supported")
}

/*return managed.ExternalObservation{
ResourceExists: re,
ResourceUpToDate: !changes,
ResourceLateInitialized: false,
}, nil*/
return managed.ExternalObservation{}, nil
}

func (c *external) Create(ctx context.Context, mg resource.Managed) (managed.ExternalCreation, error) {
Expand Down Expand Up @@ -339,25 +331,25 @@ func (c *external) Delete(ctx context.Context, mg resource.Managed) error {
return nil
}

func getLastApplied(cr *v1alpha1.AnsibleRun, observed *unstructured.Unstructured) (*unstructured.Unstructured, error) {
func getLastApplied(observed *v1alpha1.AnsibleRun) (*v1alpha1.AnsibleRun, error) {
lastApplied, ok := observed.GetAnnotations()[v1.LastAppliedConfigAnnotation]
if !ok {
return nil, nil
}

last := &unstructured.Unstructured{}
last := &v1alpha1.AnsibleRun{}
if err := json.Unmarshal([]byte(lastApplied), last); err != nil {
return nil, errors.Wrap(err, errUnmarshalTemplate)
}

if last.GetName() == "" {
last.SetName(cr.Name)
last.SetName(observed.GetName())
}

return last, nil
}

func (c *external) handleLastApplied(cr *v1alpha1.AnsibleRun, last, desired *unstructured.Unstructured) (managed.ExternalObservation, error) {
func (c *external) handleLastApplied(last, desired *v1alpha1.AnsibleRun) (managed.ExternalObservation, error) {
isUpToDate := false

if last != nil && equality.Semantic.DeepEqual(last, desired) {
Expand All @@ -366,41 +358,41 @@ func (c *external) handleLastApplied(cr *v1alpha1.AnsibleRun, last, desired *uns
}

if !isUpToDate {
extraVarsPath := filepath.join(c.runner.Path, "env/extravars")
extraVarsPath := filepath.Join(c.runner.Path, "env/extravars")
contentVars := map[string]interface{}{}
ansibleRunState, err := fmt.Fprintf("ansible_provider_meta.%s.state", cr.GetName())
if err != nil {
return err
}
ansibleRunState := fmt.Sprintf("ansible_provider_meta.%s.state", desired.GetName())
data, err := os.ReadFile(extraVarsPath)
if err != nil {
if !os.IsNotExist(err) {
return err
return managed.ExternalObservation{}, err
}
}
if len(data) != 0 {
if err := json.Unmarshal(data, contentVars); err != nil {
return err
if err := json.Unmarshal(data, &contentVars); err != nil {
return managed.ExternalObservation{}, err
}
}
contentVars[ansibleRunState] = "present"
contentVarsB, err = json.Marshal(contentVars)
contentVarsB, err := json.Marshal(contentVars)
if err != nil {
return managed.ExternalObservation{}, nil
}
if err := os.WriteFile(extraVarsPath, contentVarsB, 0644); err != nil {
return err
return managed.ExternalObservation{}, err
}
}

return managed.ExternalObservation{}, nil
}

func getDesired(cr *v1alpha1.AnsibleRun) (*unstructured.Unstructured, error) {
/*func getDesired(cr *v1alpha1.AnsibleRun) (*unstructured.Unstructured, error) {
desired := &unstructured.Unstructured{}
if err := json.Unmarshal(cr.Spec.ForProvider, desired); err != nil {
if _, err := json.Unmarshal([]byte(cr.Spec.ForProvider), desired); err != nil {
return nil, errors.Wrap(err, errUnmarshalTemplate)
}
if desired.GetName() == "" {
desired.SetName(obj.Name)
desired.SetName(cr.GetName())
}
return desired, nil
}
}*/
Loading

0 comments on commit c2ffc92

Please sign in to comment.