Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

Add additional types and providers #24

Open
wants to merge 19 commits into
base: master
Choose a base branch
from

Conversation

jonasdemoor
Copy link

This PR adds the following types and providers for managing local MinIO resources:

  • minio_user
  • minio_group
  • minio_bucket
  • minio_policy

These work for the most part; there are still some caveats:

  • It's not possible to update the secret key of a user, since the CLI doesn't report the secret key when fetching users.
  • Assigning policies only works reliably when doing so via either minio_user or minio_group. Attempting to mix those two providers for policy assignment might result in assigned policies being overwritten.
  • The minio_group provider processes updates by recreating the whole group to keeps things simple. A proper update would require removing and/or adding members via the CLI in a certain order.
  • A client alias with the name puppet is hardcoded into the provider code, since the MinIO CLI needs an alias to retrieve and create MinIO resources. This alias would need to be created before running the providers.

I'm running the providers on a Debian 11 VM against the following MinIO versions:

$ sudo mcli admin info puppet
●  127.0.0.1:9000
   Uptime: 1 week 
   Version: 2021-11-03T03:36:36Z
   Network: 1/1 OK 

3.1 MiB Used, 7 Buckets, 1 Object

$ sudo mcli --version
mcli version RELEASE.2021-10-07T04-19-58Z

$ cat /etc/os-release 
PRETTY_NAME="Debian GNU/Linux 11 (bullseye)"
NAME="Debian GNU/Linux"
VERSION_ID="11"
VERSION="11 (bullseye)"
VERSION_CODENAME=bullseye
ID=debian
HOME_URL="https://www.debian.org/"
SUPPORT_URL="https://www.debian.org/support"
BUG_REPORT_URL="https://bugs.debian.org/"

I'm still working on my Ruby skills, feedback is always welcome :)

@ZloeSabo
Copy link
Collaborator

ZloeSabo commented Dec 7, 2021

Thank you for your contribution @jonasdemoor . I will check the changes once I have a chance, that's a pretty big PR to check!

@ZloeSabo ZloeSabo self-requested a review December 7, 2021 16:47
require 'puppet/resource_api/simple_provider'
require 'puppet_x/minio/client'

DEFAUlT_TARGET_ALIAS ||= 'puppet'.freeze
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest removing the hardcoded alias and adding it as a parameter here and in other types you're adding. I'm sure it would work as it is for certain use-cases, but it's always better to be flexible and allow module consumers to decide what alias they want to use.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is bit of a chicken-egg problem unfortunately, as we need an alias to query MinIO for state.

I was thinking about managing a small JSON file (e.g. /usr/local/etc/minio_state.json) that would hold the currently selected alias by the user. We can manage this from the manifests or we can write a small provider for that, for example.

I was also thinking about using this file for saving user passwords to from the minio_user provider, then we could update a user's password without having to (manually) delete said user.

Does this sound okay for you? Just thinking out loud here :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I solved this by setting /root/.minio_default_alias in the manifests and retrieving the contents of that file in the providers (via the alias method in puppet_x/minio/client

desc: 'The name of the resource you want to manage.',
behaviour: :namevar,
},
},
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add autorequire here and in other new types, as I did in aliases:

autorequire: {
    file: '/root/.minioclient',
}

Otherwise, puppet sometimes tries to create resources before minio client is set and that fails for obvious reasons:

  Error: minio_bucket[testbucket]: Creating: Failed after 0.000269 seconds: Symlink to minio client does not exist at /root/.minioclient. Make sure you installed the client before managing minio resources.
Error: /Stage[main]/Main/Minio_bucket[testbucket]: Could not evaluate: Execution encountered an error

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot those indeed, I will add them to the types.

desc: 'Whether this resource should be present or absent on the target system.',
default: 'present',
},
name: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If that's possible, please also add parameters for region and locking.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some additional parameters for region and locking

operations << "admin group add #{DEFAUlT_TARGET_ALIAS} #{name} #{should[:members].join(' ')}"

operations << "admin group disable #{DEFAUlT_TARGET_ALIAS} #{name}" unless should[:enabled]
operations << "admin policy set #{DEFAUlT_TARGET_ALIAS} #{should[:policies].join(',')} group=#{name}" unless should[:policies].nil?
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest moving the policy assignment to a dedicated type that would only assign an existing policy to a user or to a group.

In my experience, as soon as a type started doing more than one thing, module consumers start having problems using the module. So it's better to give consumers smaller simple building blocks and let them decide how they want to combine those. Of course given the client supports a dedicated command for assignment (in the case of minio, policies have the dedicated command, but groups do not).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes more sense indeed, and would simplify the user and group providers.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Policy assignment is now done with a dedicated minio_policy_assignment provider. Since there's no real API endpoint for retrieving policy assignments, the get method returns resources with <subject_type>_<subject> as composite namevar. So it's only possible to update those resources.

behaviour: :namevar,
},
secret_key: {
type: 'Variant[Sensitive[String], String]',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you please add length restrictions to the string types? The secret key should be between 8 and 40 characters in length.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some length restrictions like you described.

},
access_key: {
type: 'String',
desc: 'The API access key',
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add a mention that it's also a username.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I modified the description a bit


f = Tempfile.new(["#{name}-policy", '.json'])
begin
json_policy = Hash[:Version => DEFAULT_POLICY_VERSION, :Statement => should[:statement]].to_json
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. You could just do {:Version => ...} with curly brackets without Hash
  2. you don't really need f.rewind. For further closing and deleting the file, it's not important where the internal cursor for the file is.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. I adjusted the Hash syntax to the one you described
  2. When I didn't rewind the file, mcli couldn't read the JSON file with the policy object, because the CLI read an empty string. After some searching, I found that I had to rewind the file for it to work.

type: 'Optional[Array[String]]',
desc: 'List of MinIO PBAC policies to set for this user.',
},
member_of: {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Do you really need it? I'd just remove it unless sure why would we need it.
  2. Could you please also add enabled parameter here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. This isn't really needed indeed, it's mostly cosmetic, so I removed it
  2. I added an additional enabled parameter

version: {
type: 'String',
desc: 'Specifies the language syntax rules that are to be used to process a policy.',
behaviour: :read_only,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why don't you just add a default value here instead of making it read only? In such a case, consumers could continue using the module when the version ever changes without making changes to the module code.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a default value for the version

@ZloeSabo
Copy link
Collaborator

@jonasdemoor thank you again for your PR. I finally had time to look at it.

I understand that some of my requests gonna require a lot of time to implement, so I suggest you fix whatever you have time for and let me know, so I take over and finish the remaining stuff myself.

@jonasdemoor
Copy link
Author

Hello @ZloeSabo ,

My apologies for taking so long to respond. Thank you very much for your detailed feedback, I'm reworking this PR based on your feedback.

@jonasdemoor
Copy link
Author

Hi @ZloeSabo,

I reworked the providers and types based on your feedback. Feel free to let me know if there's anything else that could be improved or handled differently :)

@jonasdemoor
Copy link
Author

I'm still working on the unit tests, so CI may still fail

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants